LeetCode 查找表专题 5:灵活选择键值:4Sum II
LeetCode 查找表专题 5:灵活选择键值:4Sum II
例1:LeetCode 第 454 题:四数相加 II
传送门:英文网址:454. 4Sum II ,中文网址:454. 四数相加 II 。
给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组
(i, j, k, l)
,使得A[i] + B[j] + C[k] + D[l] = 0
。为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终结果不会超过
。
例如:
输入: A = [ 1, 2] B = [-2,-1] C = [-1, 2] D = [ 0, 2] 输出: 2 解释: 两个元组如下: 1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0 2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
分析:其实思路只要清楚了,是个很简单的问题。把 A、B、C、D 分成两组,在 A、B 之和中找与 C、D 的相反数之和相同的组合数,要使用 HashMap 这个数据结构。考察了组合数,乘法计数原理。代码编写有技巧,一定要会。
Python 代码1:在理解的基础上记住
class Solution:
def fourSumCount(self, A, B, C, D):
"""
:type A: List[int]
:type B: List[int]
:type C: List[int]
:type D: List[int]
:rtype: int
"""
map1 = self.get_map(A, B)
map2 = self.get_map(C, D)
res = 0
for key1 in map1:
if -key1 in map2:
res += map1[key1] * map2[-key1]
return res
def get_map(self, tuple1, tuple2):
map = dict()
for num1 in tuple1:
for num2 in tuple2:
map[num1 + num2] = (map.setdefault(num1 + num2, 0) + 1)
return map
Python 代码2:下面这种写法省下一个 map,不过在计算的时候,就不能用乘法了,只能用加法,就这点区别
class Solution:
def fourSumCount(self, A, B, C, D):
"""
:type A: List[int]
:type B: List[int]
:type C: List[int]
:type D: List[int]
:rtype: int
"""
map = dict()
for num3 in C:
for num4 in D:
map[num3 + num4] = (map.setdefault(num3 + num4, 0) + 1)
res = 0
for num1 in A:
for num2 in B:
s = num1 + num2
if -s in map:
res += map[-s]
return res
Java 代码:同上
/* 分治,把4个list,拆成两两组合,降低complexity
* Time complexity: O(n^2), space complexity: O(n^2) */
class Solution {
public int fourSumCount(int[] A, int[] B, int[] C, int[] D) {
Map<Integer, Integer> hm = new HashMap<>();
for (int i = 0; i < A.length; i++) {
for (int j = 0; j < B.length; j++) {
hm.put(A[i] + B[j], hm.getOrDefault(A[i] + B[j], 0) + 1);
}
}
int res = 0;
for (int i = 0; i < C.length; i++) {
for (int j = 0; j < D.length; j++) {
res += hm.getOrDefault((C[i] + D[j]) * -1, 0);
}
}
return res;
}
}
练习 :例题:LeetCode 第 49 题:字母异位词分组
传送门:英文网址:49. Group Anagrams ,中文网址:49. 字母异位词分组 。
给定一个字符串数组,将字母异位词组合在一起。字母异位词指字母相同,但排列不同的字符串。
示例:
输入: ["eat", "tea", "tan", "ate", "nat", "bat"], 输出: [ ["ate","eat","tea"], ["nat","tan"], ["bat"] ]
说明:
- 所有输入均为小写字母。
- 不考虑答案输出的顺序。
思路1:用 map 就可以完成,key 是 sort 以后的字符。

Python 代码:
class Solution:
def groupAnagrams(self, strs):
"""
:type strs: List[str]
:rtype: List[List[str]]
"""
map = dict()
if len(strs) == 0:
return []
for s in strs:
key = ''.join(sorted(list(s)))
if key not in map:
map[key] = [s]
else:
map[key].append(s)
return list(map.values())
在官方题解下看到的解答,直接拿 tuple 就可以作为哈希表的 key。
Python 代码:
class Solution(object):
def groupAnagrams(self, strs):
ans = collections.defaultdict(list)
for s in strs:
ans[tuple(sorted(s))].append(s)
return ans.values()
下面这个解法本质上没有变,只是 key 不一样了。

注意到英文字母只有 26 个,因此如果不排序的话,直接统计字母频率也是可以的,把字母频率数组变成 tuple 作为哈希表的 key。
Python 代码:
class Solution:
def groupAnagrams(strs):
ans = collections.defaultdict(list)
for s in strs:
count = [0] * 26
for c in s:
count[ord(c) - ord('a')] += 1
ans[tuple(count)].append(s)
return ans.values()
思路2:可以给同构异形体做编码,编码一样的就应该在一组里面。很多时候,hash 表的功能可以用数组代替。下面的两版代码时间复杂度太高,了解一下有这个思路就可以了。
Python 代码:
class Solution:
def groupAnagrams(self, strs):
"""
:type strs: List[str]
:rtype: List[List[str]]
"""
# 26 个质数
primes = [2, 3, 5, 7, 11,
13, 17, 19, 23, 29,
31, 37, 41, 43, 47,
53, 59, 61, 67, 71,
73, 79, 83, 89, 97,
101]
# hash_arr 中存放的是与 res 对应的 hash 值
hash_arr = []
res = []
for s in strs:
hash_val = 1
for alpha in s:
hash_val *= primes[ord(alpha) - ord('a')]
index = 0
while index < len(hash_arr):
if hash_arr[index] == hash_val:
res[index].append(s)
break
index += 1
if index == len(hash_arr):
hash_arr.append(hash_val)
res.append([s])
return res
if __name__ == '__main__':
strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
solution = Solution()
result = solution.groupAnagrams(strs)
print(result)
Python 代码:
class Solution:
def groupAnagrams(self, strs):
"""
:type strs: List[str]
:rtype: List[List[str]]
"""
# 26 个质数
primes = [2, 3, 5, 7, 11,
13, 17, 19, 23, 29,
31, 37, 41, 43, 47,
53, 59, 61, 67, 71,
73, 79, 83, 89, 97,
101]
# hash_arr 中存放的是与 res 对应的 hash 值
hash_arr = []
res = []
for s in strs:
hash_val = 1
for alpha in s:
hash_val *= primes[ord(alpha) - ord('a')]
found = False
index = 0
while index < len(hash_arr):
if hash_arr[index] == hash_val:
res[index].append(s)
found = True
break
index += 1
# 如果没有找到,就加在后面,hash_arr 和 res 是同步的
if not found:
hash_arr.append(hash_val)
res.append([s])
return res
(本节完)