三数之和

leetcode-15 来源 https://leetcode-cn.com/problems/3sum/

思路

排序预处理后,设置两个指针i,j 其中j = i + 1, i 遍历数组,剩下一个元素用二分法查找;

my ugly code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
func threeSum(nums []int) [][]int {
    sort.Ints(nums)  // O(nlogn)
    res := [][]int{}
 
    for i := 0; i < len(nums)-2; i++ {  // O(n^2)
        n1 := nums[i]
        if n1 > 0 {   // 第一个数大于0, 后面的数都比它大,不成立
            break
        }
        // 去掉重复情况
        if i > 0 && n1 == nums[i-1] {
            continue
        }
        l, r := i+1, len(nums)-1  // left, right
        for l < r {
            n2, n3 := nums[l], nums[r]
            if n1+n2+n3 == 0 {
                res = append(res, []int{n1, n2, n3})
                
                // 现在要增加 left,减小 right,但是不能重复,比如: [-2, -1, -1, -1, 3, 3, 3], i = 0, left = 1, right = 6, [-2, -1, 3] 的答案加入后,需要排除重复的 -1 和 3
                for l < r && nums[l] == n2 {
                    l++
                }
                for l < r && nums[r] == n3 {
                    r--
                }
            }else if n1+n2+n3 < 0 {
                l++
            }else {  // nums[left] + nums[right] > target
                r--
            }
        }
    }
    return res
}

总时间复杂度 O(n^2)的复杂度;

高手思路赏析

解题思路

  • 标签:数组遍历 首先对数组进行排序,排序后固定一个数 nums[i],再使用左右指针指向 nums[i]后面的两端,数字分别为 nums[L]和 nums[R],计算三个数的和 sum判断是否满足为 0,满足则添加进结果集 如果 nums[i]大于 0,则三数之和必然无法等于 0,结束循环 如果 nums[i]= nums[i-1],则说明该数字重复,会导致结果重复,所以应该跳过 当 sum == 0 时,nums[L] = nums[L+1] 则会导致结果重复,应该跳过,L++ 当 sum = 0 时,nums[R] = nums[R−1] 则会导致结果重复,应该跳过,R– 时间复杂度:O(n^2) ,n 为数组长度
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
    public static List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> ans = new ArrayList();
        int len = nums.length;
        if(nums == null || len < 3) return ans;
        Arrays.sort(nums); // 排序
        for (int i = 0; i < len ; i++) {
            if(nums[i] > 0) break; // 如果当前数字大于0,则三数之和一定大于0,所以结束循环
            if(i > 0 && nums[i] == nums[i-1]) continue; // 去重
            int L = i+1;
            int R = len-1;
            while(L < R){
                int sum = nums[i] + nums[L] + nums[R];
                if(sum == 0){
                    ans.add(Arrays.asList(nums[i],nums[L],nums[R]));
                    while (L<R && nums[L] == nums[L+1]) L++; // 去重
                    while (L<R && nums[R] == nums[R-1]) R--; // 去重
                    L++;
                    R--;
                }
                else if (sum < 0) L++;
                else if (sum > 0) R--;
            }
        }        
        return ans;
    }
}

图解