趁热打铁,今天接着再学习哈希表。
开始做题!
注:题目前的标号都对应着力扣上的题目。
454.四数相加2(中等)
给你四个整数数组 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
思考:这道题确实挺麻烦的。。关于这种需要一次性用到多个数据的的,就该想到map了。我自己做的话还是没能做出来,这里又借鉴了卡尔的代码。
注意:本题要求的是个数,而不是每个数组的下标。
本题中,首先应该明确思路。设每个数组出的数为abcd,最后只要求a+b+c+d=0有几种就行了。但四个数我们很难判断,所以可以将其分解成a+b,c+d两个数。这样的话,假设a+b等于某个数一共出现了sum次,0-(c+d)中如果也出现了这个数,那么只对于这一个数,a+b+c+d=0有sum种选择。
那该如何界定map中的key与value呢?我们可以设a+b的和为key,其出现的次数为value.
代码实现:
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int res = 0;
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
//统计两个数组中的元素之和,同时统计出现的次数,放入map
for (int i : nums1) {
for (int j : nums2) {
int sum = i + j;
map.put(sum, map.getOrDefault(sum, 0) + 1);
}
}
//统计剩余的两个元素的和,在map中找是否存在相加为0的情况,同时记录次数
for (int i : nums3) {
for (int j : nums4) {
res += map.getOrDefault(0 - i - j, 0);
}
}
return res;
}
}
总结:
解决本题首先应该思路清晰,既然四个数不好找,我们可以两个两个的找啊。
其次,Map.getOrDefault(Object key, V defaultValue)方法的作用是:当Map集合中有这个key时,就使用这个key值;如果没有就使用默认值defaultValue。
本题思路跟Day6的字母异位词有着异曲同工之妙。
383.赎金信(简单)
给你两个字符串:ransomNote
和 magazine
,判断 ransomNote
能不能由 magazine
里面的字符构成。
如果可以,返回 true
;否则返回 false
。
magazine
中的每个字符只能在 ransomNote
中使用一次。
示例 1:
输入:ransomNote = "a", magazine = "b" 输出:false
示例 2:
输入:ransomNote = "aa", magazine = "aab" 输出:true
思路:不考虑顺序的话,我们可以计算大数组中字母出现次数,之后减去小数组中字母出现的次数。
那么false的条件就是次数出现负数,这就代表大数组中某字母的个数小于小数组某字母个数,那他就一定不包含小数组,
true的条件当然就是大数组中某字母的个数>=小数组某字母个数啦!
代码实现:
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int []z=new int[26];
for( char i:magazine.toCharArray()){
z[i-'a']++;
}
for(char i:ransomNote.toCharArray()){
z[i-'a']--;
}
for (int i = 0; i < z.length; i++) {
if(z[i]<0)
return false;
}
return true;
}
}
总结:关于查询字母的问题,可以直接用数组法,比较清晰。
15.三数之和
给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请
你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]]
思路:因为需要去重,所以这道题不建议用哈希法做。大多标准答案都是用的双指针法。这里放一个链接,看里面的视频解析就能了解。力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
所以这道题我还是没能自己做出来www。。三数之和,下次再战!
代码实现:
class Solution {
public static List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new ArrayList();
int len = nums.length;
if(nums == null || len < 3) return ans;
Arrays.sort(nums); // 排序
for (int i = 0; i < len ; i++) {
if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
int L = i+1;
int R = len-1;
while(L < R){
int sum = nums[i] + nums[L] + nums[R];
if(sum == 0){
ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
while (L<R && nums[L] == nums[L+1]) L++; // 去重
while (L<R && nums[R] == nums[R-1]) R--; // 去重
L++;
R--;
}
else if (sum < 0) L++;
else if (sum > 0) R--;
}
}
return ans;
}
}
作者:画手大鹏
链接:https://leetcode.cn/problems/3sum/solutions/12307/hua-jie-suan-fa-15-san-shu-zhi-he-by-guanpengchn/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。