454.四数相加II
思路:
1. 前两个数a+b出现的组合的和与其对应的出现次数存在一个map里,key是a+b的值,value是其对应的出现次数。要点是map.getOrDefault(a+b,0)的使用。
2. 然后遍历c和d,如果0-c-d出现在map里,即map.containsKey(0-c-d),那么说明存在能够让a+b+c+d=0的组合,这个时候原来map里0-c-d对应的value就是能满足的组合数。
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
Map<Integer,Integer> map = new HashMap<>();
int res = 0;
for(int a:nums1){
for(int b:nums2){
map.put(a+b,map.getOrDefault(a+b,0)+1);
}
}
for(int c:nums3){
for(int d:nums4){
res+=map.getOrDefault(0-c-d,0);
}
}
return res;
}
}
383. 赎金信
算是和有效字母异位词的拓展题。
思路:
1. 因为限定在小写字母,所以是有限的,故可以用数组。
2. 先遍历magazine,找出可以使用的字母集合,存储可用的数量。然后遍历信,逐个减少,如果出现<0的说明不可行,返回false,比较简单。
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
int[] magazineSet = new int[26];
for(char ch:magazine.toCharArray()){
magazineSet[ch-'a']++;
}
for(char ch:ransomNote.toCharArray()){
magazineSet[ch-'a']--;
if( magazineSet[ch-'a']<0){
return false;
}
}
return true;
}
}
15. 三数之和
要点:
1.数组要排序! Arrays.sort()
2. 双指针法,一个初始指针从左到右遍历整个数组,然后一个left为i+1从左开始遍历,然后一个right从最右开始遍历,如果和大于0就right--,反之则left++;
3. 因为结果里不能有重复的三元组,所以要有去重操作!对当前元素的去重是i和i-1对应的值如果一样的话,就continue跳过;left和right的去重操作是在找到了一组结果集的基础上,如果下一个left/right和上一个相同,就再跳过,直至不一样为止。最后再++/--表明跳到了下一个不同的元素。
4. 剪枝操作:如果排序后第一个数都大于0了,那直接返回结果集就行了,后续寻找没意义。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> resList = new ArrayList<>();
for(int i =0;i<nums.length;i++){
if(nums[i]>0) return resList;
//i剪枝
if(i>0&&nums[i]==nums[i-1]) continue;
int left = i+1;
int right = nums.length-1;
while(left<right){
if(nums[i]+nums[left]+nums[right]>0) right--;
else if(nums[i]+nums[left]+nums[right]<0) left++;
else{
resList.add(Arrays.asList(nums[i],nums[left],nums[right]));
while(left<right&&nums[right]==nums[right-1]){right--;}
while(left<right&&nums[left]==nums[left+1]){left++;}
right--;
left++;
}
}
}
return resList;
}
}
18. 四数之和
思路:
可以延续三数之和的思路,多嵌套一层循环,i,j=i+1,left=j+1,right=nums.length-1,同样的剪枝和去重操作,注意这里是target不是0,所以在判断的时候条件为如果第一个数大于0且大于target才跳过。
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> list = new ArrayList<>();
for(int i=0;i<nums.length;i++){
//剪枝
if(nums[i]>0&&nums[i]>target) break;
//去重
if(i>0&&nums[i]==nums[i-1]) continue;
for(int j=i+1;j<nums.length;j++){
//剪枝
if(nums[i]+nums[j]>0&&nums[i]+nums[j]>target) break;
//去重
if(j>i+1&&nums[j]==nums[j-1]) continue;
int left=j+1;
int right = nums.length-1;
while(left<right){
if(nums[i]+nums[j]+nums[left]+nums[right]>target) right--;
else if(nums[i]+nums[j]+nums[left]+nums[right]<target) left++;
else{
list.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
//去重
while(left<right&&nums[right]==nums[right-1]) right--;
while(left<right&&nums[left]==nums[left+1]) left++;
right--;
left++;
}
}
}
}
return list;
}
}