LeetCode 454 四数相加
这题因为每个数组中的元素的个数都是相同的,所以我们可以尝试通过hashmap 的方式来解题。
本题解题步骤:
- 首先定义 一个unordered_map,key放a和b两数之和,value 放a和b两数之和出现的次数。
- 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。
- 定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
- 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
- 最后返回统计值 count 就可以了
class Solution {
public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
int res=0;
HashMap<Integer,Integer> map = new HashMap<>();
for(int i:nums1){
for(int j:nums2){
int sum = i+j;
map.put(sum,map.getOrDefault(sum,0)+1);
}
}
for(int m:nums3){
for(int n:nums4){
res+=map.getOrDefault(0-m-n,0);
}
}
return res;
}
}
LeetCode 15 三数之和
三数之和问题我们一般通过双指针的方式来解决。我们设置三个指针:i,left,right,这三个指针分别对应a,b,c三个值。我们可以通过i来遍历整个数组,left和right分别为i+1和n-1。我们需要对整个数组先进行一个排序,这样对于每一个i的值,我们可以根据abc和的不同来更改left和right的大小。
如果a+b+c>0,那么我们减小right;
如果a+b+c<0,那么我们增加left;
如果等于0,增加到结果中去。
这题主要复杂的地方在于去重,因为题目要求结果不能重复:即便一个数组为{-1,-1,-1,-1,-1,2,2}我们的结果也只有一个{-1,-1,2}虽然我们可以取到不同的-1;但是对于结果数组来说它们完全相同,所以我们要对这种情况进行区分。
对于a的去重:
在我们对i进行遍历时我们发现,如果i此时的结果和i的前一位相同,那么对于a的值来说不会有任何变化,且对于我们之后left和right的范围为前一种情况的子集,举个例子:
{-1,-1,0,1,2,3,4}
当a为第一个-1时,left和right的取值区间为{-1,0,1,2,3,4}
当a为第二个-1时,left和right的取值区间为{0,1,2,3,4}
第二种情况下所有有可能满足条件的解都会包含在第一种情况之中,所以我们可以直接惊醒跳过
对于b和c的去重:
在i固定的情况下,当我们已经确定了一个结果,比如说{-1,-1,-1,-1,2,2}这种情况下:
如果i为第一个-1,left为第二个-1,right为最后一个2,这种情况满足a+b+c=0;但是我们发现,left++之后,a+b+c仍然满足题意但是结果重复了即nums[left] == nums[left+1];这种情况下我们对于b进行去重;同理对于right来说如果nums[right]==nums[right--],我们也需要进行一个去重操作
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
int n = nums.length;
for(int i=0;i<n-2;i++){
if (nums[i] > 0) {
return res;
}
//对a去重
if(i>0&&nums[i]==nums[i-1]){
continue;
}
int left = i+1;
int right = n-1;
while(right>left){
if(nums[i]+nums[left]+nums[right]>0){
right--;
}else if(nums[i]+nums[left]+nums[right]<0){
left++;
}else{
List<Integer> numbers = new ArrayList<>();
numbers.add(nums[i]);
numbers.add(nums[left]);
numbers.add(nums[right]);
res.add(numbers);
while(right>left&&nums[right]==nums[right-1]) right--;
while(right>left&&nums[left]==nums[left+1])left++;
left++;
right--;
}
}
}
return res;
}
}
LeetCode 18 四数之和
基本思路和三数之和相同,但是因为有四个数,所以我们需要在进行一次for循环。
并且对于i和j来说要分别进行去重
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
int n = nums.length;
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<n;i++){
if(nums[i]>0&&nums[i]>target){
return res;
}
if(i>0&&nums[i]==nums[i-1]){
continue;
}
for(int j=i+1;j<n;j++){
if(j>i+1&&nums[j]==nums[j-1]){
continue;
}
int left = j+1;
int right = n-1;
while(right>left){
long sum = (long)nums[i]+nums[j]+nums[left]+nums[right];
if(sum>target){
right--;
}else if(sum<target){
left++;
}else{
res.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
while(right>left&&nums[right]==nums[right-1]) right--;
while(right>left&&nums[left]==nums[left+1]) left++;
left++;
right--;
}
}
}
}
return res;
}
}
总结:
HashMap和Set是我们在日常代码中使用的非常多的两种类型。我们需要考虑在不同的情况应该使用什么样的数据结构。
当我们需要比较两个字符串中所包含的字母是否完全相同时(字符串中只含有小写字母),我们可以通过数组的形式来储存数据。
Set可以用来判断是否存在某个元素,而Map则可以通过<key,value>的形式来对数据进行储存