diff --git a/src/main/java/array/MaxSubArray.java b/src/main/java/array/MaxSubArray.java index 1405a86..db8b2cd 100644 --- a/src/main/java/array/MaxSubArray.java +++ b/src/main/java/array/MaxSubArray.java @@ -18,6 +18,7 @@ package array; 输出:23 */ +//二刷会做 public class MaxSubArray { public int maxSubArray(int[] nums) { int tempsum=nums[0],maxsum=nums[0]; @@ -31,6 +32,7 @@ public class MaxSubArray { return maxsum; } //假设还要同时返回起始结束下标: + //[-2,1,-3,4,-1,2,1,-5,4] public int[] maxSubArray2(int[] nums) { int tempsum = nums[0]; // 当前子数组的和 int maxsum = nums[0]; // 最大子数组和 diff --git a/src/main/java/array/Merge.java b/src/main/java/array/Merge.java index dd5fa45..6c01f21 100644 --- a/src/main/java/array/Merge.java +++ b/src/main/java/array/Merge.java @@ -20,13 +20,13 @@ import java.util.List; 输出:[[1,5]] 解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。 */ - +//二刷会做 public class Merge { public int[][] merge(int[][] intervals) { Arrays.sort(intervals,(a,b)->{ - if(a[0]!=b[0]){ + if(a[0]!=b[0]) return a[0]-b[0]; - }else + else return a[1]-b[1]; }); Listmerged=new ArrayList<>(); diff --git a/src/main/java/array/RotateArray.java b/src/main/java/array/RotateArray.java index b515c3e..4bc4b20 100644 --- a/src/main/java/array/RotateArray.java +++ b/src/main/java/array/RotateArray.java @@ -19,9 +19,9 @@ package array; 向右轮转 1 步: [99,-1,-100,3] 向右轮转 2 步: [3,99,-1,-100] */ - +//二刷会做 public class RotateArray { - public void rotateArray(int[] nums, int k) { + public void rotateArray2(int[] nums, int k) { int cnt=nums.length,index=0; int offset=k%cnt; int[]temp=new int[k]; @@ -36,4 +36,27 @@ public class RotateArray { nums[i]=temp[i]; } } + + public void rotateArray(int[] nums, int k) { + int n = nums.length; + k %= n; // 防止 k > n + if (k == 0) return; + + // 1. 整体翻转 [0, n-1] + reverse(nums, 0, n - 1); + // 2. 前 k 个翻转 [0, k-1] + reverse(nums, 0, k - 1); + // 3. 剩余部分翻转 [k, n-1] + reverse(nums, k, n - 1); + } + + // 原地翻转 helper + private void reverse(int[] a, int i, int j) { + while (i < j) { + int tmp = a[i]; + a[i++] = a[j]; + a[j--] = tmp; + } + } + } diff --git a/src/main/java/substring/MinWindow.java b/src/main/java/substring/MinWindow.java new file mode 100644 index 0000000..def4f30 --- /dev/null +++ b/src/main/java/substring/MinWindow.java @@ -0,0 +1,98 @@ +package substring; + +import java.util.Arrays; +import java.util.HashMap; + +/** + * 题目:76. 最小覆盖子串 (minWindow) + * 描述:给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。 + * 注意: + * + * 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 + * 如果 s 中存在这样的子串,我们保证它是唯一的答案。 + * + * 链接:https://leetcode.cn/problems/minimum-window-substring/ + * + 示例 1: + 输入:s = "ADOBECODEBANC", t = "ABC" + 输出:"BANC" + 解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。 + + */ +//不会 +public class MinWindow { + /** + *滑动窗口的核心是:用两根指针 l、r 在 s 上维护一个区间,既能“扩”又能“收”,保证它包含 t 中所有字符且最小。 + * + * 用数组 need[128] 记录 t 中每个字符的需求次数,window[128] 记录当前窗口中的次数,valid 记录满足需求的字符种类数。 + * 右指针 r 向右滑,遇到 need[s[r]]>0 时增加 window[s[r]],若 window[s[r]]==need[s[r]] 则 valid++。 + * 当 valid == 需要的字符种类数 时,可尝试用左指针 l 收缩窗口: + * 更新最小长度; + * 若移出字符 d=s[l] 且 need[d]>0,window[d]--,若 window[d] 0) required++; + } + + // 2. 初始化窗口左右边界、已满足种类数、最优结果 + int left = 0, right = 0; + int valid = 0; + int start = 0, minLen = Integer.MAX_VALUE; + + // 3. 开始滑动右边界 + while (right < s.length()) { + char c = s.charAt(right); + right++; + // 如果是目标字符,则更新 window 计数,且可能增加 valid + if (need[c] > 0) { + window[c]++; + if (window[c] == need[c]) { + valid++; + } + } + + // 4. 当所有字符需求都已满足时,尝试收缩左边界 + while (valid == required) { + // 更新最小覆盖子串 + if (right - left < minLen) { + start = left; + minLen = right - left; + } + // d 是将移出窗口的字符 + char d = s.charAt(left); + left++; + if (need[d] > 0) { + //因为window[d]的数量可能>need[d]的数量,减掉一个还是valid + if (window[d] == need[d]) { + valid--; + } + window[d]--; + } + } + } + + // 5. 返回结果 + return minLen == Integer.MAX_VALUE + ? "" + : s.substring(start, start + minLen); + } +} +