18. 四数之和 - 力扣(LeetCode)

基础知识要求:

Java:方法、集合、泛型、if else语句、while循环、for循环、逻辑运算符、自增自减运算符、数组、Arrays.sort()、Arrays.asList()

Python: 方法、if else语句、while循环、for循环、逻辑运算符、列表

题目: 

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

  • 0 <= a, b, c, d < n
  • abc 和 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]]

提示:

  • 1 <= nums.length <= 200
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109

思路解析:

  1. 排序:首先,我们对输入数组nums进行排序。排序有助于我们跳过重复的数字,并优化搜索过程。

  2. 固定前两个数:我们使用两个指针ij来固定前两个数。指针i从数组的起始位置开始遍历,而指针j则从i的下一个位置开始遍历。由于数组已经排序,我们可以通过比较当前的和与目标值来跳过一些不必要的搜索。

    • 如果当前两个数之和加上剩余所有数的最小值和最大值仍然小于目标值,那么无需继续遍历当前i,因为后续的组合的和只会更大。
    • 如果当前两个数之和已经大于目标值,那么同样无需继续向后遍历,因为后续的组合的和只会更大。
  3. 固定第三个数:在固定前两个数之后,我们使用指针j来固定第三个数。与固定前两个数类似,我们需要跳过重复的数字以避免重复的组合。

  4. 双指针法:在固定了前三个数之后,我们使用双指针leftright来从数组的剩余部分中选择第四个数。双指针leftj + 1开始,而right从数组的末尾开始。

    • 如果四个数的和等于目标值,我们将这个组合添加到结果列表中,并尝试跳过重复的数字以避免重复的组合。
    • 如果和小于目标值,我们增加left指针来增大和。
    • 如果和大于目标值,我们减小right指针来减小和。
  5. 跳过重复的数字:在遍历过程中,我们需要跳过重复的数字以避免产生重复的组合。这是通过在固定每个数字后检查它是否与前一个数字相同来实现的。

  6. 返回结果:最后,我们返回所有满足条件的四元组列表。

Java代码示例:

import java.util.ArrayList;  
import java.util.Arrays;  
import java.util.List;  
  
public class Solution {  
    public List<List<Integer>> fourSum(int[] nums, int target) {  
        List<List<Integer>> result = new ArrayList<>(); // 存储满足条件的四元组结果  
  
        if (nums == null || nums.length < 4) {  
            return result; // 如果数组为空或长度小于4,直接返回空结果  
        }  
  
        // 对数组进行排序,以便使用双指针法  
        Arrays.sort(nums);  
  
        int n = nums.length;  
  
        // 固定前两个数(i, j)  
        for (int i = 0; i < n - 3; i++) {  
            // 跳过重复的数字,避免重复组合  
            if (i > 0 && nums[i] == nums[i - 1]) {  
                continue;  
            }  
  
            // 如果当前4个数之和已经大于目标值,则无需继续向后遍历  
            if (nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {  
                break;  
            }  
  
            // 如果当前数加上3个最大值仍然小于目标值,则无需继续遍历当前i  
            if (nums[i] + nums[n - 1] + nums[n - 2] + nums[n - 3] < target) {  
                continue;  
            }  
    
            for (int j = i + 1; j < n - 2; j++) {  
                // 跳过重复的数字  
                if (j > i + 1 && nums[j] == nums[j - 1]) {  
                    continue;  
                }  
  
                // 双指针,从两端向中间遍历(left, right)  
                int left = j + 1;  
                int right = n - 1;  
                while (left < right) {  
                    int sum = nums[i] + nums[j] + nums[left] + nums[right];  
  
                    // 如果和等于目标值  
                    if (sum == target) {  
                        // 将当前四元组添加到结果列表中  
                        result.add(Arrays.asList(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--;  
                        }  
  
                        // 移动指针,继续寻找  
                        left++;  
                        right--;  
                    }   
                    // 如果和小于目标值,移动左指针  
                    else if (sum < target) {  
                        left++;  
                    }   
                    // 如果和大于目标值,移动右指针  
                    else {  
                        right--;  
                    }  
                }  
            }  
        }  
  
        // 返回结果列表  
        return result;  
    }  
  
    // 主方法用于测试  
    public static void main(String[] args) {  
        Solution solution = new Solution();  
        int[] nums = {1, 0, -1, 0, -2, 2};  
        int target = 0;  
        List<List<Integer>> result = solution.fourSum(nums, target);  
        for (List<Integer> quadruplet : result) {  
            System.out.println(quadruplet);  
        }  
    }  
}

Python代码示例:

from typing import List  
  
def four_sum(nums: List[int], target: int) -> List[List[int]]:  
    # 初始化结果列表  
    result = []  
      
    # 如果数组长度小于4,直接返回空列表  
    if len(nums) < 4:  
        return result  
      
    # 对数组进行排序  
    nums.sort()  
      
    n = len(nums)  
      
    # 固定前两个数(i, j)  
    for i in range(n - 3):  
        # 跳过重复的数字  
        if i > 0 and nums[i] == nums[i - 1]:  
            continue  
          
        # 如果当前两个数之和已经大于目标值,则无需继续向后遍历  
        if nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target:  
            break  
          
        # 如果当前两个数之和加上剩余所有数的最小值和最大值仍然小于目标值,则无需继续遍历当前i  
        if nums[i] + nums[n - 1] + nums[n - 2] + nums[n - 3] < target:  
            continue  
          
        # 固定第三个数(j)  
        for j in range(i + 1, n - 2):  
            # 跳过重复的数字  
            if j > i + 1 and nums[j] == nums[j - 1]:  
                continue  
              
            # 双指针,从两端向中间遍历(left, right)  
            left = j + 1  
            right = n - 1  
            while left < right:  
                total = nums[i] + nums[j] + nums[left] + nums[right]  
                  
                # 如果四个数的和等于目标值  
                if total == target:  
                    # 将当前四元组添加到结果列表中  
                    result.append([nums[i], nums[j], nums[left], nums[right]])  
                      
                    # 跳过重复的数字  
                    while left < right and nums[left] == nums[left + 1]:  
                        left += 1  
                    while left < right and nums[right] == nums[right - 1]:  
                        right -= 1  
                      
                    # 移动指针,继续寻找  
                    left += 1  
                    right -= 1  
                  
                # 如果和小于目标值,移动左指针  
                elif total < target:  
                    left += 1  
                  
                # 如果和大于目标值,移动右指针  
                else:  
                    right -= 1  
      
    # 返回结果列表  
    return result  
  
# 测试代码  
nums = [1, 0, -1, 0, -2, 2]  
target = 0  
print(four_sum(nums, target))

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千小凡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值