Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 07dbe0c

Browse files
author
scuyjzh
committed
modify solutions to problem - "259. 3Sum Smaller"
1 parent 5bf0cef commit 07dbe0c

File tree

2 files changed

+12
-67
lines changed

2 files changed

+12
-67
lines changed

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,7 @@
227227
| 18 | [四数之和](https://leetcode-cn.com/problems/4sum/) | [Java](./src/com/scuyjzh/leetcode/medium/No_0018_4Sum/Solution.java) | 中等 | 数组 双指针 排序 |
228228
| 42 | [接雨水](https://leetcode-cn.com/problems/trapping-rain-water/) | [Java](./src/com/scuyjzh/leetcode/hard/No_0042_Trapping_Rain_Water/Solution.java) | 困难 | 栈 数组 双指针 动态规划 单调栈 |
229229
| 658 | [找到 K 个最接近的元素](https://leetcode-cn.com/problems/find-k-closest-elements/) | [Java](./src/com/scuyjzh/leetcode/medium/No_0658_Find_K_Closest_Elements/Solution.java) | 中等 | 数组 双指针 二分查找 排序 堆(优先队列) |
230+
| 259 | [较小的三数之和](https://leetcode-cn.com/problems/3sum-smaller/) 🔒 | [Java](./src/com/scuyjzh/leetcode/medium/No_0259_3Sum_Smaller/Solution.java) | 中等 | 数组 双指针 二分查找 排序 |
230231

231232
### Array
232233

‎src/com/scuyjzh/leetcode/medium/No_0259_3Sum_Smaller/Solution.java‎

Lines changed: 11 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -11,107 +11,51 @@
1111
*/
1212
class Solution {
1313
/**
14-
* 方法一:二分查找
15-
*
16-
* • 时间复杂度:O(N^2logN)。枚举 i 和 j 各需要 O(N) 的时间复杂度,二分查找 k 需要 O(logN) 的时间复
17-
* 杂度,因此总的时间复杂度为 O(N^2logN)。
18-
* • 空间复杂度:O(1)。
14+
* 方法:双指针
1915
*/
20-
public int threeSumSmaller1(int[] nums, int target) {
16+
public int threeSumSmaller(int[] nums, int target) {
2117
/*
22-
* 首先考虑更简单的情况。题目中要求的是三元组 (i,j,k),可以首先尝试一个简单的版本,求出二元
23-
* 组 (i,j)。即
24-
* 给定一个长度为 n 的数组 nums,找出所有的二元组 (i,j) 的数目,满足 0≤i<j<n 且 nums[i]+
25-
* nums[j]<target。
18+
* 首先考虑更简单的情况。题目中要求的是三元组 (i,j,k),可以首先尝试一个简单的版本,求出二元组 (i,j)。
2619
*
27-
* 在这个简化的问题中,首先对数组进行排序,随后从小到大枚举 i,并用二分查找,找出最大的满足
28-
* nums[i]+nums[j]<target 的 j,那么就可以知道对于当前的 i,有 j−i 对二元组是满足要求的。
29-
*
30-
* 解决了二元组的问题后,可以发现,在问题变成三元组时,只要在二元组的算法框架外部再套上一层循
31-
* 环就行了。也就是说,从小到大枚举 i 和 j,规定 i<j,随后在数组上二分查找,找出最大的满足
32-
* nums[i]+nums[j]+nums[k]<target 的 k,那么对于当前的 i 和 j,有 k−j 对三元组是满足要求的。
33-
*/
34-
Arrays.sort(nums);
35-
int sum = 0;
36-
for (int i = 0; i < nums.length - 2; ++i) {
37-
sum += twoSumSmaller1(nums, i + 1, target - nums[i]);
38-
}
39-
return sum;
40-
}
41-
42-
private int twoSumSmaller1(int[] nums, int startIndex, int target) {
43-
int sum = 0;
44-
for (int i = startIndex; i < nums.length - 1; ++i) {
45-
int j = binarySearch(nums, i, target - nums[i]);
46-
sum += j - i;
47-
}
48-
return sum;
49-
}
50-
51-
private int binarySearch(int[] nums, int startIndex, int target) {
52-
int left = startIndex;
53-
int right = nums.length - 1;
54-
while (left < right) {
55-
int mid = (left + right + 1) / 2;
56-
if (nums[mid] < target) {
57-
left = mid;
58-
} else {
59-
right = mid - 1;
60-
}
61-
}
62-
return left;
63-
}
64-
65-
/**
66-
* 方法二:双指针
67-
*
68-
* • 时间复杂度:O(N^2)。在每一步中,要么 left 向右移动一位,要么 right 向左移动一位。当 left≥right
69-
* 时循环结束,因此它的时间复杂度为 O(N)。加上外层的循环,总的时间复杂度为 O(N^2)。
70-
* • 空间复杂度:O(1)。
71-
*/
72-
public int threeSumSmaller2(int[] nums, int target) {
73-
/*
74-
* 在方法一中,首先解决了一个简化版的问题,随后在外部套上一层循环,就可以解决当前的问题。如果
75-
* 能找出更好的解决简化版的问题的方法,就能在更低的时间复杂度内解决当前的问题。
76-
*
77-
* 首先仍然对数组进行排序,例如 nums=[3,5,2,8,1] 排序后变成 [1,2,3,5,8]。target 的值为 7。
20+
* 首先对数组进行排序,例如 nums=[3,5,2,8,1] 排序后变成 [1,2,3,5,8]。target 的值为 7。
7821
* [1, 2, 3, 5, 8]
7922
* ↑ ↑
8023
* left right
24+
*
8125
* 用两个指针 left 和 right 分别指向数组中的第一个和最后一个元素,它们的和为 1+8=9>target,这
8226
* 说明 right 不能出现在二元组中(因为 left 只向左移动,如果此时二者的和已经大于 target,那么在 left 移
8327
* 动的过程中,二者的和就不可能小于 target 了),因此需要将 right 向左移动一位。
8428
* [1, 2, 3, 5, 8]
8529
* ↑ ↑
8630
* left right
31+
*
8732
* 现在二者的和为 1+5=6<target,那么对于当前的 left,应当有 right−left=3 对二元组满足要求,它们
8833
* 分别为 (1,2),(1,3),(1,5)。在这之后,将 left 向右移动一位。
8934
*/
9035
Arrays.sort(nums);
9136
int sum = 0;
9237
for (int i = 0; i < nums.length - 2; i++) {
93-
sum += twoSumSmaller2(nums, i + 1, target - nums[i]);
38+
sum += twoSumSmaller(nums, i + 1, target - nums[i]);
9439
}
9540
return sum;
9641
}
9742

98-
private int twoSumSmaller2(int[] nums, int startIndex, int target) {
43+
private int twoSumSmaller(int[] nums, int startIndex, int target) {
9944
int sum = 0;
10045
int left = startIndex;
10146
int right = nums.length - 1;
10247
while (left < right) {
10348
if (nums[left] + nums[right] < target) {
10449
sum += right - left;
105-
left++;
50+
++left;
10651
} else {
107-
right--;
52+
--right;
10853
}
10954
}
11055
return sum;
11156
}
11257

11358
public static void main(String[] args) {
114-
System.out.println(new Solution().threeSumSmaller1(new int[]{-2, 0, 1, 3}, 2));
115-
System.out.println(new Solution().threeSumSmaller2(new int[]{-2, 0, 1, 3}, 2));
59+
System.out.println(new Solution().threeSumSmaller(new int[]{-2, 0, 1, 3}, 2));
11660
}
11761
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /