正文
这种题目没有什么复杂的算法逻辑,也用不到动态规划,考察的就是一个思维能力,能想明白,就能写的出来。当然,最后落实在代码上还需要考略多种情况,逻辑严谨。
题目一:三个数之和
【源于LeetCode - 15】(中等)
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:
输入:nums = []
输出:[]
示例 3:
输入:nums = [0]
输出:[]
我的思路:
我的老师曾说过:“没有两个for循环解决不了的问题,如果有,就再加一个”。小编采用的是偏向暴力解法,冒泡排序的理念。事后看了看其他人的方案,对比下来,还是我写的这种更容易理解,时间和内存消耗中上水平,还不错。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
// 先排序,方便计算
Arrays.sort(nums);
// 把题干中的0当成变量设置,让代码更灵活
int sum = 0;
for (int i = 0;i < nums.length;i++) {
// 排序之后如果第一个元素已经大于 sum,那么无论如何组合都不可能凑成三元组
// 直接返回结果就可以了
if (nums[i] > sum) break;
// 错误去重方法,将会漏掉-1,-1,2 这种情况
// if (nums[i] == nums[i + 1]) continue;
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1, right = nums.length - 1;
while (right > left) {
int temp = nums[i] + nums[left] + nums[right];
if (temp == sum) {
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 去重用的
while (right > left && nums[left] == nums[left+1]) left++;
while (right > left && nums[right] == nums[right-1]) right--;
// 找到答案时,双指针同时收缩
left++;
right--;
} else if (temp > sum) {
right--;
} else {
left++;
}
}
}
return result;
}
}
题目二:最接近的三个数之和
【源于LeetCode - 16】(中等)
给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。返回这三个数的和。注意:假定每组输入只存在恰好一个解。
示例 1:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
示例 2:
输入:nums = [0,0,0], target = 1
输出:0
提示:
3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-104 <= target <= 104
我的思路:
这是 LeetCode - 15 题目的变形,思路是一样的,但是题目里没有将一定等于目标值,最接近的思路就是使用绝对值 Math.abs(),确保结果最接近。
class Solution {
public int threeSumClosest(int[] nums, int target) {
// 先排序
Arrays.sort(nums);
int min = nums[0] + nums[1] + nums[2];
for (int i = 0;i < nums.length;i++) {
// 设置左右指针
int left = i+1, right = nums.length-1;
while (right > left) {
int threeSum = nums[i] + nums[left] + nums[right];
// 计算最小绝对值的min
if (Math.abs(threeSum - target) < Math.abs(min - target)) {
min = threeSum;
}
if (threeSum > target) {
right--;
} else if (threeSum < target) {
left++;
} else {
// 如果已经等于 target 的话, 肯定是最接近的
return threeSum;
}
}
}
// 通知GC,本行代码影响不大
System.gc();
return min;
}
}