算法题6:三数之和

题目描述:

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != 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、首先想到的是三重循环,第一层循环确定a,第二层确定b,第三层确定c,然后想办法简单化,使循环层数减少
2、题目要求不能重复,那么为了不重复,有两个点可以帮助我们减少计算时间,首先可以把数组从小到大排序,这样可以保证小的在前面大的在后面便于判断,其次每重循环相邻两次循环的数不能相同否则会重复,如[-1,-1,-1,0,1,2]得到一个组合[-1,-1,0],第一层循环遍历到第二个数-1时就要跳过去,
否则还会得到[-1,-1,0]就重复了,因此每层循环可以减少循环此次,即相邻元素相同时则跳过
3、第三重循环可以改为和第二重循环并列的关系,通过双指针的方法,第一层循环固定一个数后(a、b、c中的左边的a),第二重循环和第三重循环可以一边从左右到右,另一边从有到左,像两个指针由两边ian同时往中间找b和c,c肯定比b大,当两个指针重合则进入下一次循环
 

python

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        
        n=len(nums)
        res=[]
        nums.sort()
        for first in range(len(nums)):
            third = n - 1 # 右侧指针
            if first > 0 and nums[first] == nums[first - 1]: # 和前一个一样则跳出,去掉重复项
                continue 
            for second in range(first + 1, n):
                if second > first + 1 and nums[second] == nums[second - 1]: # 如果和前面数一样则跳过
                    continue
                # 进行计算,如果nums[second] + nums[third] > -nums[first] 则有指针向左移动1
                while (second < third and nums[second] + nums[third] > -nums[first]):
                    third -= 1
                if second == third: # 指针重合后退出
                    break
                if nums[second] + nums[third] == -nums[first]:
                    res.append([nums[first], nums[second], nums[third]])
        return res

结果:

 

java:

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        for (int first = 0; first < n; ++first) {
            // 需要和上次枚举的数不同
            if (first > 0 && nums[first] == nums[first - 1]) {
                continue;
            }
            // c对应的指针指向数据最右侧
            int third = n - 1;
            
            for (int second = first + 1; second < n; ++second) {
                // 需和上次枚举的数不同
                if (second > first + 1 && nums[second] == nums[second - 1]){
                    continue;
                }
                // 需保证b的指针在c指针的左侧
                while (second < third && nums[second] + nums[third] > -nums[first]) {
                    --third;
                }
                if (second == third) {
                    break;
                }
                if (nums[second] + nums[third] == -nums[first]) {
                    List<Integer> list = new ArrayList<Integer>();
                    list.add(nums[first]);
                    list.add(nums[second]);
                    list.add(nums[third]);
                    res.add(list);
                }
            }
        }
        return res;
    }
}

结果:

 

 

posted @ 2025-04-30 09:28  夏晓旭  阅读(18)  评论(0)    收藏  举报