双指针
大约 6 分钟
双指针
- OI Wiki: https://oi-wiki.org/misc/two-pointer/
- 分享丨【题单】滑动窗口(定长/不定长/多指针): https://leetcode.cn/circle/discuss/0viNMK/
定长滑动窗口
题目 | 难度 | |
---|---|---|
1456. 定长子串中元音的最大数目 | 中等 | 1263 |
643. 子数组最大平均数 I | 简单 | |
1343. 大小为 K 且平均值大于等于阈值的子数组数目 | 中等 | 1317 |
2090. 半径为 k 的子数组平均值 | 中等 | 1358 |
2379. 得到 K 个黑块的最少涂色次数 | 简单 | 1360 |
1052. 爱生气的书店老板 | 中等 | 1418 |
2841. 几乎唯一子数组的最大和 | 中等 | 1546 |
2461. 长度为 K 子数组中的最大和 | 中等 | 1553 |
1423. 可获得的最大点数 | 中等 | 1574 |
$1151. 最少交换次数来组合所有的 1 | 中等 | |
2134. 最少交换次数来组合所有的 1 II | 中等 | 1748 |
567. 字符串的排列 | 中等 | |
438. 找到字符串中所有字母异位词 | 中等 | |
2953. 统计完全子字符串 | 困难 | 2449 【好题】 |
不定长滑动窗口(求最长/最大)
题目 | 难度 | |
---|---|---|
3. 无重复字符的最长子串 | 中等 | |
1493. 删掉一个元素以后全为 1 的最长子数组 | 中等 | 1423 |
2730. 找到最长的半重复子字符串 | 中等 | 1502 【好题】 |
904. 水果成篮 | 中等 | 1516 |
1695. 删除子数组的最大得分 | 中等 | 1529 |
2958. 最多 K 个重复元素的最长子数组 | 中等 | 1535 |
2024. 考试的最大困扰度 | 中等 | 1643 |
1004. 最大连续 1 的个数 III | 中等 | 1656 |
239. 滑动窗口最大值 | 困难 | |
1438. 绝对差不超过限制的最长连续子数组 | 中等 | 1672 【好题】 |
2401. 最长优雅子数组 | 中等 | 1750 【好题】 |
1658. 将 x 减到 0 的最小操作数 | 中等 | 1817 |
1838. 最高频元素的频数 | 中等 | 1876 |
2516. 每种字符至少取 K 个 | 中等 | 1948 |
2831. 找出最长等值子数组 | 困难 | 1976 |
2106. 摘水果 | 困难 | 2062 |
2781. 最长合法子字符串的长度 | 困难 | 2204 【好题】优化 |
395. 至少有 K 个重复字符的最长子串 | 中等 | 【好题】分治 和 滑窗 |
1763. 最长的美好子字符串 | 简单 | 【好题】分治 和 滑窗 |
$159. 至多包含两个不同字符的最长子串 | 简单 | |
$340. 至多包含 K 个不同字符的最长子串 | 简单 |
不定长滑动窗口(求最短/最小)
题目 | 难度 | |
---|---|---|
209. 长度最小的子数组 | 中等 | |
1234. 替换子串得到平衡字符串 | 中等 | 1878 |
1574. 删除最短的子数组使剩余数组有序 | 中等 | 1932 |
76. 最小覆盖子串 | 困难 | |
面试题 17.18. 最短超串 | 中等 |
不定长滑动窗口(求子数组个数)
TODO
多指针滑动窗口
TODO
非滑窗
题目 | 难度 | |
---|---|---|
524. 通过删除字母匹配到字典里最长单词 | 中等 | |
167. 两数之和 II - 输入有序数组 | 中等 | |
15. 三数之和 | 中等 | |
1031. 两个非重叠子数组的最大和 | 中等 | 双指针 + 动态规划 |
1477. 找两个和为目标值且不重叠的子数组 | 中等 | 双指针 + 动态规划 |
2555. 两个线段获得的最多奖品 | 中等 | 双指针 + 动态规划 |
CF1154E | rating 1800 | 双指针 + 动态规划 |
类型
codeforces 上只有 two pointers
标签,没有滑动窗口的说法。
524. 通过删除字母匹配到字典里最长单词
import java.util.List;
public class Solution524 {
public String findLongestWord(String s, List<String> dictionary) {
String res = "";
for (String t : dictionary) {
// 双指针 判断 每个 t 是否为 s 的一个子序列
int p1 = 0;
int p2 = 0;
while (p1 < s.length() && p2 < t.length()) {
if (s.charAt(p1) == t.charAt(p2)) {
p2++;
}
p1++;
}
if (p2 == t.length()) {
// 遇到长度更长 或者 相同长度但字典序更小 时更新 res
if (t.length() > res.length() || (t.length() == res.length() && t.compareTo(res) < 0)) {
res = t;
}
}
}
return res;
}
}
167. 两数之和 II - 输入有序数组
public class Solution167 {
public int[] twoSum(int[] numbers, int target) {
int left = 0;
int right = numbers.length - 1;
while (left < right) {
int sum = numbers[left] + numbers[right];
if (sum == target) {
return new int[]{left + 1, right + 1};
} else if (sum < target) {
++left;
} else {
--right;
}
}
return new int[]{-1, -1};
}
}
15. 三数之和
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution15 {
public List<List<Integer>> threeSum(int[] nums) {
int len = nums.length;
if (len < 3) {
return new ArrayList<>();
}
Arrays.sort(nums);
List<List<Integer>> resList = new ArrayList<>();
for (int i = 0; i < len - 2; i++) {
// 剪枝
if (i - 1 >= 0 && nums[i - 1] == nums[i]) {
continue;
}
// 双指针
int left = i + 1;
int right = len - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
resList.add(List.of(nums[i], nums[left], nums[right]));
// 移动到下一个不相等的元素
int l0 = left + 1;
while (l0 < right && nums[l0] == nums[left]) {
l0++;
}
left = l0;
} else if (sum < 0) {
left++;
} else {
right--;
}
}
}
return resList;
}
}
1031. 两个非重叠子数组的最大和
public class Solution1031 {
public int maxSumTwoNoOverlap(int[] nums, int firstLen, int secondLen) {
return Math.max(dp(nums, firstLen, secondLen), dp(nums, secondLen, firstLen));
}
private int dp(int[] nums, int firstLen, int secondLen) {
int n = nums.length;
// f[i] 表示 [0, i) 之间长为 firstLen 的最大和
int[] f = new int[n + 1];
int l = 0, r = 0, sum = 0, max = 0;
while (r < n) {
sum += nums[r];
while (r - l + 1 > firstLen) sum -= nums[l++];
max = Math.max(max, sum);
f[r + 1] = Math.max(f[r], max);
r++;
}
r = l = sum = max = 0;
while (r < n) {
sum += nums[r];
while (r - l + 1 > secondLen) sum -= nums[l++];
max = Math.max(max, sum + f[l]);
r++;
}
return max;
}
}
1477. 找两个和为目标值且不重叠的子数组
public class Solution1477 {
public int minSumOfLengths(int[] arr, int target) {
int n = arr.length;
// f[i] 表示 [0, i) 之间最短的和为 target 的子数组长度
int[] f = new int[n + 1];
f[0] = n + 1;
int l = 0, r = 0;
int sum = 0;
int min = n + 1;
while (r < n) {
sum += arr[r];
while (sum > target) {
sum -= arr[l];
l++;
}
if (sum == target) {
min = Math.min(min, (r - l + 1) + f[l]);
f[r + 1] = Math.min(f[r], r - l + 1);
} else {
f[r + 1] = f[r];
}
r++;
}
return (min == n + 1) ? -1 : min;
}
}
2555. 两个线段获得的最多奖品
public class Solution2555 {
public int maximizeWin(int[] prizePositions, int k) {
int n = prizePositions.length;
// f[i] 表示 [0, i) 线段长度 <= k 的最多奖品数
int[] f = new int[n + 1];
int l = 0, r = 0;
int res = 0;
while (r < n) {
while (prizePositions[r] - prizePositions[l] > k) {
l++;
}
res = Math.max(res, (r - l + 1) + f[l]);
f[r + 1] = Math.max(f[r], r - l + 1);
r++;
}
return res;
}
}
(全文完)