首页 > 编程语言 >[6]-代码随想录算法训练营-dat7-哈希表-part2

[6]-代码随想录算法训练营-dat7-哈希表-part2

时间:2023-08-31 22:55:12浏览次数:50  
标签:right nums int 随想录 ++ part2 vector 哈希 left

代码随想录算法训练营第七天|哈希表-part2

1. LeetCode 454. 四数相加 II

  1. 题目

  2. 思路

  3. 刷随想录后想法

    • 将四数相加转化为两数之和
    • 借用unordered_map,利用两数之和思想解决本问题
  4. 实现困难

    • 代码尚模糊,不过整个流程能写出来
    • 对部分C++特性尚不清楚,比如map的使用
  5. 实现代码

    class Solution {
    public:
        int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
            unordered_map <int, int> uMap;
            int count = 0;
    
            for(int a:nums1){
                for(int b:nums2){
                    uMap[a+b]++;
                }
            }
    
            for (int c:nums3){
                for (int d:nums4){
                    if(uMap.find(0-(c+d)) != uMap.end()){
                        //如果找到相反数了
                        count += uMap[0-(c+d)];
                    }
                }
            }
            return count;
        }
    };
    
  6. 学习收获

    • 四数变两数,有繁化简的思想

2. LeetCode 383. 赎金信

  1. 题目

  2. 思路

    • 使用map,其中的key为magazine里面的每一个字符,value为每个字符的个数,如果个数为0则返回false
  3. 刷随想录后想法

    • map消耗过大,因为都是小写字母,用数组完全ok
  4. 实现困难

  5. 实现代码

    class Solution {
    public:
        bool canConstruct(string ransomNote, string magazine) {
            int hash[26] = {0};
    
            for (int i=0; i < magazine.size(); i++){
                hash[ magazine[i]- 'a']++;
            }
    
            for (int i=0; i < ransomNote.size(); i++){
                if(hash[ ransomNote[i] - 'a'] <= 0){
                    return false;
                }else{
                    hash[ ransomNote[i] - 'a' ]--;
                }
            }
            return true;
        }
    };
    
  6. 学习收获

3. LeetCode 15. 三数之和

  1. 题目

  2. 思路

  3. 刷随想录后想法

    • 排序+双指针
  4. 实现困难

    • 总是将题目条件看漏,导致思考问题想象的过于复杂
    • 自己编写时,对判重条件总是会漏掉一些,思维不够全面和严谨
  5. 实现代码

    class Solution {
    public:
        vector<vector<int>> threeSum(vector<int>& nums) {
            vector< vector<int> > result;
            //先进行排序
            sort(nums.begin(), nums.end());
            for (int i=0; i < nums.size(); i++){
                int left = i+1;
                int right = nums.size()-1;
    
                //如果i>0,则后续所有都是>0的数,因此直接跳出循环
                if (nums[i] > 0){
                     break;
                }
    
                //如果i在前面一个有一样的,就不用重复判断了
                if ( i > 0 && nums[i] == nums[i-1] ){
                     continue;
                }
    
                 //如果i<=0
                while( left < right ){
                     if((nums[i] + nums[left] + nums[right]) == 0){
                        //如果和为0,则找到了一组
                        result.push_back(vector<int> {nums[i], nums[left], nums[right]});
                        //这里注意去重 1111,只有一个1有效
                        while(right > left && nums[right] == nums[right-1])
                            right--;
                        while(left < right && nums[left] == nums[left+1])
                            left++;
                        //别忘记了左右指针移动
                        right--;
                        left++;
                     }else if((nums[i] + nums[left] + nums[right]) > 0){
                         right--;
                     }else{
                         left++;
                     }
                }
            }
            return result;
        }
    };
    
  6. 学习收获

    • 并不是所有的题目用哈希法都简单,尝试思考对指针的运用

4.Leecode 18. 四数之和

  1. 题目

  2. 思路

    • 参考前面三数之和的思想,用三指针
  3. 刷随想录后想法

    • 更改思路,两个基数,两个依旧用双指针
    • 注意target可能是负数,-1+(-2) = -3,因此剪枝时要主语与三树之和的区别
    • 剪枝要仔细
  4. 实现困难

    • 容易漏掉剪枝条件,或者说错判剪枝条件
    • 没考虑到溢出情况
  5. 实现代码

    class Solution {
    public:
        vector<vector<int>> fourSum(vector<int>& nums, int target) {
            vector<vector<int>> result;
            sort(nums.begin(), nums.end());
    
            for (int k = 0; k < nums.size(); k++){
                //第一层剪枝,注意包含target=0的情况
                if (nums[k] > target && target >= 0){
                    break;
                }
                //存在k和k-1一样的情况,需要去掉
                if (k > 0 && nums[k] == nums[k - 1]){
                    continue;
                }
                for(int i = k+1; i < nums.size(); i++){
                    //第二层剪枝
                    if( (nums[k] + nums[i]) > target && target >= 0){
                        break;
                    }
                    //注意这里是i>k+1 而不是i>0
                    if(i > k + 1 && nums[i] == nums[i - 1]){
                        continue;
                    }
    
                    int left = i + 1;
                    int right = nums.size() - 1;
    
                    while(left < right){
                        //这里要用(long),为什么?
                        if((long)nums[k] + nums[i] + nums[left] + nums[right] > target){
                            right--;
                        }else if ((long)nums[k] + nums[i] + nums[left] + nums[right] < target){
                            left++;
                        }else{
                            // 四数之和为target
                            result.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});
                            //去掉right和left身前一样的
                            while(right > left && nums[right] == nums[right-1]){
                                right--;
                            }
                            while(left < right && nums[left] == nums[left+1]){
                                left++;
                            }
                            right--;
                            left++;
                        }
                    }
                }
            }
            return result;
        }
    };
    
  6. 学习收获

    • 双指针思想,同类问题转化为“三数之和”
    • 双指针的广泛应用

标签:right,nums,int,随想录,++,part2,vector,哈希,left
From: https://www.cnblogs.com/Miubai-blog/p/17670646.html

相关文章

  • [代码随想录]Day30-贪心算法part04
    题目:860.柠檬水找零思路:收到钱三种情况:5刀:直接收起来就可以了,不需要找钱10刀:收到10刀,需要找5刀,如果没有5刀,就返回false,否则5刀-120刀:收到20刀(但是没用,找钱也不能找20所以不需要记录数量),优先考虑找105,因为10只能在这里用,其次再考虑找555代码:funclemonadeChange(bil......
  • 代码随想录第6天|242.有效的字母异位词;349.两个数组的交集;202.快乐数;1.两数之和;
     unordered_map<int,int>map;  unordered_set<int>result;vector<vector<int>>res(n,vector<int>(n,0));声明了长度为n*n的二维数组在C++中,auto是一个关键字,用于实现类型推导,使编译器能够根据变量的初始化表达式来自动推断其数据类型。它在C++11标准中引入,......
  • [代码随想录]Day29-贪心算法part03
    题目:1005.K次取反后最大化的数组和思路:思路是:先把负数从小到大变成正数(即绝对值由大到小)如果还需要变化(k>0),就变化最小的数在第一步变化的同时顺便记录一个数组和,那么结束之后会有三种情况:k==0;也就是说负数的个数大于等于k,直接返回结果k%2==0;此时全是正整数,......
  • 哈希表基础题217. 存在重复元素、389. 找不同、496. 下一个更大元素 I
    217. 存在重复元素1classSolution:2defcontainsDuplicate(self,nums:List[int])->bool:3#方法1:set去重,直接比较去重之后数组长度4iflen(set(nums))!=len(nums):5returnTrue6else:7return......
  • 哈希表
    哈希表CSDN哈希表的作用哈希表是在键和值之间通过散列函数建立对应关系,将一个庞大的值域映射到一个比较小的空间,并使得元素的查找可以以\(O(1)\)的效率进行例将\(0\sim10^9\to0\sim10^5\)\[Loc(i)=Hash(key_i)\]常见的散列函数线性定址法:直接取关键字的某个线性函数......
  • hash(哈希)
    hash(哈希)map集合k-map关于哈希操作的命令一般都是以h开头的创建一个哈希hset创建一个哈希127.0.0.1:6379>hsetmyhashf1hello(integer)1读取一个哈希127.0.0.1:6379>HGETmyhashf1"hello"127.0.0.1:6379>设置多个值使用mset的时候如果原本的数据已经存在那么会覆盖......
  • 代码随想录第4天|链表复习
    做这种算法题真的要放平心态,你想不到思路的时候不要觉得自己太笨,其实想不到很正常,今天环形链表和相交链表这两道题,真的一点思路都没有,环形链表是最难理解的,在课堂上学的链表上的那点东西拿来做这种题确实还是差很多,我真的非常感谢这个做题的训练营,没有它我自己真的做不下去,现在跟......
  • 代码随想录算法训练营第二十四天| 理论基础 77. 组合
     理论基础    卡哥建议:其实在讲解二叉树的时候,就给大家介绍过回溯,这次正式开启回溯算法,大家可以先看视频,对回溯算法有一个整体的了解。   题目链接/文章讲解:https://programmercarl.com/%E5%9B%9E%E6%BA%AF%E7%AE%97%E6%B3%95%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%8......
  • 代码随想录算法训练营第二十三天| 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜
     669. 修剪二叉搜索树    卡哥建议:这道题目比较难,比 添加增加和删除节点难的多,建议先看视频理解。   题目链接/文章讲解:https://programmercarl.com/0669.%E4%BF%AE%E5%89%AA%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.html   视频讲解:https://www.......
  • 代码随想录算法训练营第二十二天| 235. 二叉搜索树的最近公共祖先 701.二叉搜索树
      235. 二叉搜索树的最近公共祖先    卡哥建议:相对于 二叉树的最近公共祖先 本题就简单一些了,因为 可以利用二叉搜索树的特性。   题目链接/文章讲解:https://programmercarl.com/0235.%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E7%9A%84%E6%9C%80%E8%B......