当前位置:   article > 正文

代码随想录训练营Day7 哈希表part02 454.四数相加II ● 383. 赎金信 ● 15. 三数之和 ● 18. 四数之和

代码随想录训练营Day7 哈希表part02 454.四数相加II ● 383. 赎金信 ● 15. 三数之和 ● 18. 四数之和

454.四数相加II

题目链接:力扣题目链接

文章链接:代码随想录 (programmercarl.com)

视频链接:学透哈希表,map使用有技巧!LeetCode:454.四数相加II
 

 这道题涉及的四个数组元素的相加,可以运用map,先将nums1和nums2的元素分别相加并存入map中,再判断nums3和nums4元素相加后的得到的元素的相反数是否在map中,若在,即满足条件。

代码如下:

  1. class Solution {
  2. public:
  3. int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
  4. unordered_map <int,int> umap;
  5. for(int n1:nums1)//二层遍历
  6. {
  7. for(int n2:nums2)
  8. {
  9. umap[n1+n2]++;
  10. }
  11. }
  12. int count=0;
  13. for(int n3:nums3)
  14. {
  15. for(int n4:nums4)
  16. {
  17. if(umap.count(-n3-n4)>0)//也可以用umap.find(-n3-n4)!=umap.end()
  18. {
  19. count+=umap[-n3-n4];
  20. }
  21. }
  22. }
  23. return count;
  24. }
  25. };

383. 赎金信 

 题目链接:力扣题目链接

文章链接:代码随想录 (programmercarl.com)

 判断元素是否存在,就要下意识想到运用哈希表,再加上这里需要key和value做映射,很自然想到适用map。本题思考不难,需要注意一点,就是“magazine每个字符只能使用一次”,这就代表了对于magazine同一字符需要计数,代码如下:

  1. class Solution {
  2. public:
  3. bool canConstruct(string ransomNote, string magazine) {
  4. unordered_map <int,int> umap;
  5. for(int i=0;i<magazine.size();i++)
  6. {
  7. umap[magazine[i]]++;//记录同意字符出现次数
  8. }
  9. for(int i=0;i<ransomNote.size();i++)
  10. {
  11. if(umap.count(ransomNote[i])==0)//magazine中找不到该字符
  12. {
  13. return false;
  14. }
  15. if(umap[ransomNote[i]]==0)//magazine中找的到该字符,但可使用的次数已经用完了
  16. {
  17. return false;
  18. }
  19. umap[ransomNote[i]]--;
  20. }
  21. return true;
  22. }
  23. };

15. 三数之和

 题目链接:力扣题目链接

文章链接:代码随想录 (programmercarl.com)

视频链接:梦破碎的地方!| LeetCode:15.三数之和

 这道题我一开始的想法是:先通过两层for循环就可以确定 a 和b 的数值了,然后可以使用哈希法来确定 0-(a+b) 是否在 数组里出现过,但是我们有一个非常棘手的问题,就是题目中说的不可以包含重复的三元组,而哈希表在去重这一方面步骤很是繁琐,这种方法不细讲,代码附上,有兴趣的朋友可以自己研究:

  1. class Solution {
  2. public:
  3. vector<vector<int>> threeSum(vector<int>& nums) {
  4. vector<vector<int>> result;
  5. sort(nums.begin(), nums.end());
  6. // 找出a + b + c = 0
  7. // a = nums[i], b = nums[j], c = -(a + b)
  8. for (int i = 0; i < nums.size(); i++) {
  9. // 排序之后如果第一个元素已经大于零,那么不可能凑成三元组
  10. if (nums[i] > 0) {
  11. break;
  12. }
  13. if (i > 0 && nums[i] == nums[i - 1]) { //三元组元素a去重
  14. continue;
  15. }
  16. unordered_set<int> set;
  17. for (int j = i + 1; j < nums.size(); j++) {
  18. if (j > i + 2
  19. && nums[j] == nums[j-1]
  20. && nums[j-1] == nums[j-2]) { // 三元组元素b去重
  21. continue;
  22. }
  23. int c = 0 - (nums[i] + nums[j]);
  24. if (set.find(c) != set.end()) {
  25. result.push_back({nums[i], nums[j], c});
  26. set.erase(c);// 三元组元素c去重
  27. } else {
  28. set.insert(nums[j]);
  29. }
  30. }
  31. }
  32. return result;
  33. }
  34. };

在此,细讲这道题的另一种做法——排序+双指针法

这道题并没有要求返回数组的下标,所以首先可以通过排序,重新组合数组

接着通过双指针法,left=i+1,right=nums.size()-1,通过判断nums[i]+nums[left]+nums[right]是否等于0,如果大于0,则right--,如果小于0,则left++,如果等于,就将三个数存入二维数组result中。

接着就是去重操作,首先是i,如果写成if(i>0&&nums[i]==nums[i+1]) continue;,则会疏忽-1,-1,2这类情况,所以需要写成if(i>=&&nums[i]==nums[i-1]).

left与left+1比较是否相等,相等就left++

right与right-1比较是否相等,相等就right--

代码如下:

  1. class Solution {
  2. public:
  3. vector<vector<int>> threeSum(vector<int>& nums) {
  4. vector<vector<int>> result;
  5. sort(nums.begin(),nums.end());//数组升序排列
  6. for(int i=0;i<nums.size()-2;i++)
  7. {
  8. if(nums[i]>0)//如果nums[i]都大于0,nums[left]和nums[right]一定大于0,不需要考虑
  9. {
  10. return result;
  11. }
  12. if(i>0&&nums[i]==nums[i-1])//i去重
  13. {
  14. continue;
  15. }
  16. int left=i+1;
  17. int right=nums.size()-1;
  18. while(left<right)
  19. {
  20. if(nums[i]+nums[left]+nums[right]>0)//i去重
  21. {
  22. right--;
  23. }
  24. else if(nums[i]+nums[left]+nums[right]<0)
  25. {
  26. left++;
  27. }
  28. else{
  29. result.push_back(vector<int>{nums[i],nums[left],nums[right]});
  30. while(right>left&&nums[right]==nums[right-1])//right去重
  31. {
  32. right--;
  33. }
  34. while(right>left&&nums[left]==nums[left+1])//left去重
  35. {
  36. left++;
  37. }
  38. right--;
  39. left++;
  40. }
  41. }
  42. }
  43. return result;
  44. }
  45. };

18. 四数之和 

 题目链接:力扣题目链接

文章链接:代码随想录 (programmercarl.com)

视频链接:难在去重和剪枝!| LeetCode:18. 四数之和

 这道题和三数求和的解题思路几乎一模一样,只是更多了一层循环而已,此题重点是剪枝与去重,代码如下:

  1. lass Solution {
  2. public:
  3. vector<vector<int>> fourSum(vector<int>& nums, int target) {
  4. vector<vector<int>> result;
  5. sort(nums.begin(), nums.end());
  6. for (int k = 0; k < nums.size(); k++) {
  7. // 剪枝处理
  8. if (nums[k] > target && nums[k] >= 0) {
  9. break; // 这里使用break,统一通过最后的return返回
  10. }
  11. // 对nums[k]去重
  12. if (k > 0 && nums[k] == nums[k - 1]) {
  13. continue;
  14. }
  15. for (int i = k + 1; i < nums.size(); i++) {
  16. // 2级剪枝处理
  17. if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) {
  18. break;
  19. }
  20. // 对nums[i]去重
  21. if (i > k + 1 && nums[i] == nums[i - 1]) {
  22. continue;
  23. }
  24. int left = i + 1;
  25. int right = nums.size() - 1;
  26. while (right > left) {
  27. // nums[k] + nums[i] + nums[left] + nums[right] > target 会溢出
  28. if ((long) nums[k] + nums[i] + nums[left] + nums[right] > target) {
  29. right--;
  30. // nums[k] + nums[i] + nums[left] + nums[right] < target 会溢出
  31. } else if ((long) nums[k] + nums[i] + nums[left] + nums[right] < target) {
  32. left++;
  33. } else {
  34. result.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});
  35. // 对nums[left]和nums[right]去重
  36. while (right > left && nums[right] == nums[right - 1]) right--;
  37. while (right > left && nums[left] == nums[left + 1]) left++;
  38. // 找到答案时,双指针同时收缩
  39. right--;
  40. left++;
  41. }
  42. }
  43. }
  44. }
  45. return result;
  46. }
  47. };

Day 7打卡成功,耗时3小时。再接再厉!!!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/182856?site
推荐阅读
相关标签
  

闽ICP备14008679号