[Leetcode Weekly Contest]332

链接:LeetCode

[Leetcode]2562. 找出数组的串联值

给你一个下标从 0 开始的整数数组 nums 。
现定义两个数字的 串联 是由这两个数值串联起来形成的新数字。
例如,15 和 49 的串联是 1549 。
nums 的 串联值 最初等于 0 。执行下述操作直到 nums 变为空:
如果 nums 中存在不止一个数字,分别选中 nums 中的第一个元素和最后一个元素,将二者串联得到的值加到 nums 的 串联值 上,然后从 nums 中删除第一个和最后一个元素。
如果仅存在一个元素,则将该元素的值加到 nums 的串联值上,然后删除这个元素。
返回执行完所有操作后 nums 的串联值。

遍历即可。

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

    public int concat(int num1, int num2) {
        int length = 1, temp = num2;
        while(temp!=0) {
            length *= 10;
            temp /= 10;
        }
        return num1 * length + num2;
    }
}

[Leetcode]2563. 统计公平数对的数目

给你一个下标从 0 开始、长度为 n 的整数数组 nums ,和两个整数 lower 和 upper ,返回 公平数对的数目 。
如果 (i, j) 数对满足以下情况,则认为它是一个 公平数对 :

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

由于排序不会影响数对的个数,为了能够二分,可以先排序。
然后枚举 nums[i],二分查找符合要求的nums[j] 的个数。

class Solution {
    public long countFairPairs(int[] nums, int lower, int upper) {
        Arrays.sort(nums);
        long res = 0L;
        for(int i=0;i<nums.length;++i) {
            int left = getFirstLargerOrEqualIndex(nums, lower-nums[i]);
            int right = getLastSmallerOrEqualIndex(nums, upper-nums[i]);
            if(i>=left && i<=right)res += right-left;
            else res += right-left+1;

        }
        return res/2;
    }

    public int getFirstLargerOrEqualIndex(int[] nums, int target) {
        int lo=0, hi = nums.length-1;
        while(lo<=hi) {
            int mid = lo+((hi-lo)>>1);
            if(target <= nums[mid]) {
                hi =  mid - 1;
            } else {
                lo = mid + 1;
            }
        }
        return lo;
    }

    public int getLastSmallerOrEqualIndex(int[] nums, int target) {
        int lo=0, hi = nums.length-1;
        while(lo<=hi) {
            int mid = lo+((hi-lo)>>1);
            if(target < nums[mid]) {
                hi =  mid - 1;
            } else {
                lo = mid + 1;
            }
        }
        return hi;
    }
}

[Leetcode]2564. 子字符串异或查询

给你一个 二进制字符串 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 中找到值为 second⊕first 的数。
由于 \(10^9 < 2^30\), 我们可以直接预计算所有 s 中长度不超过 30 的数及其对应的 left 和 right,记到一个哈希表中,然后 O(1) 地回答询问。

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

    public int[][] substringXorQueries(String S, int[][] queries) {
        var m = new HashMap<Integer, int[]>();
        int i = S.indexOf('0');
        if (i >= 0) m.put(0, new int[]{i, i}); // 这样下面就可以直接跳过 '0' 了,效率更高
        var s = S.toCharArray();
        for (int l = 0, n = s.length; l < n; ++l) {
            if (s[l] == '0') continue;
            for (int r = l, x = 0; r < Math.min(l + 30, n); ++r) {
                x = x << 1 | (s[r] & 1);
                m.putIfAbsent(x, new int[]{l, r});
            }
        }

        var ans = new int[queries.length][];
        for (i = 0; i < queries.length; i++)
            ans[i] = m.getOrDefault(queries[i][0] ^ queries[i][1], NOT_FOUND);
        return ans;
    }
}

[Leetcode]2565. 最少得分子序列

给你两个字符串 s 和 t 。
你可以从字符串 t 中删除任意数目的字符。
如果没有从字符串 t 中删除字符,那么得分为 0 ,否则:

  • 令 left 为删除字符中的最小下标。
  • 令 right 为删除字符中的最大下标。
    字符串的得分为 right - left + 1 。
    请你返回使 t 成为 s 子序列的最小得分。
    一个字符串的 子序列 是从原字符串中删除一些字符后(也可以一个也不删除),剩余字符不改变顺序得到的字符串。(比方说 "ace" 是 "abcde" 的子序列,但是 "aec" 不是)

前后缀分解+双指针.
left和right之间的都删掉,不违背题目的意愿,也更好地成为子序列。我们直接计算 s 的前缀 s[:i] 能够匹配 t 的前缀的最大长度 prefix[i],计算 s 的后缀 s[i:] 能够匹配 t 的前缀的最大长度 suffix[i],枚举 s 的前缀与后缀,找到前缀 s[:i] 与 后缀 s[(i+1):] 的最长匹配的之和,找到最大的前缀和匹配之和即可。
prefix[i]+suffix[i+1] 一定满足小于 n 的,否则两个字符串完全匹配直接返回 0。

class Solution {
    public int minimumScore(String s, String t) {
        int sn = s.length();
        int tn = t.length();

        int [] prefix_cnt = new int[sn + 1];
        int [] suffix_cnt = new int[sn + 1];

        prefix_cnt[0] = 0;
        int ti = 0;
        int cnt = 0;
        for (int si = 0; si < sn; si ++){
            if (ti < tn && s.charAt(si) == t.charAt(ti)){
                ti ++;
                cnt ++;
            }
            prefix_cnt[si + 1] = cnt;
        }

        suffix_cnt[sn] = 0;
        ti = tn - 1;
        cnt = 0;
        for (int si = sn - 1; si > -1; si --){
            if (0 <= ti && s.charAt(si) == t.charAt(ti)){
                ti --;
                cnt ++;
            }
            suffix_cnt[si] = cnt;
        }

        int res = tn;
        for (int si = 0; si < sn + 1; si ++){
            int cur = tn - (prefix_cnt[si] + suffix_cnt[si]);
            cur = Math.max(0, cur);
            res = Math.min(res, cur);
        }
        return res;
    }
}

参考:LeetCode

posted @ 2023-02-23 09:33  Jamest  阅读(13)  评论(0编辑  收藏  举报