代码随想录第六天|454.四数相加II、 383. 赎金信、15. 三数之和、18. 四数之和

454.四数相加II

思路:先求nums1和nums2和的种类,记录数目,用unordered_map记录。遍历得到nums3和nums4的和,回到unordered_map搜索有没有数可以凑到0。
题解:

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int, int> map;
        int ret{0};
        for (int &num1:nums1)
        {
            for (int &num2:nums2)
                ++map[num1+num2];
        }
        for (int &num3:nums3)
        {
            for (int &num4:nums4)
            {
                auto it = map.find(-(num3+num4));
                if (it != map.end())
                    ret += it -> second;
            }
        }
        return ret;
    }
};

383. 赎金信

思路:用hash表存一下ransomNote里的字母分布,遍历magazine就行。
题解:

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        unordered_map <char,int> hash;
        for (char ch : ransomNote)
            ++hash[ch];
        for (char ch : magazine)
        {
            if (hash.find(ch) != hash.end())
            {
                if (hash[ch] == 1)
                    hash.erase(ch);
                else
                    --hash[ch];
            }
        }
        return hash.empty() ? true : false;
    }
};

15. 三数之和

思路:确定第一个数后,另外两个数由双指针法得到,本身不难,但是剪枝部分可能出一堆问题。我自己的话主要是两个出错了。
首先

if (i != 0 && nums[i] == nums[i-1])

这行两个条件写反了,导致越界,应该养成良好习惯,把对下标的要求尽量写在前面。
其次

while (nums[right] == nums[right-1] && left < right) right--;
while (nums[left] == nums[left+1] && left < right) left++;

在剪枝防止重复的过程中,left+1或者right-1可能就越界了,需要注意。
题解:

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ret;
        for (int i = 0; i < nums.size(); ++i)
        {
            if (nums[i] > 0)
                return ret;
            if (i != 0 && nums[i] == nums[i-1])
                continue;
            int left = i + 1;
            int right = nums.size() - 1;
            while (left < right)
            {
                if (nums[left] + nums[right] > -nums[i]) 
                    --right;
                else if (nums[left] + nums[right] < -nums[i]) 
                    ++left;
                else
                {
                    vector<int> subret = {nums[i], nums[left], nums[right]};
                    ret.push_back(subret);
                    while (nums[right] == nums[right-1] && left < right) right--;
                    while (nums[left] == nums[left+1] && left < right) left++;
                    --right;
                    ++left;
                }
            }
        }
        return ret;
    }
};

18. 四数之和

思路:上一题的plus版,和上一题的注意点相同,注意一下四个数相加可能溢出,但是其实改成

nums[left] + nums[right] > target - nums[i] - nums[j]

是不会溢出的,但是四个数相加美观一点。
题解:

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ret;
        for (int i = 0; i < nums.size(); ++i)
        {
            if (nums[i] > target && target > 0)
                return ret;
            if (i > 0 && nums[i] == nums[i-1])
                continue;
            for (int j = i + 1; j < nums.size(); ++j)
            {
                if (nums[j] == nums[j-1] && j > i + 1)
                    continue;
                int left = j + 1;
                int right = nums.size() - 1;
                while (left < right)
                {
                    if ((long)nums[left] + nums[right] + nums[i] + nums[j] > target)
                        --right;
                    else if ((long)nums[left] + nums[right] + nums[i] + nums[j] < target)
                        ++left;
                    else
                    {
                        vector<int> subret = {nums[i], nums[j], nums[left], nums[right]};
                        ret.push_back(subret);
                        while (nums[right] == nums[right-1] && left < right) --right;
                        while (nums[left] == nums[left+1] && left < right) ++left;
                        ++left;
                        --right;
                    }
                }
            }
        }
        return ret;
    }
};
  • 8
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值