三数之和的解法(附java和python代码)

目录

背景

解题思路

基本问题

衍生问题


背景

三数之和的题目和题目是求解一个数组中满足三数之和等于0的数组的个数。

一般变形有以下几种:

1、求解三数之和等于某个固定目标值的三元数组

2、求解四数之和等于某个固定目标值的四元数组

3、求解与某个目标值最为接近的三元数组

解题思路

三数之和问题的一般套路是排序+双指针法。四元数组解法一般是在三元数组解法基础上套上一层循环。因此这篇主要就详细套路三元数组和问题。

基本问题

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组
示例 1:


输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

思路:

1、需要先对数组进行排序,因为考察的不是排序算法,所以可以调用函数直接排序(如果想自己写也是可以的),以数组[-1,0,1,2,-1,-4]举例子。

 排序后:

 2、准备3个指针

【指针I】从数组的头遍历到数组的尾部。【指针L】从【指针I】+ 1的位置开始,【指针R】从数组的尾部开始。

最开始的三指针位置:

三数之和的解法(附java和python代码)_第1张图片

 【指针I】是最外层循环,从数组头部依次遍历到数组尾部

【指针L】运动轨迹是从【指针I】下一个位置开始向右滑动,直到遇到【指针R】

【指针R】运动轨迹是从 数组尾部开始向左滑动,直到遇到【指针L】

注意,三个指针不能重叠,指向不同的数,且【指针I】< 【指针L】< 【指针R】

3、三指针移动标准:

a、 如果三指针指向的数据和 = 0; 收集此时的答案。并且【指针L】+1,【指针R】-1;

b、如果三指针指向的数据和 > 0,说明此时的答案偏大,把【指针R】-1;

c、如果三指针指向的数据和 < 0,说明此时的答案偏小,把【指针L】+1

d、左右指针重合或者交错,【指针I】+1,【指针L】= 【指针I】+1,【指针R】= length-1

下面将展示移动过程:

图I

三数之和的解法(附java和python代码)_第2张图片

 三数之和的解法(附java和python代码)_第3张图片

 三数之和的解法(附java和python代码)_第4张图片

 指针交错,【指针I】+1,【指针L】= 【指针I】+1,【指针R】= length-1三数之和的解法(附java和python代码)_第5张图片

三数之和的解法(附java和python代码)_第6张图片

三数之和的解法(附java和python代码)_第7张图片

 这一步收集答案时,发现已经存在这样的组合,所以不再重复收集三数之和的解法(附java和python代码)_第8张图片

三数之和的解法(附java和python代码)_第9张图片

   指针交错,【指针I】+1,【指针L】= 【指针I】+1,【指针R】= length-1三数之和的解法(附java和python代码)_第10张图片

 三数之和的解法(附java和python代码)_第11张图片

三数之和的解法(附java和python代码)_第12张图片

下面的过程不再重复展示。

Java代码: 

class Solution {
    public List> threeSum(int[] nums) {
        List> result = new ArrayList<>();
        Arrays.sort(nums);
        for(int i=0; i list = new ArrayList<>();
                    for(int k=0; k

Python代码

class Solution(object):
    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        nums = sorted(nums)
        for i in range(0, len(nums)):
            a = nums[i]
            left = i + 1
            right = len(nums) - 1
            while left < right:
                target = a + nums[left] + nums[right]
                if target == 0:
                    arr = [a, nums[left], nums[right]]
                    if arr not in res:
                        res.append(arr)
                    left += 1
                    right -= 1
                elif target < 0:
                    left += 1
                else:
                    right -= 1
        return res

衍生问题1最接近的三数之和

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。

返回这三个数的和。

假定每组输入只存在恰好一个解。

示例 1:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

示例 2:

输入:nums = [0,0,0], target = 1
输出:0

提示:

3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-104 <= target <= 104

思路:

1、在基础问题的基础上准备两个变量,minClose 和maxClose, 意思是比target小且最接近target的数以及比target大且最接近target的数

三指针移动标准:

a、 如果三指针指向的数据和 = target ,返回target,终止程序

b、如果三指针指向的数据和 > target,说明此时的答案偏大,把【指针R】-1,并且与maxClose做比较,如果此时的值更接近target,更新maxClose

c、如果三指针指向的数据和 < target,说明此时的答案偏小,把【指针L】+1,并且与minClose做比较,如果此时的值更接近target,更新minClose

d、左右指针重合或者交错,【指针I】+1,【指针L】= 【指针I】+1,【指针R】= length-1

e、最终比较minClose和maxClose哪个更接近target

Java代码

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        int minClose = Integer.MIN_VALUE;
        int maxClose = Integer.MAX_VALUE;
        Arrays.sort(nums);
        if(nums[0]+nums[1]+nums[2]>=target){
            return nums[0]+nums[1]+nums[2];
        }
        if(nums[nums.length-1] + nums[nums.length-2] + nums[nums.length-3]<=target){
            return nums[nums.length-1] + nums[nums.length-2] + nums[nums.length-3];
        }
        for(int i=0; iminClose){
                        minClose = tmp;
                    }
                }else if(tmp>target){
                    right --;
                    if(tmp

Python代码


class Solution(object):
    def threeSumClosest(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        minClose =  - (1<<31)
        maxClose = 1<<31
        nums = sorted(nums)
        if nums[0] + nums[1] + nums[2] >= target:
            return nums[0] + nums[1] + nums[2]
        
        if nums[-1] + nums[-2] + nums[-3] <= target:
            return nums[-1] + nums[-2] + nums[-3]
        for i in range(0, len(nums)):
            left = i + 1
            right = len(nums) - 1
            while left < right:
                tmp = nums[i] + nums[left] + nums[right]
                if tmp < target:
                    left += 1
                    if tmp > minClose:
                        minClose = tmp 
                elif tmp > target:
                    right -= 1
                    if tmp < maxClose:
                        maxClose = tmp
                else:
                    maxClose = target 
                    minClose = target 
                    return target
        return minClose if abs(target-minClose) < abs(target-maxClose) else maxClose

衍生问题2四数之和

解题思路:

1、在三数之和的基础上再添上一层循环

2、由于代码不过,对于数据状况特别差的两种情况做额外处理,如果target>0 且 nums中的值都<0,则没有满足要求的组合。如果target<0 且nums中的值都>0,也没有满足要求的组合
Java代码:

class Solution {
    public List> fourSum(int[] nums, int target) {
        List> result = new ArrayList<>();
        Arrays.sort(nums);
        if(target>0){
            boolean flg = false;
            for(int i=0; i0){
                    flg = true;
                }
            }
            if(!flg){
                return result;
            }
        }
        if(target<0){
            boolean flg = false;
            for(int i=0; i> result){
        for(int idx=start+1; idx resTmp = new ArrayList<>();
                resTmp.add(nums[start]);
                resTmp.add(nums[idx]);
                resTmp.add(nums[left]);
                resTmp.add(nums[right]);
                if(tmp==target){
                    if(!result.contains(resTmp)){
                        result.add(resTmp);
                    }
                    left ++;
                    right --;
                }else if(tmp>target){
                    right --;
                }else {
                    left ++;
                }
            }
        }
    }
}

Python代码:


class Solution(object):
    def fourSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[List[int]]
        """
        result = []
        nums = sorted(nums)
        if target > 0:
            flg = False
            for i in range(len(nums)):
                if nums[i] > 0:
                    flg = True
                    break
            if not flg:
                return result
        if target < 0:
            flg = False
            for i in range(len(nums)):
                if nums[i] < 0:
                    flg = True
                    break
            if not flg:
                return result
        for i in range(len(nums)):
            self.process(nums, target-nums[i], i, result)
        return result
    
    def process(self, nums, target, start, result):
        for idx in range(start+1, len(nums)):
            left = idx + 1
            right = len(nums) - 1
            while left < right:
                tmp = nums[idx] + nums[left] + nums[right]
                resTmp = [nums[start], nums[idx], nums[left], nums[right]]
                if tmp == target:
                    if resTmp not in result:
                        result.append(resTmp[:])
                    left += 1
                    right -= 1
                elif tmp > target:
                    right -= 1
                else:
                    left += 1

你可能感兴趣的:(学习笔记,随便写点,leetcode)