-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathP0016_ThreeSumClosest.java
More file actions
143 lines (131 loc) · 6.72 KB
/
P0016_ThreeSumClosest.java
File metadata and controls
143 lines (131 loc) · 6.72 KB
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package yyl.leetcode.p00;
import java.util.Arrays;
/**
* <h3>最接近的三数之和</h3><br>
* 给定一个包括 n 个整数的数组 nums 和 一个目标值 target。<br>
* 找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。<br>
*
* <pre>
* 示例:
* 输入:nums = [-1,2,1,-4], target = 1
* 输出:2
* 解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
*
* 提示:
* 3 <= nums.length <= 10^3
* -10^3 <= nums[i] <= 10^3
* -10^4 <= target <= 10^4
* </pre>
*/
public class P0016_ThreeSumClosest {
public static void main(String[] args) {
Solution solution = new Solution();
System.out.println(solution.threeSumClosest(new int[] { 1, 1, 1 }, 0));// 3
System.out.println(solution.threeSumClosest(new int[] { -1, 2, 1, -4 }, 1));// 2
System.out.println(solution.threeSumClosest(new int[] { -55, -24, -18, -11, -7, -3, 4, 5, 6, 9, 11, 23, 33 }, 0));// 0
System.out.println(solution.threeSumClosest(new int[] { 0, 2, 1, -3 }, 1));// 0
}
// 排序+双指针
// 1、先让数组有序(对数组排序)
// 2、枚举第一个元素 a,然后使 b+c 接近 target−a
// 3、借助双指针,对 b+c 枚举的过程进行优化
// 4、对超越界限的问题进行优化处理
// 时间复杂度:O(N^2),其中 N 是数组 nums 的长度。我们首先需要 O(NlogN) 的时间对数组进行排序,随后在枚举的过程中,使用一重循环 O(N) 枚举 a ,双指针 O(N) 枚举 b和 c,故一共是 O(N^2)。
// 空间复杂度:O(logN)。排序需要使用 O(logN) 的空间。
static class Solution {
public int threeSumClosest(int[] nums, int target) {
// 利用 Arrays.sort对数组进行排序
Arrays.sort(nums);
// 初始化一个用于保存结果的值 result = nusm[0] + nums[1] + nums[2]
int result = nums[0] + nums[1] + nums[2];
// 利用下标 i 对数组进行遍历,此时就是在固定第一个元素,注意,下标 i 的边界为 i < nums.length-2,否则设置指针的时候会出现数组越界
for (int i = 0; i < nums.length - 2; i++) {
// 每次遍历的过程中设置两个指针,分别是 left = i + 1、right = nums.length - 1
int left = i + 1;
int right = nums.length - 1;
// 双指针遍历 (如果 left==right,说明我们已经将所有的元素都遍历过一遍了)
while (left < right) {
// 判断最小值(优化点)
int min = nums[i] + nums[left] + nums[left + 1];
if (target < min) {
if (Math.abs(result - target) > Math.abs(min - target)) {
result = min;
}
break;
}
// 判断最大值(优化点)
int max = nums[i] + nums[right] + nums[right - 1];
if (target > max) {
if (Math.abs(result - target) > Math.abs(max - target)) {
result = max;
}
break;
}
// 获得三个数之和
int sum = nums[i] + nums[left] + nums[right];
// 如果 sum 之前保存的 result与 target 更接近就更新 result
if (Math.abs(sum - target) < Math.abs(result - target)) {
result = sum;
}
// 移动双指针
// 如果 sum 的值比 target 大,那么 right--
if (sum > target) {
right--;
// 元素重复,继续移动指针(优化点)
while (left != right && nums[right] == nums[right + 1]) {
right--;
}
}
// 如果 sum 的值 target 小,那么 left++
else {
left++;
// 元素重复,继续移动指针(优化点)
while (left != right && nums[left] == nums[left - 1]) {
left++;
}
}
}
}
return result;
}
}
// 双指针法
// 先让数组有序(对数组排序),然后每次固定一个元素,再去寻找另外两个元素
static class Solution2 {
public int threeSumClosest(int[] nums, int target) {
// 利用 Arrays.sort对数组进行排序
Arrays.sort(nums);
// 初始化一个用于保存结果的值 result = nusm[0] + nums[1] + nums[2]
int result = nums[0] + nums[1] + nums[2];
// 利用下标 i 对数组进行遍历,此时就是在固定第一个元素,注意,下标 i 的边界为 i < nums.length-2,否则设置指针的时候会出现数组越界
for (int i = 0; i < nums.length; i++) {
// 每次遍历的过程中设置两个指针,分别是 left = i + 1、right = nums.length - 1
int left = i + 1;
int right = nums.length - 1;
// 双指针遍历 (如果 left==right,说明我们已经将所有的元素都遍历过一遍了)
while (left < right) {
// 获得三个数之和 sum = nums[i] + nums[left] + nums[right]
int sum = nums[i] + nums[left] + nums[right];
// 如果三个数之和与目标相等那么直接返回(相等必然最接近)
if (sum == target) {
return sum;
}
// 如果 sum 之前保存的 result与 target 更接近就更新 result
if (Math.abs(sum - target) < Math.abs(result - target)) {
result = sum;
}
// 移动双指针
// 如果 sum 的值比 target 大,那么 right--,因为数组是有序的,right --会使得下一次的 sum 更小,也就更接近 target 的值
if (sum > target) {
right--;
}
// 否则,如果 sum 的值 target 小,那么 left++
else {
left++;
}
}
}
return result;
}
}
}