代码随想录第十二期集训营-第七天
今天的任务如下:
完成哈希法的剩下题目
454.四数相加II
力扣里有两道四数相加的题,这题比另一题简单,这题是四个独立的数组,而且不用考虑结果集重复的情况。这题思路就是先把A、B数组对应元素相加,存放在Map中,Key为相加和,Value为这个和出现的频率。然后再求出C、D元素对象相加和,然后比较0-sum是否在,如果在就记录Map中对应的Value,最后把Value累加就得到结果,这题比较简单。
383.赎金信
这个和之前的有效字母异位词有点像,只不过异位词这题是两个字符串互相比较,必须完全相同才行。而本题是一个字符串里的字母可以组成另一个字符串就行。这题依然用数组来作为Set,也可以用Map,但是因为小写字母是连续的,用数组好一些。我的思路就是我先遍历赎金信,遇到的字母在数组中元素对应加一,这样就确定每个字母的数量。然后再遍历报纸,判断这个字母是否在赎金信数组中,在的话先判断元素是否大于0,大于的话就减一。最后就看这个数组是否全为0,全为零就对了。我说一下为什么要判断元素是否大于零,假如赎金信里的a有两个,报纸里的a有三个,那我从报纸里找到两个之后就能够满足赎金信里a的数量要求了,所以再找到报纸中的a就不用管了,不需要了。
14.三数之和
这题的难度就提升了不少,因为是在一个数组中,结果集不能重复,所以要去重,但是哈希法去重很麻烦,在代码随想录中有具体讲解,本题采用双指针法。其实一共有三个指针,一个是for循环遍历数组的索引i,一个是指向i后一个元素的指针left,还有一个是指向末尾的right。先对数组进行排序,等下就知道为什么要排序了。每次都求出三个指针对应元素的和,sum = nums[i]+nums[left]+nums[right]。然后判断如果sum>0,说明大了,就要把right左移,变小一点,这就是为什么要排序了。如果sum < 0,说明小了,要把left右移。如果相等,说明找到了。直到sum = 0或者left > right。
如果此时nums[i] > 0,这是就不用再遍历了,肯定找不到了。
然后说一下去重问题,去谁的重,就是这三个指针的重。先去重nums[i],有个细节,是判断nums[i] == nums[i+1]还是判断nums[i] == nums[i-1]呢?
if (nums[i] == nums[i + 1]) { // 去重操作 continue; }
如果写成这样会怎么样?假如有一个数组是{-1,-1,2},按照这么判断,前两个相等了就不要第一个-1了,那这样是不是就把一个结果集给干没了,我们的去重是去除重复的结果集而不是不让一个结果集里有重复的元素。所以还得是判断nums[i] == nums[i-1],相当于我们走过的路就不要再走了。应该这么写:
if (i > 0 && nums[i] == nums[i - 1]) { continue; }
接着就是去left、right的重,这两个去重逻辑是一样的,只需要在sum == 0的情况下才会去重。因为sum不等于0时,假如大于0,要把right--,再假如左边的right和他一样,那又如何,sum还是>0,继续左移,left也同理,所以sum != 0时不用考虑去重。只需要在sum == 0是加去重代码就行。
while (left < right && nums[right] == nums[right - 1]) right--;
class Solution { public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> res = new ArrayList<>(); //创建三个指针 //双指针法,先要对nums排序 Arrays.sort(nums); for(int i = 0;i < nums.length;i++){ if(nums[i] > 0){ return res; } int left = i+1; int right = nums.length - 1; //先对i去重,当前i要和前一个i比较,不跟后一个比较 if(i > 0 && nums[i] == nums[i-1]){ continue; } while(right > left){ int sum = nums[left] + nums[right] + nums[i]; if(sum > 0){ //和大了,right左移,不用考虑重复,即使重复也肯定还是sum大了,继续左移就好 right--; }else if(sum < 0){ left++; }else{ //相等,就可以把这组数放入list集合中 res.add(Arrays.asList(nums[i],nums[left],nums[right])); //要对left和right去重 while(left < right && nums[right] == nums[right-1]){ right--; } while(left < right && nums[left] == nums[left+1]){ left++; } right--; left++; } } } return res; } }
18.四数之和
这题和上一题思路一样,就是求四个数的和,比三数之和多一层for循环,一共相当于四个指针,其他的去重都一样。有一个细节要注意,就是三数之和当nums[i] > 0就return,这里是行不通的,因为这里我们给定的是target,不是确定值,有可能target < 0。要这么判断:nums[i] > target && (nums[i] >=0 || target >= 0)
#2022毕业即失业取暖地##2022毕业生求职现身说法##2022毕业的你对23届的寄语##如何判断面试是否凉了#