From a0c713479951b0c31d63603cd5d8ec64ec3e2732 Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Tue, 11 Mar 2025 17:08:00 +0800 Subject: [PATCH] =?UTF-8?q?3.11=E5=AD=90=E4=B8=B2+=E6=99=AE=E9=80=9A?= =?UTF-8?q?=E6=95=B0=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/array/MaxSubArray.java | 33 +++++++ src/main/java/array/Merge.java | 49 ++++++++++ src/main/java/array/RotateArray.java | 39 ++++++++ src/main/java/substring/CheckSubarraySum.java | 82 +++++++++++++++++ src/main/java/substring/MaxSlidingWindow.java | 89 +++++++++++++++++++ src/main/java/substring/SubarraySum.java | 61 +++++++++++++ src/test/java/array/MaxSubArrayTest.java | 16 ++++ src/test/java/array/MergeTest.java | 16 ++++ src/test/java/array/RotateArrayTest.java | 19 ++++ .../java/substring/CheckSubarraySumTest.java | 17 ++++ .../java/substring/MaxSlidingWindowTest.java | 20 +++++ src/test/java/substring/SubarraySumTest.java | 26 ++++++ 12 files changed, 467 insertions(+) create mode 100644 src/main/java/array/MaxSubArray.java create mode 100644 src/main/java/array/Merge.java create mode 100644 src/main/java/array/RotateArray.java create mode 100644 src/main/java/substring/CheckSubarraySum.java create mode 100644 src/main/java/substring/MaxSlidingWindow.java create mode 100644 src/main/java/substring/SubarraySum.java create mode 100644 src/test/java/array/MaxSubArrayTest.java create mode 100644 src/test/java/array/MergeTest.java create mode 100644 src/test/java/array/RotateArrayTest.java create mode 100644 src/test/java/substring/CheckSubarraySumTest.java create mode 100644 src/test/java/substring/MaxSlidingWindowTest.java create mode 100644 src/test/java/substring/SubarraySumTest.java diff --git a/src/main/java/array/MaxSubArray.java b/src/main/java/array/MaxSubArray.java new file mode 100644 index 0000000..d7252bc --- /dev/null +++ b/src/main/java/array/MaxSubArray.java @@ -0,0 +1,33 @@ +package array; +/** + * 题目:53. 最大子数组和 (maxSubArray) + * 描述:给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 + 子数组是数组中的一个连续部分。 + * 链接:https://leetcode.cn/problems/maximum-subarray/ + 示例 1: + 输入:nums = [-2,1,-3,4,-1,2,1,-5,4] + 输出:6 + 解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。 + + 示例 2: + 输入:nums = [1] + 输出:1 + + 示例 3: + 输入:nums = [5,4,-1,7,8] + 输出:23 + + */ +public class MaxSubArray { + public int maxSubArray(int[] nums) { + int tempsum=nums[0],maxsum=nums[0]; + for (int i = 1; i < nums.length; i++) { + if(tempsum<0) + tempsum=0; + tempsum+=nums[i]; + if(maxsum{ + if(a[0]!=b[0]){ + return a[0]-b[0]; + }else + return a[1]-b[1]; + }); + Listmerged=new ArrayList<>(); + int[] current = new int[2]; + current[0] = intervals[0][0]; + current[1] = intervals[0][1]; + for (int i = 1; i < intervals.length; i++) { + if (current[1] >= intervals[i][0]) { + // 重叠时合并区间,更新右边界 + current[1] = Math.max(current[1], intervals[i][1]); + } + else{ + merged.add(new int[]{current[0], current[1]}); + current = new int[]{intervals[i][0], intervals[i][1]}; + } + } + merged.add(new int[]{current[0], current[1]}); + return merged.toArray(new int[merged.size()][]); + } +} diff --git a/src/main/java/array/RotateArray.java b/src/main/java/array/RotateArray.java new file mode 100644 index 0000000..b515c3e --- /dev/null +++ b/src/main/java/array/RotateArray.java @@ -0,0 +1,39 @@ +package array; +/** + * 题目:189. 轮转数组 (rotate) + * 描述:给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。 + + * 链接:https://leetcode.cn/problems/rotate-array/ + 示例 1: + 输入: nums = [1,2,3,4,5,6,7], k = 3 + 输出: [5,6,7,1,2,3,4] + 解释: + 向右轮转 1 步: [7,1,2,3,4,5,6] + 向右轮转 2 步: [6,7,1,2,3,4,5] + 向右轮转 3 步: [5,6,7,1,2,3,4] + + 示例 2: + 输入:nums = [-1,-100,3,99], k = 2 + 输出:[3,99,-1,-100] + 解释: + 向右轮转 1 步: [99,-1,-100,3] + 向右轮转 2 步: [3,99,-1,-100] + */ + +public class RotateArray { + public void rotateArray(int[] nums, int k) { + int cnt=nums.length,index=0; + int offset=k%cnt; + int[]temp=new int[k]; + for (int i = cnt-offset; i < cnt; i++) { + temp[index]=nums[i]; + index++; + } + for (int i = cnt-1; i>=offset ; i--) { + nums[i]=nums[i-offset]; + } + for (int i = 0; i < offset; i++) { + nums[i]=temp[i]; + } + } +} diff --git a/src/main/java/substring/CheckSubarraySum.java b/src/main/java/substring/CheckSubarraySum.java new file mode 100644 index 0000000..d4e2467 --- /dev/null +++ b/src/main/java/substring/CheckSubarraySum.java @@ -0,0 +1,82 @@ +package substring; + +import hash.Test; + +import java.util.HashMap; +import java.util.Iterator; + +/** + * 题目:523. 连续的子数组和 (checkSubarraySum) + * 描述:给你一个整数数组 nums 和一个整数 k ,如果 nums 有一个 好的子数组 返回 true ,否则返回 false: + 一个 好的子数组 是: + 长度 至少为 2 ,且 + * 子数组元素总和为 k 的倍数。 + * 注意: + * 子数组 是数组中 连续 的部分。 + * 如果存在一个整数 n ,令整数 x 符合 x = n * k ,则称 x 是 k 的一个倍数。0 始终 视为 k 的一个倍数。 + * + * 链接:https://leetcode.cn/problems/continuous-subarray-sum/ + + 示例 1: + 输入:nums = [23,2,4,6,7], k = 6 + 输出:true + 解释:[2,4] 是一个大小为 2 的子数组,并且和为 6 。 + + 示例 2: + 输入:nums = [23,2,6,4,7], k = 6 + 输出:true + 解释:[23, 2, 6, 4, 7] 是大小为 5 的子数组,并且和为 42 。 + 42 是 6 的倍数,因为 42 = 7 * 6 且 7 是一个整数。 + + 示例 3: + 输入:nums = [23,2,6,4,7], k = 13 + 输出:false + */ +//需重做 +//本题不一样的地方是无需统计个数,故哈希表中键值可以存索引。 +public class CheckSubarraySum { + //枚举法超时 + public boolean checkSubarraySum1(int[] nums, int k) { + for (int left = 0; left < nums.length; left++) { + int tpsum=nums[left]; + for (int right = left+1; right < nums.length; right++) { + tpsum+=nums[right]; + if(tpsum%k==0) + return true; + } + } + return false; + } + //前缀和 这题需要判断子数组和是否为 k 的倍数,因此我们关心的是前缀和对 k 取余后的值是否相等 + public boolean checkSubarraySum(int[] nums, int k) { + // 特殊情况:k == 0 的处理,寻找连续和为 0 的子数组 + if (k == 0) { + for (int i = 0; i < nums.length - 1; i++) { + if (nums[i] == 0 && nums[i+1] == 0) { + return true; + } + } + return false; + } + + // 哈希表存储前缀和 mod k 的余数及其第一次出现的下标 + HashMap modMap = new HashMap<>(); + modMap.put(0, -1); // 余数为0时,将下标设为-1,方便处理从数组开头开始的情况 + int prefixSum = 0; + + for (int i = 0; i < nums.length; i++) { + prefixSum += nums[i]; + int mod = prefixSum % k; + // 如果这个余数之前出现过,则当前下标和之前下标之差至少大于1 + if (modMap.containsKey(mod)) { + if (i - modMap.get(mod) > 1) { + return true; + } + } else { + // 记录第一次出现该余数的下标 + modMap.put(mod, i); + } + } + return false; + } +} diff --git a/src/main/java/substring/MaxSlidingWindow.java b/src/main/java/substring/MaxSlidingWindow.java new file mode 100644 index 0000000..6ce645f --- /dev/null +++ b/src/main/java/substring/MaxSlidingWindow.java @@ -0,0 +1,89 @@ +package substring; + +import java.util.*; + +/** + * 题目:239. 滑动窗口最大值 (maxSlidingWindow) + * 描述:给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 + * 返回 滑动窗口中的最大值 。 + * + * 链接:https://leetcode.cn/problems/sliding-window-maximum/ + * + 示例 1: + + 输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 + 输出:[3,3,5,5,6,7] + 解释: + 滑动窗口的位置 最大值 + --------------- ----- + [1 3 -1] -3 5 3 6 7 3 + 1 [3 -1 -3] 5 3 6 7 3 + 1 3 [-1 -3 5] 3 6 7 5 + 1 3 -1 [-3 5 3] 6 7 5 + 1 3 -1 -3 [5 3 6] 7 6 + 1 3 -1 -3 5 [3 6 7] 7 + + 示例 2: + 输入:nums = [1], k = 1 + 输出:[1] + */ +//普通方法超时 需重做 +public class MaxSlidingWindow { + //优先队列 + public int[] maxSlidingWindow1(int[] nums, int k) { + int n = nums.length; + PriorityQueue pq = new PriorityQueue(new Comparator() { + public int compare(int[] pair1, int[] pair2) { + return pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[1]; + } + }); + for (int i = 0; i < k; ++i) { + pq.offer(new int[]{nums[i], i}); + } + int[] ans = new int[n - k + 1]; + ans[0] = pq.peek()[0]; + for (int i = k; i < n; ++i) { + pq.offer(new int[]{nums[i], i}); + while (pq.peek()[1] <= i - k) { //如果堆顶元素不在滑动窗口内部,就移除 ,非堆顶元素不管 + pq.poll(); + } + ans[i - k + 1] = pq.peek()[0]; + } + return ans; + } + //单调队列 + + /** + * 维护一个单调队列。 + 在这个滑动窗口最大值的算法中,双端队列的两端各自承担不同的职责: + 队头(Deque Front): + 队头始终保存当前窗口内最大元素的索引。由于我们维护队列中元素对应的数值是单调递减的,所以队头的元素必定是最大的。当窗口滑动时,如果队头的索引超出窗口范围,会将其移除,以保证队头始终代表当前窗口的最大值。 + + 队尾(Deque Rear): + 队尾用于存放候选的元素索引,它们按照数值从大到小的顺序排列。在加入新元素前,会从队尾移除所有比新元素小的元素索引,因为这些较小的元素在未来的窗口中不可能成为最大值。这样既保证了队列的单调递减性质,也为未来的窗口维护了正确的候选顺序。 + */ + public int[] maxSlidingWindow(int[] nums, int k) { + int n = nums.length; + Deque deque = new LinkedList<>(); + for (int i = 0; i < k; ++i) { + while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) { + deque.pollLast(); + } + deque.offerLast(i); + } + + int[] ans = new int[n - k + 1]; + ans[0] = nums[deque.peekFirst()]; + for (int i = k; i < n; ++i) { + while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) { //队尾元素本来就比队头小,如果新元素比队尾还大,那就没有保留的价值了 + deque.pollLast(); + } + deque.offerLast(i); + while (deque.peekFirst() <= i - k) { + deque.pollFirst(); + } + ans[i - k + 1] = nums[deque.peekFirst()]; + } + return ans; + } +} diff --git a/src/main/java/substring/SubarraySum.java b/src/main/java/substring/SubarraySum.java new file mode 100644 index 0000000..aeef557 --- /dev/null +++ b/src/main/java/substring/SubarraySum.java @@ -0,0 +1,61 @@ +package substring; + +import java.util.HashMap; + +/** + * 题目:560. 和为 K 的子数组 (subarraySum) + * 描述:给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的子数组的个数 。 + * 子数组是数组中元素的连续非空序列。 + * 链接:https://leetcode.cn/problems/subarray-sum-equals-k/ + * + 示例 1: + 输入:nums = [1,1,1], k = 2 + 输出:2 + + 示例 2: + 输入:nums = [1,2,3], k = 3 + 输出:2 + */ +//只会暴力解 +public class SubarraySum { + //枚举 + public int subarraySum(int[] nums, int k) { + int count = 0; + int len = nums.length; + for (int left = 0; left < len; left++) { + int sum = 0; + // 区间里可能会有一些互相抵销的元素 + for (int right = left; right < len; right++) { + sum += nums[right]; + if (sum == k) { + count++; + } + } + } + return count; + } + /**前缀和 + * pre[i]代表 [0,i]内所有元素的和,pre[j]代表 [0,j]内所有元素之和。那么子串[i,j]之和为a[j]-a[i-1] + */ + public int subarraySum1(int[] nums, int k) { + int count = 0; // 用于累计满足条件的子数组个数 + int prefixSum = 0; // 当前前缀和 + // 哈希表,用于存储前缀和出现的次数,初始化时前缀和为 0 出现 1 次 + HashMap map = new HashMap<>(); + map.put(0, 1); + + // 遍历数组 + for (int num : nums) { + prefixSum += num; + // 如果存在前缀和为 prefixSum - k 的情况, + // 则从那个位置到当前下标的子数组和为 k + if (map.containsKey(prefixSum - k)) { + count += map.get(prefixSum - k); + } + // 更新哈希表,将当前的前缀和计数加 1 + map.put(prefixSum, map.getOrDefault(prefixSum, 0) + 1); + } + + return count; + } +} diff --git a/src/test/java/array/MaxSubArrayTest.java b/src/test/java/array/MaxSubArrayTest.java new file mode 100644 index 0000000..0055491 --- /dev/null +++ b/src/test/java/array/MaxSubArrayTest.java @@ -0,0 +1,16 @@ +package array; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class MaxSubArrayTest { + + @Test + public void maxSubArray() { + MaxSubArray solution = new MaxSubArray(); + int[] nums={-2,1,-3,4,-1,2,1,-5,4}; + int res=solution.maxSubArray(nums); + System.out.println(res); + } +} \ No newline at end of file diff --git a/src/test/java/array/MergeTest.java b/src/test/java/array/MergeTest.java new file mode 100644 index 0000000..cd768bf --- /dev/null +++ b/src/test/java/array/MergeTest.java @@ -0,0 +1,16 @@ +package array; + +import org.junit.Test; + +import java.util.Arrays; + + +public class MergeTest { + @Test + public void testmerge(){ + int[][] intervals = {{1,3},{2,6},{8,10},{15,18}}; + Merge solution = new Merge(); + int[][] res =solution.merge(intervals); + System.out.println(Arrays.deepToString(res)); + } +} \ No newline at end of file diff --git a/src/test/java/array/RotateArrayTest.java b/src/test/java/array/RotateArrayTest.java new file mode 100644 index 0000000..f4d3d0e --- /dev/null +++ b/src/test/java/array/RotateArrayTest.java @@ -0,0 +1,19 @@ +package array; + +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.*; + +public class RotateArrayTest { + + @Test + public void rotateArray() { + int[]nums = {1,2,3,4,5,6,7}; + int k = 2; + RotateArray solution = new RotateArray(); + solution.rotateArray(nums,k); + System.out.println(Arrays.toString(nums)); + } +} \ No newline at end of file diff --git a/src/test/java/substring/CheckSubarraySumTest.java b/src/test/java/substring/CheckSubarraySumTest.java new file mode 100644 index 0000000..1472a15 --- /dev/null +++ b/src/test/java/substring/CheckSubarraySumTest.java @@ -0,0 +1,17 @@ +package substring; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class CheckSubarraySumTest { + + @Test + public void checkSubarraySum() { + int[] nums={5,0,0,0}; + int k=3; + CheckSubarraySum solution = new CheckSubarraySum(); + boolean res=solution.checkSubarraySum(nums,k); + System.out.println(res); + } +} \ No newline at end of file diff --git a/src/test/java/substring/MaxSlidingWindowTest.java b/src/test/java/substring/MaxSlidingWindowTest.java new file mode 100644 index 0000000..daca9ed --- /dev/null +++ b/src/test/java/substring/MaxSlidingWindowTest.java @@ -0,0 +1,20 @@ +package substring; + +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.*; + +public class MaxSlidingWindowTest { + + @Test + public void maxSlidingWindow() { + MaxSlidingWindow solution = new MaxSlidingWindow(); + int[] num={1,3,-1,-3,5,3,6,7}; + int k=3; + int[] res=new int[num.length-k+1]; + res=solution.maxSlidingWindow(num,3); + System.out.println(Arrays.toString(res)); + } +} \ No newline at end of file diff --git a/src/test/java/substring/SubarraySumTest.java b/src/test/java/substring/SubarraySumTest.java new file mode 100644 index 0000000..9150e12 --- /dev/null +++ b/src/test/java/substring/SubarraySumTest.java @@ -0,0 +1,26 @@ +package substring; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class SubarraySumTest { + + @Test + public void subarraySum() { + int[] nums={1,1,1}; + int k=2; + SubarraySum solution = new SubarraySum(); + int cnt=solution.subarraySum(nums,k); + System.out.println(cnt); + } + + @Test + public void subarraySum1() { + int[] nums={1,1,1}; + int k=2; + SubarraySum solution = new SubarraySum(); + int cnt=solution.subarraySum1(nums,k); + System.out.println(cnt); + } +} \ No newline at end of file