题目详细:LeetCode.454
四数相加的解题思路很简单,其解题过程可以看作是先计算两个小的数组的两数之和,再整体计算一个大的两数之和的过程:
Java解法(哈希表)
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int n = nums1.length, ans = 0;
Map<Integer,Integer> map = new HashMap<>();
for(int i=0; i < n; i++){
for(int j=0; j < n; j++){
int sum = nums1[i] + nums2[j];
map.put(sum, map.getOrDefault(sum, 0) + 1);
}
}
for(int k=0; k < n; k++){
for(int l=0; l < n; l++){
int sum = 0 - (nums3[k] + nums4[l]);
ans += map.getOrDefault(sum, 0);
}
}
return ans;
}
}
题目详细:LeetCode.383
这道题和字母异位词的解题思路差不多,可以通过数组或者HashMap来解决,两者的解题思路是相同的:
Java解法(数组):
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] set = new int[26];
for(char c: magazine.toCharArray()){
set[c - 'a']++;
}
for(char c: ransomNote.toCharArray()){
int f = --set[c - 'a'];
if(f < 0){
return false;
}
}
for(int n: set){
if(n < 0){
return false;
}
}
return true;
}
}
Java解法(哈希表):
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
Map<Character, Integer> map = new HashMap<>();
for(char m: magazine.toCharArray()){
map.put(m, map.getOrDefault(m, 0) + 1);
}
for(char r: ransomNote.toCharArray()){
int t = map.getOrDefault(r, 0);
if(t <= 0){
return false;
}
map.put(r, t-1);
}
return true;
}
}
题目详细:LeetCode.15
这道题我一开始的思路比较简单,就是先将数组排序之后,将计算三数之和的过程看作是计算两次两数之和的过程,利用HashSet记录数字a和数字b的和,再看有没有数字c可以满足三数之和为0的要求,如果满足则作为一个三元组结果。
但我想的还是太简单了,这道题的难点不在于计算数值之和,而是在于去重,而且是要对每一个出现过的数值都进行去重操作,否则会出现重复的三元组。
在看完题解之后,发现双指针法比使用HashSet来解决问题会更加容易理解且简便:三数之和—题解
Java解法(双指针法):
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<>();
for(int i = 0; i < nums.length; i++){
// 排序之后,如果第i个元素已经大于零,那么其后续的数值都不可能凑成三数之和为0三元组
if (nums[i] > 0) {
break;
}
// 去重
if(i > 0 && nums[i] == nums[i-1]){
continue;
}
// 双指针法
int l = i+1, r = nums.length-1;
while(l < r){
int sum = nums[i] + nums[l] + nums[r];
if(sum > 0){
r--;
}else if(sum < 0){
l++;
}else{
ans.add(Arrays.asList(nums[i], nums[l], nums[r]));
r--;
l++;
// 去重
while(l < r && nums[r] == nums[r+1]) r--;
while(l < r && nums[l] == nums[l-1]) l++;
}
}
}
return ans;
}
}
题目详细:LeetCode.18
作为练习题,这道题对我来说太难了,可以学,但是莫必要,日后再见
哈希法是典型的利用空间换时间的方法,当需要判断某个数据是否记录过,或者进行去重操作时,基本都会优先到哈希法。
在做题的过程中,我发现哈希法是一个学起来简单,但是运用起来也简单,但是要用好就很难的方法,特别是在做今天《三数之和》和《四数之和》两道题目的过程中,真的就是给了我一种“梦破碎了”的感觉。
在运用Java提供给我们的哈希表容器后,我发现其底层的实现更加有趣,它是底层是用什么进行存储的,存储的结构是什么样的,如何对数据进行哈希的,如何避免哈希碰撞的等问题也值得我们去学习和探究。
今日作结诗,同时也是我对哈希法的运用由浅至深之后的感触:
坐井观天只有一孔之见,登山远望方知天外有天。