前言
今日文案:
许多事情看似不可能,但在敢为人先的勇敢和坚韧执着的发奋下,会变成可能,会变成事实。看追的事情就去做,追求就有期望,发奋就有可能。
一、四数相加||
题目来源:
暴力解法思路:
四数相加==0,知道一个结果,求出四个下标。我们最容易想到暴力解法,四个for循环嵌套来一个一个遍历,枚举,但时间复杂度就去到了恐怖的O(n^4),可以,但不好。
哈希解法思路:
我们要求的是一个结果值,好像和之前查找字符串是不是相等一样,我们只需要一个++,一个--,最后数组等于0就能说明完全契合,那相加==0,不就是相反数契合吗。那四个数组,我们只需要两两组合,找出他们的结果集,再哈希就可以解决这道题了,时间复杂度也回到了O(n^2),
代码如下:
class Solution { public: int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) { unordered_map<int,int> map; int target=0,count=0; for(int i=0;i<nums1.size();i++) //循环遍历出每一个结果值 { for(int j=0;j<nums1.size();j++) { map[nums2[j]+nums1[i]]++; } } for(int i=0;i<nums1.size();i++) { for(int j=0;j<nums1.size();j++) { target=0-(nums3[i]+nums4[j]); //target-结果值就是我们要从上面结果值找的数 if(map.find(target)!=map.end()) //查找 count=count+map[target]; //因为里面可能不止一个符合的结果值 } } return count; } };
二、赎金信
题目来源:
解题思路:
我们要干嘛?我们要在一个集合里找元素的个数是否和另外一个集合的元素个数相等,还是字母,26个,我们只需要使用哈希数组结构就能轻松实现。
代码如下:
class Solution { public: bool canConstruct(string ransomNote, string magazine) { int hash[26]={0},a=1; for(int i=0;i<ransomNote.size();i++) { hash[ransomNote[i]-'a']++; } for(int i=0;i<magazine.size();i++) { hash[magazine[i]-'a']--; } for(int i=0;i<26;i++) { if(hash[i]>0) a=0; }; if(a==0) return false; else return true; } };
前面的博客有写过数组解法,就不多解释了。
三、三数之和
题目描述:
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请
你返回所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
题目来源:
解题思路:
可能有朋友看到这题,会马上想到四数相加||,这乍一看确实很像,但是仔细看看,好像又不一样了,我们这里的三元组是不重复的,而且i != j、i != k 且 j != k,要是要用哈希法的话,会很麻烦,具体我也不会。
我们在这里可以用一个双指针的思路。下面是一些比较重要的点,如图:
细节的点我会在代码上标明:
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { sort(nums.begin(),nums.end()); //排序 int i=0,left,right; vector<vector<int>> ans; for(i=0;i<nums.size();i++) { left=i+1; right=nums.size()-1; if(nums[i]>0) //最小值大于0,说明不可能再有和==0了 return ans; if(i>0&&nums[i]==nums[i-1]) //如果后面的值等于前面那个,那个数的所有结果集都 continue; //已经用过了,直接下一层循环 while(right>left){ //这个条件是必要的 if(nums[i]+nums[left]+nums[right]>0) { right--; //值大就左移right拉小 } else if(nums[i]+nums[left]+nums[right]<0) { left++; //值大就右移left拉大 } else if(nums[i]+nums[left]+nums[right]==0) { ans.push_back(vector<int>{nums[i], nums[left], nums[right]});//保存 while(right>left&&nums[right]==nums[right-1]) //判断重复 { right--; } while(right>left&&nums[left+1]==nums[left]) { left++; } left++; //指针收缩 right--; } } } return ans; } };
四、四数之和:
题目描述:
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
题目来源:
解题思路:
与上面的有点像,但是剪枝和查重部分,有出入,直接上代码:
class Solution { public: vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int>> ans; sort(nums.begin(),nums.end()); int k,left,right; for(k=0;k<nums.size();k++) { if(k>0&&nums[k]==nums[k-1]) { continue; } if(nums[k]>=0&&nums[k]>target) { break; } for(int i=k+1;i<nums.size();i++) { if(nums[i]+nums[k]>=0&&nums[i]+nums[k]>target) { break; } if(i>k+1&&nums[i]==nums[i-1]) { continue; } left=i+1; right=nums.size()-1; while(left<right) { if((long)nums[i]+nums[k]+nums[left]+nums[right]>target) { right--; } else if((long)nums[i]+nums[k]+nums[left]+nums[right]<target) { left++; } else { ans.push_back(vector<int>{nums[i],nums[k],nums[left],nums[right]}); while(left<right&&nums[left+1]==nums[left]) left++; while(left<right&&nums[right-1]==nums[right]) right--; left++; right--; } } } } return ans; } };
总结
继续每天进步一点点。