今天除了哈希表还有两道双指针的题,383题和昨天做的一道题很像,其他的看了都没什么好的思路。感叹一下暴力解决时间复杂度越来越高了,还是得积累算法的。
454.四数相加II
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
这道题用哈希表解决的关键就是Map是如何存储键值对的。把问题优化成两两一组求解,因为这道题只是要求有效解的个数,没要求具体下标,我们只需要用Map来存储nums1和nums2中和的值和这个和出现的个数,用二层嵌套的for循环遍历两个数组,每次如果发现了一个新值就更新Map,否则增加该和出现的次数。
代码如下:
for(int i : nums1){
for(int j : nums2){
int sum = i + j;
sum12.put(sum, sum12.getOrDefault(sum, 0) + 1);
}
}
对于nums3和nums4,也同样的使用二层for嵌套,寻找HashMap中有没有已经存在的3,4数组中的数的和的相反数。存在几个,对于这个和,就有几个解。
for(int i : nums3){
for(int j : nums4){
int sum = i + j;
if(sum12.containsKey(0 - sum)){
count += sum12.get(0 - sum);
}
}
}
这道题里用到了一个HashMap的轮子函数getOrDefault,它的作用是获取指定 key 对应对 value,如果找不到 key ,则返回设置的默认值。这样的话,就可以很容易的更新key所对应的sum出现的次数,
383. 赎金信
题目链接:https://leetcode.cn/problems/ransom-note/description/
这道题和昨天的242题很像,我的做法也基本一样,用数组来充当哈希表,先遍历magazine来获取每个字母出现几次,然后遍历randomNote,出现一个字符就减去一次,如果某个字符出现次数小于0了,就证明不符合题意,直接返回了。
15. 三数之和
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
18. 四数之和
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
这两道题基本上是一样的,就是四数之和要多一重for循环,别的基本就是照搬,就放在一起说。
可以看出这两个题如果直接暴力的话,时间复杂度很高,采取双指针的方式来做的话就可以降低一个指数级别。
【其实感觉也有点像滑动窗口】
具体就是先排序,这样的话就会有一定的规律可循。三数之和用for循环固定第一个数字,四数之和用二重for循环固定前两个数字,然后用双指针划定left和right,如果几个数的和小了,那么就需要右移left指针,从而使nums[left]变大(记住数组已经是有序的了),同样如果几个数的和大了,就左移right指针。当移动到left比right大了,就证明这一组已经遍历完了,没有符合要求的,可以进行下一组。
上面说的是基本思想。实际操作的时候要注意,几个数的和可能会超过int限制,要进行一下强制转换换成long类型。
然后要注意一点就是要去重,不是指题目里的下标不能相等,而是对于返回的那个二维数组,里面不能有重复的元素。比如说,nums[]里面可能有一些相同的元素,这就可能导致满足结果的几个数值相同,不满足条件。其实这是集合的一种性质,感觉可以用Set接口来进行处理。不过也有单独的判断方式,就是每次左移和右移后,判断一下新指的和旧指的是否相同,如果相同的话,就要跳过这个新指的,因为不跳过的话必然会导致答案重复。
在满足了以上的条件之后其实就可以过了,但还应该进行一些必要的剪枝。比如如果这一组数最小的都比target要大,鉴于我们是从左往右处理,和就必然比target大了,后面的数肯定只会更大,那么这个时候就可以返回了。
语法方面:
1. 二维数组ArrayList怎么创建:List<List<Integer>> result = new ArrayList<List<Integer>>();
2. 上面提到的需要强制转换,涉及加和乘操作的时候需要多注意;
3. 把几个数加到二维数组里,用到Arrays里面的函数:result.add(Arrays.asList(nums[i], nums[left], nums[right]));