5.29 字符串、哈希
This commit is contained in:
parent
6dc7b98fe0
commit
60e38e3d55
70
src/main/java/hash/FourSum.java
Normal file
70
src/main/java/hash/FourSum.java
Normal file
@ -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<List<Integer>> fourSum(int[] nums, int target) {
|
||||
List<List<Integer>> 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;
|
||||
}
|
||||
|
||||
}
|
65
src/main/java/hash/FourSumCount.java
Normal file
65
src/main/java/hash/FourSumCount.java
Normal file
@ -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<Integer, Integer> 记录 “和 → 出现次数”。
|
||||
* 再枚举 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<Integer, Integer> 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;
|
||||
}
|
||||
}
|
33
src/main/java/hash/Intersection.java
Normal file
33
src/main/java/hash/Intersection.java
Normal file
@ -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<Integer> set1 = new HashSet<>();
|
||||
for (int n : nums1) set1.add(n);
|
||||
|
||||
// 用第二个集合保存交集,天然保证唯一
|
||||
HashSet<Integer> 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<Integer> → int[]
|
||||
return arr;
|
||||
}
|
||||
}
|
30
src/main/java/string/RepeatedSubstringPattern.java
Normal file
30
src/main/java/string/RepeatedSubstringPattern.java
Normal file
@ -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;
|
||||
}
|
||||
}
|
42
src/main/java/string/ReverseStr.java
Normal file
42
src/main/java/string/ReverseStr.java
Normal file
@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
26
src/main/java/string/ReverseString.java
Normal file
26
src/main/java/string/ReverseString.java
Normal file
@ -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--;
|
||||
}
|
||||
}
|
||||
}
|
19
src/test/java/hash/FourSumTest.java
Normal file
19
src/test/java/hash/FourSumTest.java
Normal file
@ -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<List<Integer>>RES=fourSum.fourSum(a,target);
|
||||
System.out.println(RES.toString());
|
||||
}
|
||||
}
|
15
src/test/java/string/RepeatedSubstringPatternTest.java
Normal file
15
src/test/java/string/RepeatedSubstringPatternTest.java
Normal file
@ -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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user