代码随想录刷题-哈希表-四数之和

四数之和

本节对应代码随想录中:代码随想录,讲解视频:难在去重和剪枝!| LeetCode:18. 四数之和_哔哩哔哩_bilibili

习题

题目链接:18. 四数之和 - 力扣(LeetCode)

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。

示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

示例 2:
输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]

双指针

这题的解法和上面的三数之和类似。在三数之和中,我们使用一个 i 指针遍历第一个元素,然后使用 left 和 right 指针寻找合适的第二个和第三个元素。在这题中,还是用 left 和 right 指针去查找合适的最后两个元素,不过要多加一层 for 循环去遍历第二个元素

对于第一个元素去重,我们的判断条件是 i>0&&nums[i]==nums[i-1],而对于第二个元素去重,还是 nums[j]==nums[j-1] 只不过这里是 j>i+1 不能写成 j>0,比如0 0 0 0,target =0 ,i=0,j=1时 nums[j]==nums[j-1] 这其实就是用 nums[j]和前面的 nums[i]进行了对比。当 j=i+1 的时候是可能满足四元组的条件的,因此,判断条件是 j>i+1&&nums[j]==nums[j-1],其实就是要大于它循环的初始值

另外,还需要注意的是,四个数直接相加,在 LeetCode 给的测试用例中会有整数溢出的情况,因此要转换成 long。可以写四条赋值语句将四个数都转为 long,但更好的写法是在相加的时候将其中一个数转为 long,其余的 int 类型的元素也会被自动升级为 long 类型进行计算,从而避免了整数溢出的问题

一样的道理,五数之和、六数之和等等都采用这种解法

class Solution {
    
    
   public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
    
    
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        // 找出a + b + c + d = target
        // a = nums[i], b = nums[j],b = nums[left], c = nums[right]
        for (int i = 0; i < nums.size(); i++) {
    
    
            // 对a去重
            if (i > 0 && nums[i] == nums[i - 1]) {
    
    
                continue;
            }
            for (int j = i + 1; j < nums.size(); j++) {
    
    
                // 对b去重
                if (j > i + 1 && nums[j] == nums[j - 1]) {
    
    
                    continue;
                }
                int left = j + 1;
                int right = nums.size() - 1;
                while (right > left) {
    
    
                    // nums[i] + nums[j] + nums[left] + nums[right] > target 会溢出
                    if ((long)nums[i] + nums[j] + nums[left] + nums[right] > target) {
    
    
                        right--;
                        // nums[i] + nums[j] + nums[left] + nums[right] < target会溢出
                    } else if ((long)nums[i] + nums[j] + nums[left] + nums[right] < target) {
    
    
                        left++;
                    } else {
    
    
                        result.push_back(
                            {
    
    nums[i], nums[j], 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;
    }
};
  • 时间复杂度:O( n 3 n^3 n3)。外层有两个 for 循环,时间复杂度为 O( n 2 n^2 n2),内部用了 while 循环,时间复杂度为 O(n),最终总的时间复杂度为 O( n 2 ∗ n n^2 * n n2n) = O( n 3 n^3 n3)。
  • 空间复杂度:O(n)。只开辟了一个 vector<\vector> result 存储答案,因此空间复杂度为 O(n)

猜你喜欢

转载自blog.csdn.net/zss192/article/details/129779381