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

Leetcode 454.四数相加II

题目链接:454.四数相加II
思路:通过哈希表记录a+b,并在哈希表找寻0 - (c+d) 是否等于 a + b,那么就可以找到四数相加的答案(i, j, k, l),这题于四数之和的区别在于因为它没有要求去重。所以可以用哈希法来做

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int, int> map;
        int count = 0;
        
        for(int a : nums1) {
            for(int b : nums2) {
                map[a+b]++;
            }
        }
        for(int c : nums3) {
            for(int d : nums4) {
                auto iter = map.find(0 - (c + d));
                if(iter != map.end()) {
                    count += iter->second;
                }
            }
        }
        return count;
    }
};
  • 时间复杂度为O(n^2)
  • 空间复杂度为O(n^2)

Leetcode 383.赎金信

题目链接:383.赎金信

哈希法(map)思路:这题与有效字母异位词有点类似,但我这里使用了map来写,记录magazine的字符++,然后ransomNote的字符–,如果在map中没出现该字符或该字符< 0就return false,否则return true

哈希法(数组)思路:用数组做的话就完全类似于有效字母异位词了。详细思路可以看有效字母异位词

哈希法(map):

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        unordered_map<char, int> map;
        for(char x : magazine) {
            map[x]++;
        }

        for(char x : ransomNote) {
            auto iter = map.find(x);
            if(iter != map.end() && iter->second > 0) {
                iter->second --;
            } else {
                return false;
            }
        }
        return true;
    }
};
  • 时间复杂度为O(n)
  • 空间复杂度为O(n)

哈希法(数组):

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26] = { 0 };

        for(int i = 0; i < ransomNote.size(); i++) {
            record[ransomNote[i] - 'a'] --;
        }

        for(int i = 0; i < magazine.size(); i++) {
            record[magazine[i] - 'a'] ++;
        }
        
        for(int i = 0; i < 26; i++) {
            if(record[i] < 0) return false;
        }
        return true;
    }
};
  • 时间复杂度为O(n)
  • 空间复杂度为O(1)

Leetcode.15三数之和

题目链接:15.三数之和
思路:这题用哈希法来做的话,不容易达到bugfree。因此这里只写双指针的方法,首先对nums进行排序,这样的话数组就会变成有序,那么对后序去找到target也比较容易。
我们对数组有三个大概的变量,一个是i,一个是left,一个right,i从头开始循环,而left则是i + 1,right 是nums.size() - 1,那主要移动的是left和right,而i由for循环来推进。首先如果我们三数之和是要等于0,如果排序后的数组的第一个元素已经是大于0,那不可能找出合适的三元组,直接return即可。那该如何移动left和right呢,那我们可以用一个循环,当三数之和相加 > 0说明,我们该减少这个数,那right = right - 1即可,那如果 < 0 说明,我们该增大这个数,那left = left + 1即可。等于0的话我们就将这个三元组push到result当中去。然后我们再对right和left进行去重,再移动left和right指针。

双指针法:

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[left] + nums[right] > 0) {
                    right = right - 1;
                } else if(nums[i] + nums[left] + nums[right] < 0) {
                    left = left + 1;
                } else {
                    result.push_back(vector<int>{nums[i], nums[left], nums[right]});
                    while(right > left && nums[right] == nums[right-1]) right--;
                    while(right > left && nums[left] == nums[left+1]) left++;
                    left ++;
                    right --;
                }
            }
        }
        return result;
    }
};
  • 时间复杂度为O(n^2)
  • 空间复杂度为O(1)

Leetcode 18.四数之和

题目链接:18.四数之和
思路:这题也是用哈希法不太好做的,那这里使用双指针法,但这题的思路可以在三数之和的思路上做。那我们前面也是先将数组排序,然后我们增加一个k的循环不变量,两层循环nums[k] + nums[i]作为确定值,循环内有left和right的双指针,从而找出nums[k] + nums[i] + nums[left] + nums[right] == target的情况。额外的就是剪枝的情况,不再像三数之和那么简单了,因为有可能有负数的情况,那么必须nums[k] > target && nums[k] >= 0再可以进行剪枝,在for i循环中则是nums[k] + nums[i] > target && nums[k] + nums[i] >= 0 才能剪枝(有可能出现-4 -3 -2 -1 target = -10,如果简简单单nums[k] > 0 或者是nums[k] + nums[i]就进行剪枝,就会出现找不到target的情况),而去重操作是和三数之和类似的。

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++) {
        	//剪枝
            if(nums[k] > target && nums[k] >= 0) {
                break;
            }
            //去重
            if(k > 0 && nums[k] == nums[k - 1]) continue;

            for(int i = k + 1; i < nums.size(); i++) {
                if(nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) break;

                if(i > k + 1 && nums[i] == nums[i - 1]) continue;

                int left = i + 1;
                int right = nums.size() - 1;
                while(right > left) {
                    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 {
                        result.push_back(vector<int>{nums[k], nums[i], nums[left], nums[right]});

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

                        right --;
                        left ++;
                    }
                }
            }
        }
        return result;
    }
};
  • 时间复杂度为O(n^3)
  • 空间复杂度为O(1)

今日收获:温故知新,明天该进入字符串章节了
学习时长:两个半小时

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值