代码随想录训练营打卡DAY 7 | 哈希表+双指针

代码随想录训练营打卡DAY 7 | 哈希表+双指针

四数相加

454.四数相加(leetcode链接)

注意:与四数之和区分开

题解

思路:利用unordered_map存储sum1和sum2的和key以及出现的次数value,遍历sum3和sum4与map比较即可。

核心代码【C++】:

// 4个数组,与只有一个数组(四数之和)区分开
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
    // int n = nums1.size();
    // int i,j,result = 0;
    // unordered_map<int,int> sum1_2;
    // // 遍历nums1和nums2,求出数组的和 key 并记录个数 value
    // for(i = 0; i < n; i++){
    //     for(j = 0; j < n; j++){
    //         int sum = nums1[i] + nums2[j];
    //         auto iter = sum1_2.find(sum);
    //         if(iter == sum1_2.end()) sum1_2.insert(pair<int,int>(sum,1));
    //         else iter->second++;
    //     }
    // }
    // // 遍历nums3和nums4,看看其和的相反数在不在集合sum1_2中
    // for(i = 0; i < n; i++){
    //     for(j = 0; j < n; j++){
    //         int target = - nums3[i] - nums4[j];
    //         auto iter = sum1_2.find(target);
    //         if(iter != sum1_2.end()) result += iter->second;
    //     }
    // }
    // return result;

    // c++风格代码
    int result = 0;
    unordered_map<int,int> sum1_2;
    for(int a : nums1){
        for(int b : nums2){
            // C++中,map[i] 即value
            sum1_2[a + b]++;
        }
    }
    for(int c : nums3){
        for(int d : nums4){
            if(sum1_2.find(-c-d) != sum1_2.end()) result += sum1_2[-c-d];
        }
    }
    return result;
}

时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( n 2 ) O(n^2) O(n2)

赎金信

383.赎金信(leetcode链接)

题解

思路:利用map存储字母以及出现的次数。由于键值是小写字母,个数有限,所以用数组其实是更好的解法。

核心代码【C++】:

bool canConstruct(string ransomNote, string magazine) {
    // 本道题由于键值是小写字母,个数有限,所以用数组其实是更好的解法
    unordered_map<char,int> magazineSet;
    for(char c : magazine){
        magazineSet[c]++;
    }
    for(char c : ransomNote){
        auto iter = magazineSet.find(c);
        if(iter == magazineSet.end()) return false;
        else{
            iter->second--;
            if(iter->second == -1) return false;
        }
    }
    return true;
}

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)

三数之和 & 四数之和

注意:与四数相加区分开

15.三数之和(leetcode链接)

18.四数之和(leetcode链接)

题解

思路:利用双指针,这里只解析三数之和,四数之和同理。

  • 双指针法求和前需要排序。
  • 一层for循环遍历sum1,由于题目要求不重复,所以当num[i] == num[i-1]时,要跳过当前的sum1;同时这里不可以是num[i] == num[i+1],因为这样其实是比较sum1与sum2了,如[-1,-1,2]。
  • sum2与sum3分别用指针left与right指向。当sum == target时将三元组push到result,反之收缩指针left或right。且只有当push后才需要对sum2或sum3去重,具体见代码注释。

核心代码【C++】:

vector<vector<int>> threeSum(vector<int>& nums) {
    vector<vector<int>> result;
    int i, left, right;
    sort(nums.begin(), nums.end());// 将nums排序
    int n = nums.size();
    for(i = 0; i < n; i++){
        left = i + 1;
        right = n - 1;
        if(i > 0 && nums[i] == nums[i - 1]){//对sum1去重
            continue;
        }
        while (left < right)
        {
            if(nums[i] + nums[left] + nums[right] == 0){
                result.push_back(vector<int>{nums[i], nums[left++],nums[right--]});
                // 对sum2去重
                while (left < right && nums[left] == nums[left-1])
                {
                    left++;
                }
                // 对sum3去重
                while (left < right && nums[right] == nums[right+1])
                {
                    right--;
                }
            }
            else if(nums[i] + nums[left] + nums[right] < 0){
                left++;
                // 下面注释掉了对 left 和 right 的去重逻辑,因为即使这里没有去重,由于if条件,left 和 right仍然会收缩
                // while (left < right && nums[left] == nums[left-1])
                // {
                //     left++;
                // }
            }
            else{
                right--;
                // while (left < right && nums[right] == nums[right+1])
                // {
                //     right--;
                // }
            }
        }      
    }
    return result;
}

时间复杂度: O ( n 2 ) O(n^2) O(n2)
空间复杂度: O ( 1 ) O(1) O(1),返回值需要用到的空间不计入额外空间

四数之和代码【C++】代码:

vector<vector<int>> fourSum(vector<int>& nums, int target) {
    vector<vector<int>> result;
    int i,j,left,right;
    int n = nums.size();
    sort(nums.begin(),nums.end());
    for(i = 0; i < n; i++){
        if(i > 0 && nums[i] == nums[i-1]) continue;
        for(j = i + 1; j < n; j++){
            if(j > i + 1 && nums[j] == nums[j-1]) continue;
            left = j + 1;
            right = n - 1;
            while(left < right){
                // 4数之和可能会溢出,转化为long
                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 {
                    result.push_back(vector<int>{nums[i], nums[j], nums[left++], nums[right--]});
                    while(left < right && nums[left] == nums[left-1]) left++;
                    while(left < right && nums[right] == nums[right+1]) right--;
                }
            }
        }
    }
    return result;
}

时间复杂度: O ( n 3 ) O(n^3) O(n3)
空间复杂度: O ( 1 ) O(1) O(1)

参考文档

  1. https://programmercarl.com/0454.%E5%9B%9B%E6%95%B0%E7%9B%B8%E5%8A%A0II.html
  2. https://programmercarl.com/0383.%E8%B5%8E%E9%87%91%E4%BF%A1.html
  3. https://programmercarl.com/0015.%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C.html
  4. https://programmercarl.com/0018.%E5%9B%9B%E6%95%B0%E4%B9%8B%E5%92%8C.html
  • 26
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值