欢迎大家加QQ群:623375442,可以方便群里面交流。这周题目,太要求仔细了。写起来真的好麻烦。

100525. Maximum Subarray With Equal Products

给你一个由 正整数 组成的数组 nums。

如果一个数组 arr 满足 prod(arr) == lcm(arr) * gcd(arr),则称其为 乘积等价数组 ,其中:

  • prod(arr) 表示 arr 中所有元素的乘积。
  • gcd(arr) 表示 arr 中所有元素的最大公因数 (GCD)。
  • lcm(arr) 表示 arr 中所有元素的最小公倍数 (LCM)。

返回数组 nums 的 最长 乘积等价子数组 的长度。

子数组 是数组中连续的、非空的元素序列。

术语 gcd(a, b) 表示 a 和 b 的 最大公因数 。

术语 lcm(a, b) 表示 a 和 b 的 最小公倍数 。

测试样例:

输入:nums = [1,2,1,2,1,1,1]

输出:5

解释:按照题意暴力计算。

解答:按照题意,暴力计算。

class Solution {
    public int maxLength(int[] nums) {
        int res = 1;
        for (int i = 0; i < nums.length; ++i) {
            long mul = nums[i], gcd = nums[i], lcm = nums[i];
            for (int j = i + 1; j < nums.length; ++j) {
                gcd = gcd(gcd, nums[j]);
                mul *= nums[j];
                lcm = lcm * nums[j] / gcd(lcm, nums[j]);
                if (gcd * lcm == mul) {
                    res = Math.max(res, j - i + 1);
                } else {
                    break;
                }
            }
        }
        return res;
    }

    private long gcd(long x, long y) {
        while (y != 0) {
            long tmp = x % y;
            x = y;
            y = tmp;
        }
        return x;
    }
}

100476. Find Mirror Score of a String

给你一个字符串 s。

英文字母中每个字母的 镜像 定义为反转字母表之后对应位置上的字母。例如,'a' 的镜像是 'z','y' 的镜像是 'b'。

最初,字符串 s 中的所有字符都 未标记 。

字符串 s 的初始分数为 0 ,你需要对其执行以下过程:

  • 从左到右遍历字符串。
  • 对于每个下标 i ,找到距离最近的 未标记 下标 j,下标 j 需要满足 j < i 且 s[j] 是 s[i] 的镜像。然后 标记 下标 i 和 j,总分加上 i - j 的值。
  • 如果对于下标 i,不存在满足条件的下标 j,则跳过该下标,继续处理下一个下标,不需要进行标记。

返回最终的总分。

测试样例:

输入: s = "aczzx"

输出:5

解释:所有可能的分割方式为:

  • i = 0。没有符合条件的下标 j,跳过。
  • i = 1。没有符合条件的下标 j,跳过。
  • i = 2。距离最近的符合条件的下标是 j = 0,因此标记下标 0 和 2,然后将总分加上 2 - 0 = 2 。
  • i = 3。没有符合条件的下标 j,跳过。
  • i = 4。距离最近的符合条件的下标是 j = 1,因此标记下标 1 和 4,然后将总分加上 4 - 1 = 3 。

解答:这周最简单的题目,用栈模拟一下即可。

class Solution {
    public long calculateScore(String s) {
        long res = 0;
        Stack<Integer>[] map = new Stack[26];
        for (int i = 0; i < 26; ++i) {
            map[i] = new Stack<>();
        }
        for (int i = 0; i < s.length(); ++i) {
            int tmp = s.charAt(i) - 'a';
            if (!map[25 - tmp].isEmpty()) {
                res += (i - map[25 - tmp].pop());
            } else {
                map[tmp].push(i);
            }
        }
        return res;
    }
}

100535. Maximum Coins From K Consecutive Bags

在一条数轴上有无限多个袋子,每个坐标对应一个袋子。其中一些袋子里装有硬币。

给你一个二维数组 coins,其中 coins[i] = [li, ri, ci] 表示从坐标 li 到 ri 的每个袋子中都有 ci 枚硬币。

数组 coins 中的区间互不重叠。

另给你一个整数 k。

返回通过收集连续 k 个袋子可以获得的 最多 硬币数量。

测试样例:

输入:coins = [[8,10,1],[1,3,2],[5,6,4]], k = 4

输出:10

解释:选择坐标为 [3, 4, 5, 6] 的袋子可以获得最多硬币:2 + 0 + 4 + 4 = 10。

解答:稍微脑筋急转弯一下。最大范围一定是从一个区间的左边向后找到最大范围,或者从一个区间的右边向前最大范围。

class Solution {
    public long maximumCoins(int[][] coins, long k) {
        Arrays.sort(coins, (a, b) -> (Integer.compare(a[0], b[0])));
        long res = 0;
        {
            int left = 0, right = 0;
            long cur = 0;
            // 锁定左区间,然后向后找最大范围
            while (left < coins.length) {
                while (right < coins.length && coins[right][1] - coins[left][0] < k) {
                    cur += (coins[right][1] - coins[right][0] + 1L) * coins[right][2];
                    ++right;
                }
                if (right < coins.length && coins[right][1] - coins[left][0] >= k && coins[right][0] - coins[left][0] < k) {
                    res = Math.max(res, cur + (coins[left][0] + k - coins[right][0]) * coins[right][2]);
                } else {
                    res = Math.max(res, cur);
                }
                if (coins[left][1] - coins[left][0] < k) {
                    cur -= (coins[left][1] - coins[left][0] + 1L) * coins[left][2];
                }
                ++left;
                right = Math.max(right, left);
            }
        }
        {
            int left = coins.length - 1, right = coins.length - 1;
            long cur = 0;
            // 锁定右区间,然后向前找最大范围
            while (right >= 0) {
                while (left >= 0 && coins[right][1] - coins[left][0] < k) {
                    cur += (coins[left][1] - coins[left][0] + 1L) * coins[left][2];
                    --left;
                }
                if (left >= 0 && coins[right][1] - coins[left][0] >= k && coins[right][1] - coins[left][1] < k) {
                    res = Math.max(res, cur + (coins[left][1] - coins[right][1] + k) * coins[left][2]);
                } else {
                    res = Math.max(res, cur);
                }
                if (coins[right][1] - coins[right][0] < k) {
                    cur -= (coins[right][1] - coins[right][0] + 1L) * coins[right][2];
                }
                --right;
                left = Math.min(left, right);
            }
        }
        return res;
    }
}

100418. Maximum Score of Non-overlapping Intervals

给你一个二维整数数组 intervals,其中 intervals[i] = [li, ri, weighti]。区间 i 的起点为 li,终点为 ri,权重为 weighti。你最多可以选择 4 个互不重叠 的区间。所选择区间的 得分 定义为这些区间权重的总和。

返回一个至多包含 4 个下标且字典序最小的数组,表示从 intervals 中选中的互不重叠且得分最大的区间。

如果两个区间没有任何重叠点,则称二者 互不重叠 。特别地,如果两个区间共享左边界或右边界,也认为二者重叠。

数组 a 的字典序小于数组 b 的前提是:当在第一个不同的位置上,a 的元素小于 b 的对应元素。如果前 min(a.length, b.length) 个元素均相同,则较短的数组字典序更小。

测试样例:

输入:intervals = [[1,3,2],[4,5,2],[1,5,5],[6,9,3],[6,7,1],[8,9,1]]

输出:[2,3]

解释:可以选择下标为 2 和 3 的区间,其权重分别为 5 和 3。

解答:只能说比昨天的双周赛简单很多。比较标准的俄罗斯套娃娃的改变题目。主要写代码需要仔细一点。我是WA了好几次。

class Solution {
    public int[] maximumWeight(List<List<Integer>> _intervals) {
        int[][] intervals = new int[_intervals.size()][3];
        int pos = 0;
        for (List<Integer> interval : _intervals) {
            for (int i = 0; i < 3; ++i) {
                intervals[pos][i] = interval.get(i);
            }
            ++pos;
        }
        Integer[] sort = new Integer[intervals.length];
        for (int i = 0; i < sort.length; ++i) {
            sort[i] = i;
        }
        Arrays.sort(sort, (a, b) -> (Integer.compare(intervals[a][1], intervals[b][1])));
        TreeMap<Integer, List<Integer>[]> mem = new TreeMap<>();

        List<Integer>[] res = new List[4];
        for (int i = 0; i < 4; ++i) {
            res[i] = new ArrayList<>();
        }
        for (int s : sort) {
            Map.Entry<Integer, List<Integer>[]> lowerEntry = mem.lowerEntry(intervals[s][0]);
            List<Integer>[] best = new List[4];
            if (lowerEntry == null) {
                best[0] = new ArrayList<>();
                best[0].add(s);
            } else {
                List<Integer>[] lower = lowerEntry.getValue();
                for (int i = 0; i < 4; ++i) {
                    if (i == 0) {
                        best[0] = new ArrayList<>();
                        best[0].add(s);
                    } else {
                        best[i] = duplicate(lower[i - 1]);
                        best[i].add(s);
                        Collections.sort(best[i]);
                    }
                }
            }
            res = better(res, best, intervals);
            mem.put(intervals[s][1], res);
        }
        List<Integer> best = null;
        for (int i = 3; i >= 0; --i) {
            best = better(best, res[i], intervals);
        }
        int[] resFormat = new int[best.size()];
        for (int j = 0; j < resFormat.length; ++j) {
            resFormat[j] = best.get(j);
        }
        return resFormat;
    }

    private List<Integer>[] better(List<Integer>[] lefts, List<Integer>[] rights, int[][] intervals) {
        List<Integer>[] res = new List[4];
        for (int i = 0; i < 4; ++i) {
            res[i] = better(lefts[i], rights[i], intervals);
        }
        return res;
    }

    private List<Integer> better(List<Integer> left, List<Integer> right, int[][] intervals) {
        if (left == null) return right;
        else if (right == null) return left;
        long s1 = 0, s2 = 0;
        for (int n : left) {
            s1 += intervals[n][2];
        }
        for (int n : right) {
            s2 += intervals[n][2];
        }
        if (s1 > s2) {
            return left;
        } else if (s1 < s2) {
            return right;
        } else {
            for (int i = 0; i < Math.min(left.size(), right.size()); ++i) {
                int tmp = left.get(i).compareTo(right.get(i));
                if (tmp > 0) {
                    return right;
                } else if (tmp < 0) {
                    return left;
                }
            }
            return right;
        }
    }

    private List<Integer> duplicate(List<Integer> old) {
        List<Integer> res = new ArrayList<>(old);
        return res;
    }
}

Leave a Reply

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