diff --git a/src/main/java/hash/FourSum.java b/src/main/java/hash/FourSum.java new file mode 100644 index 0000000..593cfef --- /dev/null +++ b/src/main/java/hash/FourSum.java @@ -0,0 +1,70 @@ +package hash; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 题目: 18. 四数之和 ( fourSum) + * 描述:给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复): + * + * 0 <= a, b, c, d < n + * a、b、c 和 d 互不相同 + * nums[a] + nums[b] + nums[c] + nums[d] == target + * 你可以按 任意顺序 返回答案 。 + * + 示例 1: + 输入:nums = [1,0,-1,0,-2,2], target = 0 + 输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]] + + * 链接:https://leetcode.cn/problems/4sum/ + */ +public class FourSum { + public List> fourSum(int[] nums, int target) { + List> res = new ArrayList<>(); + int n = nums.length; + if (n < 4) return res; + + Arrays.sort(nums); + + for (int i = 0; i < n - 3; i++) { + if (i > 0 && nums[i] == nums[i - 1]) continue; // 去重 1 + + // 剪枝 1:最小可能值都比 target 大,直接结束 + long min1 = (long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3]; + if (min1 > target) break; + // 剪枝 2:当前 nums[i] + 3 个最大的值都小于 target,提前进入下一轮 + long max1 = (long) nums[i] + nums[n - 1] + nums[n - 2] + nums[n - 3]; + if (max1 < target) continue; + + for (int j = i + 1; j < n - 2; j++) { + if (j > i + 1 && nums[j] == nums[j - 1]) continue; // 去重 2 + + // 同理再剪枝 + long min2 = (long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2]; + if (min2 > target) break; + long max2 = (long) nums[i] + nums[j] + nums[n - 1] + nums[n - 2]; + if (max2 < target) continue; + + int left = j + 1, right = n - 1; + while (left < right) { + long sum = (long) nums[i] + nums[j] + nums[left] + nums[right]; + if (sum == target) { + res.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right])); + // **指针移动后再去重** —— 结构直观 + while (left < right && nums[left] == nums[left + 1]) left++; + while (left < right && nums[right] == nums[right - 1]) right--; + left++; + right--; + } else if (sum < target) { + left++; + } else { + right--; + } + } + } + } + return res; + } + +} diff --git a/src/main/java/hash/FourSumCount.java b/src/main/java/hash/FourSumCount.java new file mode 100644 index 0000000..4e792e3 --- /dev/null +++ b/src/main/java/hash/FourSumCount.java @@ -0,0 +1,65 @@ +package hash; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * 题目: 454. 四数相加 II ( fourSumCount) + * 描述:给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足: + * + * 0 <= i, j, k, l < n + * nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0 + * + 示例 1: + 输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2] + 输出:2 + 解释: + 两个元组如下: + 1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0 + 2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0 + + * 链接:https://leetcode.cn/problems/4sum-ii/ + */ +//超时 +public class FourSumCount { + /** + * 思路:把四数拆成两对 (A+B) 和 (C+D) + * 先枚举 A 与 B 的所有和 + * 用 HashMap 记录 “和 → 出现次数”。 + * 再枚举 C 与 D 的所有和 + * 对于每个和 s = c + d,要凑成 0 就需要 -(c+d)。 + * 看看 map 里有没有 -(c+d),若有就把出现次数累加到结果里。 + * 时间复杂度 + * 两个 n² 循环 ⇒ 总 O(n²)。 + * 空间复杂度 + * 哈希表最多 n² 个键 ⇒ O(n²)。 + * @param nums1 + * @param nums2 + * @param nums3 + * @param nums4 + * @return + */ + public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) { + + // 1) 统计 A+B 的所有组合和及其出现次数 + Map abCount = new HashMap<>(); + for (int a : nums1) { + for (int b : nums2) { + int sum = a + b; + abCount.put(sum, abCount.getOrDefault(sum, 0) + 1); + } + } + + // 2) 枚举 C+D,看 -(C+D) 是否出现在 map 里 + int ans = 0; + for (int c : nums3) { + for (int d : nums4) { + int sum = c + d; + // 需要 -(c+d) 才能凑成 0 + ans += abCount.getOrDefault(-sum, 0); + } + } + return ans; + } +} diff --git a/src/main/java/hash/Intersection.java b/src/main/java/hash/Intersection.java new file mode 100644 index 0000000..91276dd --- /dev/null +++ b/src/main/java/hash/Intersection.java @@ -0,0 +1,33 @@ +package hash; +import java.util.HashSet; + +/** + * 题目: 349. 两个数组的交集 ( Intersection) + * 描述:给定两个数组 nums1 和 nums2 ,返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 + * + 示例 1: + 输入:nums1 = [1,2,2,1], nums2 = [2,2] + 输出:[2] + + * 链接:https://leetcode.cn/problems/intersection-of-two-arrays/ + */ +public class Intersection { + public int[] intersection(int[] nums1, int[] nums2) { + // 把 nums1 转成集合 + HashSet set1 = new HashSet<>(); + for (int n : nums1) set1.add(n); + + // 用第二个集合保存交集,天然保证唯一 + HashSet resSet = new HashSet<>(); + for (int n : nums2) { + if (set1.contains(n)) resSet.add(n); + } + int[] arr = new int[resSet.size()]; + int j = 0; + for(int i : resSet){ + arr[j++] = i; + } + // Set → int[] + return arr; + } +} diff --git a/src/main/java/string/RepeatedSubstringPattern.java b/src/main/java/string/RepeatedSubstringPattern.java new file mode 100644 index 0000000..e7c95c9 --- /dev/null +++ b/src/main/java/string/RepeatedSubstringPattern.java @@ -0,0 +1,30 @@ +package string; +/** + * 题目: 459. 重复的子字符串 (repeatedSubstringPattern) + * 描述:给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。 + * + * 示例 1: + 输入: s = "abab" + 输出: true + 解释: 可由子串 "ab" 重复两次构成。 + + * 链接:https://leetcode.cn/problems/reverse-string-ii/ + */ +public class RepeatedSubstringPattern { + public boolean repeatedSubstringPattern(String s) { + int len = s.length(); + for (int j = 1; j <= len / 2; j++) { + if (len % j != 0) continue; // ★ 只有能整除时才有可能 + String tp = s.substring(0, j); + boolean flag = true; + for (int i = j; i < len; i += j) { + if (!s.substring(i, i + j).equals(tp)) { + flag = false; + break; + } + } + if (flag) return true; + } + return false; + } +} diff --git a/src/main/java/string/ReverseStr.java b/src/main/java/string/ReverseStr.java new file mode 100644 index 0000000..2816668 --- /dev/null +++ b/src/main/java/string/ReverseStr.java @@ -0,0 +1,42 @@ +package string; +/** + * 题目: 541. 反转字符串 II (reverseStr) + * 描述:给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。 + * + * 如果剩余字符少于 k 个,则将剩余字符全部反转。 + * 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。 + * + * 示例 1: + 输入:s = "abcdefg", k = 2 + 输出:"bacdfeg" + + * 链接:https://leetcode.cn/problems/reverse-string-ii/ + */ +public class ReverseStr { + public String reverseStr(String s, int k) { + if (s == null || s.length() <= 1 || k <= 1) return s; + + char[] ch = s.toCharArray(); + int n = ch.length; + + // i 每次跳过 2k,指向每段的起点 + for (int i = 0; i < n; i += 2 * k) { + // 计算本次需要翻转的区间 [i, right] + int left = i; + int right = Math.min(i + k - 1, n - 1); + reverse(ch, left, right); + } + return new String(ch); + } + + /** 原地翻转 ch[l..r] */ + private void reverse(char[] ch, int l, int r) { + while (l < r) { + char tmp = ch[l]; + ch[l] = ch[r]; + ch[r] = tmp; + l++; + r--; + } + } +} diff --git a/src/main/java/string/ReverseString.java b/src/main/java/string/ReverseString.java new file mode 100644 index 0000000..5eb656d --- /dev/null +++ b/src/main/java/string/ReverseString.java @@ -0,0 +1,26 @@ +package string; +/** + * 题目: 344. 反转字符串 (reverseString) + * 描述:编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 + * 不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。 + * + * + * 示例 1: + 输入:s = ["h","e","l","l","o"] + 输出:["o","l","l","e","h"] + + * 链接:https://leetcode.cn/problems/reverse-string/ + */ +public class ReverseString { + public void reverseString(char[] s) { + int l = 0; + int r = s.length - 1; + while(l < r){ + char temp = s[l]; + s[l] = s[r]; + s[r] = temp; + l++; + r--; + } + } +} diff --git a/src/test/java/hash/FourSumTest.java b/src/test/java/hash/FourSumTest.java new file mode 100644 index 0000000..278822e --- /dev/null +++ b/src/test/java/hash/FourSumTest.java @@ -0,0 +1,19 @@ +package hash; + +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.*; + +public class FourSumTest { + + @Test + public void fourSum() { + FourSum fourSum = new FourSum(); + int[]a={2,2,2,2,2}; + int target=8; + List>RES=fourSum.fourSum(a,target); + System.out.println(RES.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/string/RepeatedSubstringPatternTest.java b/src/test/java/string/RepeatedSubstringPatternTest.java new file mode 100644 index 0000000..8838993 --- /dev/null +++ b/src/test/java/string/RepeatedSubstringPatternTest.java @@ -0,0 +1,15 @@ +package string; + +import org.junit.Test; + +import static org.junit.Assert.*; + +public class RepeatedSubstringPatternTest { + + @Test + public void repeatedSubstringPattern() { + RepeatedSubstringPattern solution = new RepeatedSubstringPattern(); + String s="abac"; + solution.repeatedSubstringPattern(s); + } +} \ No newline at end of file