-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy path15.三数之和.js
91 lines (74 loc) · 2.98 KB
/
15.三数之和.js
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/*
* @lc app=leetcode.cn id=15 lang=javascript
*
* [15] 三数之和
*/
// @lc code=start
/**
* @param {number[]} nums
* @return {number[][]}
*/
var threeSum = function(nums) {
const results = []
// obviously irrelevant if we don't have at least 3 numbers to play with!
if (nums.length < 3) return results
// having the numbers in ascending order will make this problem much easier.
// also, knowing the overall problem will take at least O(N^2) time, we can
// afford the O(NlogN) sort operation
nums = nums.sort((a, b) => a - b)
// if the question asks us for a custom target, we can control it here
let target = 0
for (let i = 0; i < nums.length - 2; i++) {
// `i` represents the "left" most number in our sorted set.
// once this number hits 0, there's no need to go further since
// positive numbers cannot sum to a negative number
if (nums[i] > target) break
// we don't want repeats, so skip numbers we've already seen
if (i > 0 && nums[i] === nums[i - 1]) continue
// `j` represents the "middle" element between `i` and `k`.
// we will increment this up through the array while `i` and `k`
// are anchored to their positions. we will decrement `k` for
// for each pass through the array, and finally increment `i`
// once `j` and `k` meet.
let j = i + 1
// `k` represents the "right" most element
let k = nums.length - 1
// to summarize our setup, we have `i` that starts at the beginning,
// `k` that starts at the end, and `j` that races in between the two.
//
// note that `i` is controlled by our outer for-loop and will move the slowest.
// in the meantime, `j` and `k` will take turns inching towards each other depending
// on some logic we'll set up below. once they collide, `i` will be incremented up
// and we'll repeat the process.
while (j < k) {
let sum = nums[i] + nums[j] + nums[k]
// if we find the target sum, increment `j` and decrement `k` for
// other potential combos where `i` is the anchor
if (sum === target) {
// store the valid threesum
results.push([nums[i], nums[j], nums[k]])
// this is important! we need to continue to increment `j` and decrement `k`
// as long as those values are duplicated. in other words, we wanna skip values
// we've already seen. otherwise, an input array of [-2,0,0,2,2] would result in
// [[-2,0,2], [-2,0,2]].
//
// (i'm not a fan of this part because we're doing a while loop as we're
// already inside of another while loop...)
while (nums[j] === nums[j + 1]) j++
while (nums[k] === nums[k - 1]) k--
// finally, we need to actually move `j` forward and `k` backward to the
// next unique elements. the previous while loops will not handle this.
j++
k--
// if the sum is too small, increment `j` to get closer to the target
} else if (sum < target) {
j++
// if the sum is too large, decrement `k` to get closer to the target
} else { // (sum > target)
k--
}
}
}
return results
};
// @lc code=end