6354. Find the Array Concatenation Value

给你一个下标从 0 开始的整数数组 nums 。

现定义两个数字的 串联 是由这两个数值串联起来形成的新数字。

  • 例如,15 和 49 的串联是 1549 。

nums 的 串联值 最初等于 0 。执行下述操作直到 nums 变为空:

  • 如果 nums 中存在不止一个数字,分别选中 nums 中的第一个元素和最后一个元素,将二者串联得到的值加到 nums 的 串联值 上,然后从 nums 中删除第一个和最后一个元素。
  • 如果仅存在一个元素,则将该元素的值加到 nums 的串联值上,然后删除这个元素。

返回执行完所有操作后 nums 的串联值。

测试样例

输入:nums = [7,52,2,4]

输出:596

解释:

在执行任一步操作前,nums 为 [7,52,2,4] ,串联值为 0 。

  • 在第一步操作中:我们选中第一个元素 7 和最后一个元素 4 。二者的串联是 74 ,将其加到串联值上,所以串联值等于 74 。接着我们从 nums 中移除这两个元素,所以 nums 变为 [52,2] 。
  • 在第二步操作中:
    我们选中第一个元素 52 和最后一个元素 2 。
    二者的串联是 522 ,将其加到串联值上,所以串联值等于 596 。
    接着我们从 nums 中移除这两个元素,所以 nums 变为空。
    由于串联值等于 596 ,所以答案就是 596 。

解答:按照题意,利用双指针硬编码即可。

class Solution {
    public long findTheArrayConcVal(int[] nums) {
        long res = 0;
        int l = 0, r = nums.length - 1;
        while (l <= r) {
            if (l == r) {
                res += concate(nums[l], - 1);
            } else {
                res += concate(nums[l], nums[r]);
            }
            ++l;
            --r;
        }
        return res;
    }

    private long concate(int f, int l) {
        String tmp = String.valueOf(f);
        if (l != -1) {
            tmp += String.valueOf(l);
        }
        return Long.valueOf(tmp);
    }
}

6355. Count the Number of Fair Pairs

给你一个下标从 0 开始、长度为 n 的整数数组 nums ,和两个整数 lower 和 upper ,返回 公平数对的数目 。

如果 (i, j) 数对满足以下情况,则认为它是一个 公平数对 :

  • 0 <= i < j < n,且
  • lower <= nums[i] + nums[j] <= upper

测试样例:

输入:nums = [0,1,7,4,4,5], lower = 3, upper = 6

输出:6

解释:

共计 6 个公平数对:(0,3)、(0,4)、(0,5)、(1,3)、(1,4) 和 (1,5) 。

解答: 如果是用队列原来的循序搜索其实蛮困难的。所以我们首先利用排序,然后利用双指针搜索满足要求的区间。

class Solution {
    public long countFairPairs(int[] nums, int lower, int upper) {
        Arrays.sort(nums);
        int l = nums.length - 1, r = nums.length - 1;
        long res = 0;
        for (int i = 0; i < nums.length; ++i) {
            l = Math.max(i, l);
            while (l > i && nums[i] + nums[l] >= lower) {
                --l;
            }

            while (r > i && nums[i] + nums[r] > upper) {
                --r;
            }

            if (r - l >= 0) {
                res += (r - l);
            } else {
                break;
            }
        }
        return res;
    }
}

6356. Substring XOR Queries

给你一个 二进制字符串 s 和一个整数数组 queries ,其中 queries[i] = [firsti, secondi] 。

对于第 i 个查询,找到 s 的 最短子字符串 ,它对应的 十进制值 val 与 firsti 按位异或 得到 secondi ,换言之,val ^ firsti == secondi 。

第 i 个查询的答案是子字符串 [lefti, righti] 的两个端点(下标从 0 开始),如果不存在这样的子字符串,则答案为 [-1, -1] 。如果有多个答案,请你选择 lefti 最小的一个。

请你返回一个数组 ans ,其中 ans[i] = [lefti, righti] 是第 i 个查询的答案。

子字符串 是一个字符串中一段连续非空的字符序列。

测试样例

输入:s = "101101", queries = [[0,5],[1,2]]

输出:[[0,2],[2,3]]

解释:

第一个查询,端点为 [0,2] 的子字符串为 "101" ,对应十进制数字 5 ,且 5 ^ 0 = 5 ,所以第一个查询的答案为 [0,2]。第二个查询中,端点为 [2,3] 的子字符串为 "11" ,对应十进制数字 3 ,且 3 ^ 1 = 2 。所以第二个查询的答案为 [2,3] 。

解答:这道题是一道脑筋急转弯的题目,看着搜索空间很大,其实有一个重要的提示:

  • 0 <= firsti, secondi <= 10^9

所以每个s的位置记录向前的31位数字就可以了。这个时候最多保存31 * s.length()的数字。为了避免手贱溢出,我直接就用了Long了

class Solution {
    private static final int[] noExist = {-1,-1};

    public int[][] substringXorQueries(String s, int[][] queries) {
        HashMap<Long, int[]> map = new HashMap<>();
        for (int i = 0; i < s.length(); ++i) {
            long tmp = 0, mul = 1;
            for (int j = i; j >= 0; --j) {
                tmp += mul * (s.charAt(j) - '0');
                mul *= 2;
                if (tmp >= Integer.MAX_VALUE) {
                    break;
                } else if (!map.containsKey(tmp)) {
                    map.put(tmp, new int[]{j, i});
                }
            }
        }
        int[][] res = new int[queries.length][];
        for (int i = 0; i < queries.length; ++i) {
            long tmp = queries[i][1] ^ queries[i][0];
            res[i] = map.getOrDefault(tmp, noExist);
        }
        return res;
    }
}

6357. Subsequence With the Minimum Score

给你两个字符串 s 和 t 。

你可以从字符串 t 中删除任意数目的字符。

如果没有从字符串 t 中删除字符,那么得分为 0 ,否则:

  • 令 left 为删除字符中的最小下标。
  • 令 right 为删除字符中的最大下标。

字符串的得分为 right - left + 1 。

请你返回使 t 成为 s 子序列的最小得分。

一个字符串的 子序列 是从原字符串中删除一些字符后(也可以一个也不删除),剩余字符不改变顺序得到的字符串。(比方说 "ace" 是 "abcde" 的子序列,但是 "aec" 不是)。

测试样例

输入:s = "abacaba", t = "bzaa"

输出:1

解释:

这个例子中,我们删除下标 1 处的字符 "z" (下标从 0 开始)。
字符串 t 变为 "baa" ,它是字符串 "abacaba" 的子序列,得分为 1 - 1 + 1 = 1 。
1 是能得到的最小得分。

解答:这道题目又是一道脑筋急转弯的题目。如果需要right - left + 1最小,换个思路就是让right尽量的小,left尽量的大。那么这道题目可以换成2部分

  1. 从t的最后一个字符开始,逐步往前添加(right逐渐减小),查看最多可以覆盖多少个前缀字符(贪婪,寻找最大left)
  2. 从t的第一个一个字符开始,逐步往后添加(left逐渐增大),查看最多可以覆盖多少个后缀字符(贪婪,寻找最小right)

这道题目的code写的着实很烂,search1和search2完全硬编码实现了2个搜索。之后我有空的时候,会重写一下这道题目。

class Solution {
    public int minimumScore(String s, String t) {
        return Math.min(serach1(s, t), serach2(s, t));
    }

    private int serach1(String s, String t) {
        int sl = s.length(), tl = t.length();
        TreeMap<Integer, Integer> search = new TreeMap<>();
        int sp = 0;
        for (int i = 0; i < tl; ++i) {
            char c = t.charAt(i);
            while (sp < sl && s.charAt(sp) != c) {
                ++sp;
            }
            if (sp >= sl) break;
            else search.put(sp++, i);
        }

        int min = tl;
        sp = sl - 1;
        for (int i = tl - 1; i >= 0; --i) {
            char c = t.charAt(i);
            while (sp >= 0 && s.charAt(sp) != c) {
                --sp;
            }
            if (sp < 0) break;
            else {
                Map.Entry<Integer, Integer> lower = search.lowerEntry(sp--);
                if (lower == null) {
                    min = Math.min(min, i);
                } else {
                    min = Math.min(min, Math.max(0, i - lower.getValue() - 1));
                }
            }
        }
        return min;
    }

    private int serach2(String s, String t) {
        int sl = s.length(), tl = t.length();
        TreeMap<Integer, Integer> search = new TreeMap<>();
        int sp = sl - 1;
        for (int i = tl - 1; i >= 0; --i) {
            char c = t.charAt(i);
            while (sp >= 0 && s.charAt(sp) != c) {
                --sp;
            }
            if (sp < 0) break;
            else search.put(sp--, i);
        }

        int min = tl;
        sp = 0;
        for (int i = 0; i < tl; ++i) {
            char c = t.charAt(i);
            while (sp < sl && s.charAt(sp) != c) {
                ++sp;
            }
            if (sp >= sl) break;
            else {
                Map.Entry<Integer, Integer> higher = search.higherEntry(sp++);
                if (higher == null) {
                    min = Math.min(min, tl - i - 1);
                } else {
                    min = Math.min(min, Math.max(0, higher.getValue() - i - 1));
                }
            }
        }
        return min;
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *