leetcode第454四数相加和第15三数之和两题对比

这两题看似相似,其实差的很多,第454不需要考虑去重,但是第15题需要考虑去重问题,所以两题方法是不一样的

LeetCode第454四数相加

这道题目我们用哈希表做比较简单,原因是这是四个独立的数组,只要找到A[i] + B[j] + C[k] + D[l] = 0就可以,不用考虑有重复的四个元素相加等于0的情况

本题注意事项:

一.基于哈希表实现的两个主要容器:

unordered_map:
         存储键值对(key-value pairs)。
         每个键是唯一的,每个键对应一个值。
          用于快速查找特定键并获取相应值的场景,如构建字典、缓存等
         基于哈希表实现,平均查找时间复杂度是 O(1)。

unordered_map的方法:

1. `insert(key, value)`:插入键-值对。
2. `erase(key)`:删除具有给定键的元素。
3. `find(key)`:查找具有给定键的元素,并返回指向该元素的迭代器。
4. `count(key)`:返回具有给定键的元素的数量(通常为0或1,因为键必须唯一)。
5. `size()`:返回容器中的元素数量。
6. `empty()`:检查容器是否为空。
7. `clear()`:清空容器中的所有元素。
8. `begin()` 和 `end()`:迭代容器的起始和结束位置。


 unordered_set:
        存储唯一值的集合。
       用于存储一组元素,并确保其中不包含重复值的场景,如查找元素是否存在、去重、存储集合等。
       基于哈希表实现,平均查找、插入和删除时间复杂度都是 O(1)。

`std::unordered_map` 和 `std::unordered_set` 是C++中的无序关联容器,它们分别用于存储键-值对和唯一值的集合。

 unordered_set的方法:

1. `insert(value)`:插入值。
2. `erase(value)`:删除具有给定值的元素。
3. `find(value)`:查找具有给定值的元素,并返回指向该元素的迭代器。
4. `count(value)`:返回具有给定值的元素的数量(通常为0或1,因为值必须唯一)。
5. `size()`:返回容器中的元素数量。
6. `empty()`:检查容器是否为空。
7. `clear()`:清空容器中的所有元素。
8. `begin()` 和 `end()`:迭代容器的起始和结束位置。

请注意,由于这些容器是无序的,元素的顺序是不确定的。

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int,int>umap;//key:a+b的数值,value:a+b数值出现的次数
        //遍历nums1和nums2,统计两个数组元素之和和出现的次数,放到map中
        for(int a:nums1){
            for(int b:nums2)
            {
                umap[a+b]++;
            } 
        }
        int count=0;//统计a+b+c+d=0出现次数
        //在遍历大C和大D数组,找到如果0-(c+d)在map中key对应的value也就是出现次数统计出来
        for(int c:nums3)
        {
            for(int d:nums4)
            {
                if(umap.find(0-(c+d))!=umap.end())
                {
                    count+=umap[0-(c+d)];
                }
            }
        }
        return count;
        
        

    }
};

leetcode第15题三数之和

这题我们用双指针去做,给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组,因为是在一个数组中查找,所以必须考虑去重情况,把符合条件的三元组放进vector中,然后再去重,去重的过程不好处理,有很多小细节,如果在面试中很难想到位。

所以这题我们用双指针的思路

解题步骤
1. 首先,对输入的 `nums` 数组进行排序,这可以帮助我们更容易地处理重复元素和找到三数之和为零的组合。
2. 创建一个空的二维向量 `result`,用于存储找到的三数之和为零的组合。
3. 使用一个循环来遍历 `nums` 数组,以确定第一个元素 `a`。如果 `a` 大于零,则可以直接返回结果,因为不可能存在三数之和为零的组合。
4. 进行正确的去重操作。在这个问题中,需要确保不会重复考虑相同的 `a` 值。通过跳过重复的 `a` 值,可以避免重复的组合。

5. 使用双指针技巧来查找另外两个元素 `b` 和 `c`,它们的和应该等于 `-a`。一个指针 `left` 从当前元素的下一个位置开始,另一个指针 `right` 从数组末尾开始。

6. 在内部循环中,根据 `a + b + c` 的值与零的比较情况,采取不同的行动:
   - 如果 `a + b + c` 大于零,则将 `right` 指针向左移动,以减小总和。
   - 如果 `a + b + c` 小于零,则将 `left` 指针向右移动,以增加总和。
   - 如果 `a + b + c` 等于零,说明找到了一个符合条件的三数之和组合,将其添加到 `result` 中。

7. 在找到一个三数之和为零的组合后,需要进行去重操作,以确保不重复考虑相同的 `b` 和 `c` 值。这是通过在找到答案后,分别移动 `left` 和 `right` 指针来完成的。

8. 最后,继续循环,直到所有可能的组合都被考虑完毕。

9. 返回 `result`,其中包含了所有符合条件的三数之和为零的组合。

这就是解决这个问题的基本思路和步骤。这个算法的关键在于排序、双指针和去重操作,它们共同确保了高效地找到符合条件的三数之和为零的组合。

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        // 找出a + b + c = 0
        // a = nums[i], b = nums[left], c = nums[right]
        for (int i = 0; i < nums.size(); i++) {
            // 排序之后如果第一个元素已经大于零,那么无论如何组合都不可能凑成三元组,直接返回结果就可以了
            if (nums[i] > 0) {
                return result;
            }
            // 错误去重a方法,将会漏掉-1,-1,2 这种情况
            /*
            if (nums[i] == nums[i + 1]) {
                continue;
            }
            */
            // 正确去重a方法
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            int left = i + 1;
            int right = nums.size() - 1;
            while (right > left) {
                // 去重复逻辑如果放在这里,0,0,0 的情况,可能直接导致 right<=left 了,从而漏掉了 0,0,0 这种三元组
                /*
                while (right > left && nums[right] == nums[right - 1]) right--;
                while (right > left && nums[left] == nums[left + 1]) left++;
                */
                if (nums[i] + nums[left] + nums[right] > 0) right--;
                else if (nums[i] + nums[left] + nums[right] < 0) left++;
                else {
                    result.push_back(vector<int>{nums[i], nums[left], nums[right]});
                    // 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
                    while (right > left && nums[right] == nums[right - 1]) right--;
                    while (right > left && nums[left] == nums[left + 1]) left++;

                    // 找到答案时,双指针同时收缩
                    right--;
                    left++;
                }
            }

        }
        return result;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值