tomoebzk

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Leetcode 454 四数相加Ⅱ

unordered_map使用的练习,一次通过,但是定义了两个unordered_map,并且需要经过两次遍历,空间和时间消耗都增加了

int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<long long ,int>m1;
        unordered_map<long long ,int>m2;
        
        int ans=0;
        for(int i=0;i<nums1.size();++i)
        {
            for(int j=0;j<nums2.size();++j)
            {   
               m1[nums1[i]+nums2[j]]++;
            }
        }
        for(int i=0;i<nums3.size();++i)
        {
            for(int j=0;j<nums4.size();++j)
            {   
               m2[nums3[i]+nums4[j]]++;
            }
        }


        for(auto it1:m1)
        {
            for(auto it2:m2)
            {
                if(it1.first+it2.first==0)
                {
                    
                    ans+=it1.second*it2.second;
                }
            }
        }
        return ans;

    }

看了代码随想录以后才明白一个unordered_map两次遍历就可以了,查找0-(c+d)即可

int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
        unordered_map<int, int> umap; //key:a+b的数值,value:a+b数值出现的次数
        // 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中
        for (int a : A) {
            for (int b : B) {
                umap[a + b]++;
            }
        }
        int count = 0; // 统计a+b+c+d = 0 出现的次数
        // 再遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。
        for (int c : C) {
            for (int d : D) {
                if (umap.find(0 - (c + d)) != umap.end()) {
                    count += umap[0 - (c + d)];
                }
            }
        }
        return count;
    }

Leetcode 383 赎金信

本来想采用数组来统计字母出现次数,但是由于ransomNote是magazine的子集,因此不能直接算arr中减为零的字母,考虑到子集的存在,并且magazine中一个字符只能使用一次,因此词用unordered_map<char,int>m统计magazine中字符出现次数,查找ransomNote中字符时,如果没有出现直接返回false,出现一次m[c]--,如果m[c]=0,直接删除该字符的key,如果ransomNote中还有c,那么就表明不能由magazine构成

bool canConstruct(string ransomNote, string magazine) {
        unordered_map<char,int>m;
        for(char c:magazine)
        {
            m[c]++;
        }
        for(char c:ransomNote)
        {
            auto it=m.find(c);
            if(it==m.end())
                return false;
            
            else
            {
                m[c]--;
                if(m[c]==0)
                {
                    m.erase(c);
                }
            }
        }
        return true;
    }

Leetcode 15 三数之和

这道题考虑了一会没想出来怎么做,本来想要通过哈希表统计两两数之和,再计算第三个数,但是发现由于不重复的原因,查重处理起来很麻烦。看了随想录的思路是二分法后,尝试从这个方面进行编写,采用set<vector>check的特性进行去重,将nums排序以后从第一个数字进行遍历,left=i+1,right=nums.size()-1,使用双指针进行处理,nums[i]+nums[left]+nums[right]<0,left++;nums[i]+nums[left]+nums[right]>0,right--。查找到满足条件的结果后left++。

vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>>ans;
        set<vector<int>>check;
        ranges::sort(nums);
        int left=0;
        int right=nums.size()-1;
        for(int i=0;i<nums.size()-2;++i)
        {
            right=nums.size()-1;
            left=i+1;
            while(left<right)
            {
                if(nums[i]+nums[left]+nums[right]<0)
                {
                    left++;
                    continue;
                }
                else if(nums[i]+nums[left]+nums[right]>0)
                {
                    right--;
                    continue;
                }
                check.insert({nums[i],nums[left],nums[right]});
                left++;
                
                
            }
           
        }
        set<vector<int>>::iterator it;
        for(it=check.begin();it!=check.end();++it)
        {
            ans.push_back(*it);
        }
        return ans;

    }

Leetcode 18 四数之和

模仿三数之和进行,依然采用set<vector>check进行去重,依然排序nums,确定前两个数的基础上对后两个数采用双指针遍历,

vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>>ans;
        set<vector<int>>check;
        if(nums.size()<4) 
        {
           
            return ans;
        }
        ranges::sort(nums);
        for(int i=0;i<nums.size()-3;++i)
        {
            if(nums[i]>target&&nums[i]>=0)
            {
                break;
            }


            //转化为三数之和
            for(int j=i+1;j<nums.size()-2;++j)
            {
                int left=j+1;
                int right=nums.size()-1;
                while(left<right)
                {
                    if((long)nums[i]+nums[j]+nums[left]+nums[right]<target)
                    {
                        left++;
                        
                    }
                    else if((long)nums[i]+nums[j]+nums[left]+nums[right]>target)
                    {
                        right--;
                        
                    }
                    else 
                    {
                        check.insert({nums[i],nums[j],nums[left],nums[right]});
                        left++;
                        right--;
                    }
                }
            }
        }
        set<vector<int>>::iterator it;
        for(it=check.begin();it!=check.end();++it)
        {
            ans.push_back(*it);
        }
        return ans;
    }

运行结果不出所料地拉跨,执行用时和内存消耗双双垫底。

看了看随想录的代码。发现自己有对很多无关情况都进行了处理,例如nums[i]>target时,已经做不到=target,不需要考虑后面的数。由于对nums进行了排序,相邻的数字如果相等的话也不需要进行循环,直接移动到下一个位置即可,例如left增加过程中相同的nums[left]无需重复考虑

if (nums[k] > target && nums[k] >= 0) {
            	break; // 这里使用break,统一通过最后的return返回
            }
            // 对nums[k]去重
            if (k > 0 && nums[k] == nums[k - 1]) {
                continue;
            }
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
posted on 2026-01-21 19:59  broderk  阅读(0)  评论(0)    收藏  举报