Contents

3sum

Problem description

Analyse

这道题难点在于不重复的三元组,但是三重枚举后不断通过哈希去去重的消耗太高不合适。解决这个难点的可以先将数组进行排序,然后按照顺序去枚举当遇到相同的元素时,直接跳过,这样就避免了之后需要哈希去重的麻烦事。 这道题的三重枚举可以优化成两重。当 a+b+c = 0(a<=b<=c),在进行下一次二重枚举的若有满足条件的组合,会有 a+b`+c`=0(b`>b && c`<c) 这意味着,我们不必在第三重枚举时枚举所有剩下的元素,只需要枚举比上一次满足要求组合中比c小的元素即可。 我们可以采用双指针的思想,让第二轮的second 固定,不断向左平移thrid下标

Implement

 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
36
37
38
39
40
41
42
43
44
45
package main

import (
    "fmt"
    "sort"
)

func threeSum(nums []int) [][]int {

    if len(nums) < 3 {
        return [][]int{}
    }

    result := [][]int{}
    sort.Ints(nums)

    for i := 0; i <= len(nums)-3; i++ {
        if i > 0 && nums[i] == nums[i-1] {
            continue
        }

        k := len(nums) - 1
        target := -1 * nums[i]

        for j := i + 1; j <= len(nums)-2; j++ {
            if j > i+1 && nums[j] == nums[j-1] {
                continue
            }

            for j < k && nums[j]+nums[k] > target {
                k--
            }

            if j == k {
                break
            }

            if nums[j]+nums[k] == target {
                result = append(result, []int{nums[i], nums[j], nums[k]})
            }

        }
    }
    return result
}
 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
36
37
38
39
40
41
42
43
44
45
#include <algorithm>
#include <vector>

using namespace std;
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {

        vector<vector<int>> result;

        if (nums.size() < 3) {
            return result;
        }

        sort(nums.begin(),nums.end());

        for (int i=0; i<nums.size(); ++i) {
            if (i>0 && nums[i]==nums[i-1]) {
                continue;
            }

            int third = nums.size()-1;
            int target = -nums[i];

            for (int j=i+1; j<nums.size(); j++) {
                if (j>i+1 && nums[j] == nums[j-1]) {
                    continue;
                }

                while(j<third && nums[j]+nums[third] > target){
                    third--;
                }

                if (third == j) {
                    break;
                }

                if(nums[j]+nums[third] == target){
                    result.push_back({nums[i],nums[j],nums[third]});
                }
            }
        }
        return result;
    }
};

Summery

解题的时候还是应该多多思考题目已知条件所带来的一些性质,这题就用到了数字可以排序的性质来解决重复枚举的问题。新的第三轮的枚举值必定小于上一次成功的第三轮枚举值,可以用来优化代码。