目录
一,3411. 最长乘积等价子数组
二,3412. 计算字符串的镜像分数
三,3413. 收集连续 K 个袋子可以获得的最多硬币数量
四,3414. 不重叠区间的最大得分
一,3411. 最长乘积等价子数组
本题数据范围小,直接暴力枚举,代码如下:
class Solution {public int maxLength(int[] nums) {int n = nums.length;int ans = 0;for(int l=0; l<n; l++){for(int r=l; r<n; r++){int p = 1, g = 0, lc = 1;for(int i=l; i<=r; i++){p *= nums[i];g = gcd(nums[i], g);lc = lcm(nums[i], lc);}if(p == g * lc) ans = Math.max(ans, r-l+1);}}return ans;}int gcd(int a, int b){return b==0?a:gcd(b,a%b);}int lcm(int a, int b){return a*b/gcd(a,b);}
}
二,3412. 计算字符串的镜像分数
本题就是要存储26个字母的出现的所有下标,对于 s[i] 来说,需要找到相应镜像的字母 c,然后返回字母 c 最近的下标,也就是说,需要一个先进后出的数据结构——栈来存储 26 个字母的下标,代码如下:
class Solution {public long calculateScore(String s) {Stack<Integer>[] st = new Stack[26];Arrays.setAll(st, e->new Stack<>());long ans = 0;for(int i=0; i<s.length(); i++){int c = s.charAt(i) - 'a';if(!st[25-c].isEmpty()){ans += i - st[25-c].pop();}else{st[c].push(i);}}return ans;}
}
三,3413. 收集连续 K 个袋子可以获得的最多硬币数量
本题求连续 k 个袋子可获得的最多硬币数量,就是维护一个长度为 k 的滑动窗口,关键的问题就变成了如何维护窗口的更新(进/出),求最多,贪心的想对于一个区间 [L,R],需要尽可能多的包含这个区间,那么有两种情况——以 L 为左端点,向右维护一个长为 k 的窗口;以 R 为右端点,向左维护一个长为 k 的窗口。需要分别求出上述两种情况,取最大值。
这里写以 L 为左端点,向右维护一个长为 k 的窗口的维护方法,另一种可以通过镜像的方式,复用此代码。如图所示:
代码如下:
class Solution {long window(int[][] f, int k){int n = f.length;long ans = 0;long cover = 0, uncover = 0;for(int i=0, j=0; i<n; i++){long l = f[i][0], r = f[i][1], c = f[i][2];cover += (r - l + 1) * c;while(f[j][1] < r - k + 1){cover -= (long)(f[j][1] - f[j][0] + 1) * f[j][2];j++;}uncover = Math.max((long)(r - k + 1 - f[j][0]) * f[j][2], 0) ;ans = Math.max(ans, cover - uncover);}return ans;}public long maximumCoins(int[][] coins, int k) {Arrays.sort(coins, (x, y) -> x[0] - y[0]);long ans = window(coins, k);for(int[] c : coins){int t = -c[0];c[0] = -c[1];c[1] = t;}int n = coins.length;for(int i=0; i<n/2; i++){int[] t = coins[i];coins[i] = coins[n-1-i];coins[n-1-i] = t;}return Math.max(ans, window(coins, k));}
}
四,3414. 不重叠区间的最大得分
定义f[i][j]: 在前 i 个区间选出 j 个不重叠区间的最大得分和此时字典序最小的区间下标顺序。标准的0-1背包做法,难点在于维护字典序最小的区间下标顺序。
代码如下:
class Solution {private record Tuple(long w, List<Integer> id){}private record Info(int l, int r, int w, int i){}public int[] maximumWeight(List<List<Integer>> intervals) {int n = intervals.size();Info[] t = new Info[n];for(int i=0; i<n; i++){List<Integer> x = intervals.get(i);int l = x.get(0), r = x.get(1), w = x.get(2);t[i] = new Info(l, r, w, i);}Arrays.sort(t, (x, y) -> x.r - y.r);Tuple[][] f = new Tuple[n+1][5];Arrays.setAll(f[0], e->new Tuple(0, new ArrayList<>()));for(int i=0; i<n; i++){int l = t[i].l, r = t[i].r, w = t[i].w;int k = search(t, l-1, i);f[i+1][0] = new Tuple(0, new ArrayList<>());for(int j=1; j<5; j++){long s1 = f[i][j].w;long s2 = f[k+1][j-1].w + w;if(s1 > s2){f[i+1][j] = f[i][j];continue;}List<Integer> tmp = new ArrayList<>(f[k+1][j-1].id);tmp.add(t[i].i);Collections.sort(tmp);if(s1 == s2 && compareLists(tmp, f[i][j].id) > 0){tmp = f[i][j].id;}f[i+1][j] = new Tuple(s2, tmp);}}return f[n][4].id.stream().mapToInt(v->v).toArray();}int compareLists(List<Integer> a, List<Integer> b){for(int i=0; i<Math.min(a.size(), b.size()); i++){if(!a.get(i).equals(b.get(i)))return a.get(i) - b.get(i);}return a.size() - b.size();}int search(Info[] t, int k, int r){int l = 0;while(l <= r){int mid = (l + r) >>> 1;if(t[mid].r <= k){l = mid + 1;}else{r = mid - 1;}}return l - 1;}
}