1、题目描述
2、解题思路
先不考虑三个数字的问题,把问题变为:较小的两个数之和,问题就简单多了。
首先对数组进行排序,假如数组为 nums = [3,5,2,8,1],找出和小于 7 的两个数的组合数。
排序后为 nums=[1,2,3,5,8];target = 7。
定义两个指针 left、right,初始时,left 指向 nums[0],right 指向最后一个元素;
因为 nums[0] + nums[4] = 1 + 8 > 7,太大了,需要小一点,于是 right 往左走一步;
接着 nums[0] + nums[3] = 1 + 5 = 6 < 7,符合要求,因此和小于 7 的组合数有 3 - 0 = 3 对。
现在回到原题:求较小的三数之和的组合数。
拿数组的一个数,比如 nums[0] 当作其中一个数,于是 target 就变为 target - nums[0],问题就转化为:从 nums[1] 到 nums[length-1] 中找到和小于 target - nums[0] 的两个数的组合数。
双指针法的复杂度为 O(N),因为只遍历一遍数组。接着让 nums 的每一个数字都当一次“其中一个数”,嵌套后,时间复杂度就为 O(N²)
3、解题代码
class Solution {
public int threeSumSmaller(int[] nums, int target) {
Arrays.sort(nums);
int sum = 0;
for (int i = 0; i < nums.length - 2; i++) {
sum += twoSumSmaller(nums, i + 1, target - nums[i]);
}
return sum;
}
/**
* 从 nums[] 的 startIndex 开始的元素中找到和小于 target 的两个数的组合数
* @param nums
* @param startIndex
* @param target
* @return
*/
private int twoSumSmaller(int[] nums, int startIndex, int target) {
int sum = 0;
int left = startIndex;
int right = nums.length - 1;
while (left < right) {
if (nums[left] + nums[right] < target) {
sum += right - left;
left++;
} else {
right--;
}
}
return sum;
}
}