题目 类型 难度 状态 掌握程度 题目链接 视频链接 日期
242. 有效的字母异位词 哈希 简单 通过 思路错误 题目链接 视频链接 2026-01-10
349. 两个数组的交集 哈希 简单 通过 需要Debug 题目链接 视频链接 2026-01-10
1. 两数之和 哈希 简单 通过 完全掌握 题目链接 视频链接 2026-01-15
15. 三数之和 哈希 中等 通过 思路错误 题目链接 视频链接 2026-01-15
18. 四数之和 哈希 中等 通过 思路错误 题目链接 视频链接 2026-01-16
454. 四数相加II 哈希 中等 通过 思路错误 题目链接 视频链接 2026-01-16
383. 赎金信 哈希 简单 通过 完全掌握 题目链接 视频链接 2026-01-16

1. 两数之和

难度:简单

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值 target 的那两个整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]

解题思路

这道题是经典中的经典,主要有两种思路:

第一种思路:排序 + 双指针

把 nums 排序之后就可以用左右指针来求出和为 target 的两个数。不过因为题目要求返回元素的索引,而排序会破坏元素的原始索引,所以要记录值和原始索引的映射。进一步,如果题目拓展延伸一下,让你求三数之和、四数之和,你依然可以用双指针技巧,写一个函数来解决所有 N 数之和问题。

第二种思路:哈希表辅助判断

对于一个元素 nums[i],你想知道有没有另一个元素 nums[j] 的值为 target - nums[i],这很简单,我们用一个哈希表记录每个元素的值到索引的映射,这样就能快速判断数组中是否有一个值为 target - nums[i] 的元素了。

简单说,数组其实可以理解为一个「索引 -> 值」的哈希表映射,而我们又建立一个「值 -> 索引」的映射即可完成此题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution {
public int[] twoSum(int[] nums, int target) {
// 维护 val -> index 的映射
HashMap<Integer, Integer> valToIndex = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
// 查表,看看是否有能和 nums[i] 凑出 target 的元素
int need = target - nums[i];
if (valToIndex.containsKey(need)) {
return new int[]{valToIndex.get(need), i};
}
// 存入 val -> index 的映射
valToIndex.put(nums[i], i);
}
return null;
}
}

N 数之和

难度:中等

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:答案中不可以包含重复的四元组。

解题思路

对于 N 数之和问题,我们可以使用递归 + 双指针的方法来解决。核心思想是:

  1. 先对数组进行排序
  2. 对于 N 数之和,递归计算 (N-1) 数之和
  3. 当递归到 2 数之和时,使用双指针法
  4. 注意跳过重复元素,避免重复结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 注意:调用这个函数之前一定要先给 nums 排序
// n 填写想求的是几数之和,start 从哪个索引开始计算(一般填 0),target 填想凑出的目标和
List<List<Integer>> nSumTarget(int[] nums, int n, int start, long target) {
int sz = nums.length;
List<List<Integer>> res = new ArrayList<>();
// 至少是 2Sum,且数组大小不应该小于 n
if (n < 2 || sz < n) return res;
// 2Sum 是 base case
if (n == 2) {
// 双指针那一套操作
int lo = start, hi = sz - 1;
while (lo < hi) {
int sum = nums[lo] + nums[hi];
int left = nums[lo], right = nums[hi];
if (sum < target) {
while (lo < hi && nums[lo] == left) lo++;
} else if (sum > target) {
while (lo < hi && nums[hi] == right) hi--;
} else {
res.add(new ArrayList<>(Arrays.asList(left, right)));
while (lo < hi && nums[lo] == left) lo++;
while (lo < hi && nums[hi] == right) hi--;
}
}
} else {
// n > 2 时,递归计算 (n-1)Sum 的结果
for (int i = start; i < sz; i++) {
List<List<Integer>> sub = nSumTarget(nums, n - 1, i + 1, target - nums[i]);
for (List<Integer> arr : sub) {
// (n-1)Sum 加上 nums[i] 就是 nSum
arr.add(nums[i]);
res.add(arr);
}
while (i < sz - 1 && nums[i] == nums[i + 1]) i++;
}
}
return res;
}

454. 四数相加 II

难度:中等

给你四个整数数组 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

示例 2:

输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]
输出:1

解题思路

采用分为两组,HashMap 存一组,另一组和 HashMap 进行比对。

这样的话情况就可以分为三种:

  1. HashMap 存一个数组,如 A。然后计算三个数组之和,如 BCD。时间复杂度为:O(n)+O(n^3),得到 O(n^3)
  2. HashMap 存三个数组之和,如 ABC。然后计算一个数组,如 D。时间复杂度为:O(n^3)+O(n),得到 O(n^3)
  3. HashMap 存两个数组之和,如AB。然后计算两个数组之和,如 CD。时间复杂度为:O(n^2)+O(n^2),得到 O(n^2)

根据第二点我们可以得出要存两个数组算两个数组。

我们以存 AB 两数组之和为例。首先求出 A 和 B 任意两数之和 sumAB,以 sumAB 为 key,sumAB 出现的次数为 value,存入 hashmap 中。然后计算 C 和 D 中任意两数之和的相反数 sumCD,在 hashmap 中查找是否存在 key 为 sumCD。

算法时间复杂度为 O(n^2)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public int fourSumCount(int[] A, int[] B, int[] C, int[] D) {
Map<Integer, Integer> map = new HashMap<>();
int res = 0;
for(int i = 0;i<A.length;i++){
for(int j= 0;j<B.length;j++){
int sumAB = A[i]+B[j];
if(map.containsKey(sumAB)) map.put(sumAB,map.get(sumAB)+1);
else map.put(sumAB,1);
}
}

for(int i = 0;i<C.length;i++){
for(int j = 0;j<D.length;j++){
int sumCD = -(C[i]+D[j]);
if(map.containsKey(sumCD)) res += map.get(sumCD);
}
}
return res;
}
}