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

LeetCode454. 四数相加 II

文章链接:代码随想录
题目链接:454. 四数相加 II

思路: 需要ket和value,用unordered_map遍历一下即可,由于分四个数组,故不用考虑重复的问题;和两数之和的问题很像;另外注意以下map的用法,和数组类似。

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int, int> record;
        int count = 0;
        for (int a : nums1){
            for (int b : nums2){
                record[a + b]++;
            }
        }
        for (int c : nums3){
            for (int d : nums4){
                if (record.find(0 - c - d) != record.end()){
                    count += record[0 - c - d];
                }
            }
        }
        return count;
    }
};

LeetCode383. 赎金信

文章链接:代码随想录
题目链接:383. 赎金信

思路: key有限,用数组记录,最后出现负数即false,和 LeetCode242.有效的字母异位词 很像。

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26] = {0};
        for (char i : magazine){
            record[i - 'a']++;
        }
        for (char i : ransomNote){
            record[i - 'a']--;
        }
        for (int i : record){
            if (i < 0){
                return false;
            }
        }
        return true;
    }
};

用map也可以做,但时间(要做哈希运算)和空间占用都变大。

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        unordered_map<int, int> record;
        for (char i : magazine){
            record[i - 'a']++;
        }
        for (char i : ransomNote){
            record[i - 'a']--;
            if (record[i - 'a'] < 0){
                return false;
            }
        }
        return true;
    }
};

LeetCode15. 三数之和

文章链接:代码随想录
题目链接:15. 三数之和

思路:用哈希表的方法暂时没做,采用双指针。

  1. 注意用双指针之前先排序
  2. 注意第一步去重时用continue,用 i++ 只能去一遍重。
  3. 注意先收缩和后收缩去重方法的不同
  4. 暂时没写剪枝,后续方法掌握熟练后有时间补全。
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 (i > 0 && nums[i] == nums[i - 1]){
                continue;
            }
            int l = i + 1, r = nums.size() - 1;
            while (l < r){
                if (nums[i] + nums[l] + nums[r] == 0){
                    result.push_back(vector<int> {nums[i], nums[l], nums[r]});
                    while (l < r && nums[l] == nums[l + 1]) l++;
                    while (l < r && nums[r] == nums[r - 1]) r--;
                    l++;
                    r--;
                }
                else if (nums[i] + nums[l] + nums[r] < 0){
                    l++;
                }
                else {
                    r--;
                }
            }

        }
        return result;
    }
};
  1. 排序
sort (nums.begin(), nums.end());
  1. 第一步去重用continue
if (i > 0 && nums[i] == nums[i - 1]){
                continue;
            }
  1. 先去重后收缩:
while (l < r && nums[l] == nums[l + 1]) l++;
while (l < r && nums[r] == nums[r - 1]) r--;
l++;
r--;

先收缩后去重:

l++;
r--;
while (l < r && nums[l] == nums[l - 1]) l++;
while (l < r && nums[r] == nums[r + 1]) r--;

可以这样理解,将排序后的数组看成一级级的台阶,先去重是将指针移到了台阶的边缘,这时收缩后就可以上下台阶;先收缩是先做出上下台阶的动作,但可能存在数值相同没有上下台阶,而后用去重来保障指针真正的进行了上下台阶。
建议还是先去重,方便理解;先收缩的方法自我感觉收缩的意义变小了,虽然最后效果是相同的。

2024.02.18更
现在发现随想录上也没说什么剪枝逻辑啊哈哈哈,应该是就是去重逻辑吧,还有确实就是应该先去重后更新,先更新没啥意义;另外看了哈希的解法,第二层去重的时候确实需要思考一下。

LeetCode18. 四数之和

文章链接:代码随想录
题目链接:题目链接

思路:和 15. 三数之和 一样,采用双指针的方法,多加了一层循环;
剪枝没写,暂时没写哈希表的方法。
另外比 15. 三数之和 需要多注意的是

  1. 这题的目标从0(确定值)变成了target(不定值),在剪枝操作上与 15. 三数之和 有区别。
  2. 这题在判断四数之和前要转成长整型long,不然会发生溢出(C++中int是4个字节,long是8个字节)。附上C++定义的基本整型:
类型含义字节数
bool布尔类型(本质是整形)未定义
char字符2
short短整形4
int整形4
long长整形8
long long(C++11新增)长整形16
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        for (int i = 0; i < nums.size(); i++){
            if (i > 0 && nums[i] == nums[i - 1]){
                continue;
            }
            for (int j = i + 1; j < nums.size(); j++){
                if (j > i + 1 && nums[j] == nums[j - 1]){
                    continue;
                }
                int l = j + 1, r = nums.size() - 1;
                while (l < r){
                    if ((long) nums[i] + nums[j] + nums[l] + nums[r] == target){
                        result.push_back(vector<int> {nums[i], nums[j], nums[l], nums[r]});
                        while (l < r && nums[l] == nums[l + 1]) l++;
                        while (l < r && nums[r] == nums[r - 1]) r--;
                        l++;
                        r--;
                    }
                    else if ((long) nums[i] + nums[j] + nums[l] + nums[r] < target) l++;
                    else r--;
                }
            }
        }
        return result;
    }
};

第七天打卡,debug时思考很多,记录如上,另外有些方法(哈希表)和操作(剪枝)没写,后续有时间补全,加油!!!

  • 28
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值