代码随想录算法训练营第七天| 454.四数相加II 383. 赎金信 15. 三数之和 18. 四数之和

454.四数相加II  

给你四个整数数组 nums1nums2nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

0 <= i, j, k, l < n

nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

题目链接:454. 四数相加 II - 力扣(LeetCode)

思路:当遇到需要确认元素是否重复出现的问题时,考虑用map哈希解决问题。将前两个数组的和存入map1,并用value表示这个和出现的对数。然后查询-(num3[k]+nums4[l])是否出现在map中。

注意:

用insert方法重复插入同一key值的键值对并不会导致覆盖,即会插入失败。

用find方法查找元素会比count方法快很多。

用下标访问map,即使改下标下没有内容,我们也能对value进行访问,不用区别对待。

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        map<int,int> map1;
        int count=0;
        for(int i=0;i<nums1.size();i++){
            for(int j=0;j<nums2.size();j++){
//                auto iter=map1.find(nums1[i]+nums2[j]);
//                if(iter!=map1.end())
//                if(map1.count(nums1[i]+nums2[j]))
                map1[nums1[i]+nums2[j]]++;
//                else
//                map1.insert(pair<int,int>(nums1[i]+nums2[j],1));       //无需区别对待
//                map1.insert(pair<int,int>(nums1[i]+nums2[j],1));
            }
        }

            for(int k=0;k<nums3.size();k++){
                for(int l=0;l<nums4.size();l++){
 //                   auto iter=map1.find(-(nums3[k]+nums4[l]));
//                    if(iter!=map1.end()){
                    if(map1.find(0-(nums3[k]+nums4[l]))!=map1.end()){
                        count+=map1[0-(nums3[k]+nums4[l])];
                    }
                }
            }
            return count;
    }
};

注意下面这种写法,同样的算法,却能比我的版本快一倍多。

class Solution {
public:
    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;
    }
};

383. 赎金信  

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

magazine 中的每个字符只能在 ransomNote 中使用一次。

题目链接:383. 赎金信 - 力扣(LeetCode)

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        map<char,int>map1;
        map<char,int>map2;
        for(char ch:ransomNote){
            map1[ch]++;
        }
        for(char ch:magazine){
            map2[ch]++;
        }
        for(char ch:ransomNote){
            if(map1[ch]>map2[ch])
            return false;
        }
    return true;
    }
};

更好的写法:

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        // 利用哈希表
        unordered_map<char,int> u_m;

        for(auto ch:magazine)
            ++u_m[ch];

        for(auto ch:ransomNote)
        {
            if(u_m[ch]==0)
                return false;
            
            --u_m[ch];
        }

        return true;
    }
};

15. 三数之和  

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

题目链接:15. 三数之和 - 力扣(LeetCode)

思路:正常哈希法会很困难,因为去重的操作很复杂。用双指针法可以有效的解决这个问题。同时,用sort函数先排序原数据的思想要学会(双指针法是一定要排序的)。尽管要求三元组不能重复,但注意三元组内部可以重复,因此在去重a时要注意,要比较a的上一个元素而非a的下一个元素。

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++){
            if(nums[i]>0){
                return result;
            }
            if(i>0&&nums[i]==nums[i-1])
                continue;
            int left=i+1;
            int right=nums.size()-1;
            while(right>left){
            if(nums[i]+nums[right]+nums[left]>0)
                {
                    right--;
                }
            else if(nums[i]+nums[right]+nums[left]<0)
            {
                left++;
            }
            else{

                result.push_back(vector<int>{nums[i],nums[left],nums[right]});    
                while(right>left&&nums[right]==nums[right-1])right--;        //b、c去重
                while(right>left&&nums[left]==nums[left+1])left++;
            right--;                                                        //找到答案在移动b、c
            left++;
            }
            }
        }
        return result;
    }
};

18. 四数之和 

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abc 和 d 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

题目链接:18. 四数之和 - 力扣(LeetCode)

思路:和三数之和思路类似,只是从左动右固定变成左右都动。注意,左边的去重一定要在右边移动之前进行,否则会被[0,0,0,0]判溢出。

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;
        if(nums.size()<4){
         return result;
        }
        sort(nums.begin(),nums.end());

        for(int i=0;i<nums.size()-3;i++){
            if(nums[i]>target&&nums[i]>=0)
                break;
            if(i>0&&nums[i]==nums[i-1]){
                continue;
            }                                    //左侧去重必须在for之前进行
            for(int j=nums.size()-1;j>=i+3;j--){
            if(j<nums.size()-1&&nums[j]==nums[j+1]){
                continue;
            }
            int left=i+1;
            int right=j-1;
            while(right>left){
                if((long)nums[i]+nums[left]+nums[right]+nums[j]>target)right--;
                else if((long)nums[i]+nums[left]+nums[right]+nums[j]<target)left++;
                else{
                    result.push_back(vector<int>{nums[i],nums[left],nums[right],nums[j]});
                    while(right>left&&nums[right]==nums[right-1])right--;
                    while(right>left&&nums[left]==nums[left+1])left++;
                    left++;right--;
                }
            }

            }
        }
        return result;
    }
};

 

posted @ 2024-01-30 19:48  SandaiYoung  阅读(2)  评论(0编辑  收藏  举报