6.和为s的两个数
此题暴力解法还是暴力枚举,即将所有的情况一一列举进行判断;
我们在暴力枚举的基础上进行优化:
题目已知数组有序,我们可以利用双指针来解决这类问题:
当l的元素加上r的元素时,无非只有三种情况:
(1) l + r >targrt:
如上图:8 + 66 > 61,那么由于是递增数列.从8 ~ 66之间的数加上66就一定大于61,所以66与其之前的任何一个数相加一定都大于61,那么66这个数就不用判断,直接right--;
(2) l + r < target:
8 + 34小于61,那么8 加上 8 ~ 34之间的数一定都小于61,那么就不用一一枚举,直接left++即可
(3) l + r == target:
直接返回即可
题解:
class Solution {
public int[] twoSum(int[] price, int target) {
int left = 0;
int right = price.length - 1;
int[] ret = new int[2];
while(left < right){
int sum = price[left] + price[right];
if(sum < target){
left++;
} else if(sum > target){
right--;
}else{
ret[0] = price[left];
ret[1] = price[right];
break;
}
}
return ret;
}
}
7.三数之和为0
同样,i此题的暴力解法就是一一枚举,每次比较三个数的和与target的值是否相等,但是时间复杂度来到O(n^3),再加上题目要求的去重,时间复杂度就很大;
但是我们可以在暴力枚举的方法上进行优化:
(1)我们可以先将数组进行排序,以便后面舍去一些没必要枚举的
(2)前面我们做过两数之和的题目,那么很容易想到的就是:先固定一个数,在这个数之后,找到两数之和为这个数的相反数的结果即可,那么就用双指针算法
(3)不漏,与两数和题目不同的是:我们找到和为-target的两个数后,不该停止,而是left继续++,right继续--,直到二者相遇
(4)去重:
当我们找到一组后,那么再left继续++和right继续--时,如果遇到和之前相同的数,那么直接跳过即可,因为遇到和之前相同的数就一定会重复
并且:
当我们固定好-1并且找到结果后,会发现下一个数还是-1,那么如果继续枚举必然会出现重复的情况,因此也要跳过
(5)我们会发现,当数组是递增的时候,如果target是整数,那么target后面的数必定是正数,那么不可能会有两数之和等于-target的情况,那么后面就都不用考虑了
题解:
class Solution {
public static List<List<Integer>> threeSum(int[] nums){
Arrays.sort(nums);
int n = nums.length;
List<List<Integer>> ret = new ArrayList<>();
for(int i = 0; i < n - 2;){
if(nums[i] > 0){
break;
}
int left = i + 1;
int right = n - 1;
int targer = -nums[i];
while(left < right){
if(nums[left] + nums[right] < targer){
left++;
} else if (nums[left] + nums[right] > targer) {
right--;
}else{
ret.add(new ArrayList<Integer>(Arrays.asList(nums[left],nums[right],nums[i])));
left++;
right--;
while(left < right && nums[left] == nums[left-1]){
left++;
}
while(left < right && nums[right] == nums[right+1]){
right--;
}
}
}
i++;
while (nums[i] == nums[i-1] && i < n - 2){
i++;
}
}
return ret;
}
}
8.四数之和
同样:暴力枚举的方法很容易想到,但是时间复杂度达到O(n^4)
我们结合三数之和的思想,可以先固定一个数,再固定一个数,接着利用双指针进行双数之和查找
那么剩下的只是代码问题:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> ret = new ArrayList<>();
int n = nums.length;
for(int i = 0; i < n - 3;){
for(int j = i + 1; j < n - 2;){
int left = j+1;
int right = n - 1;
int t = target - nums[i] - nums[j];
while(left < right){
long sum = nums[left] + nums[right];
if(sum < t){
left++;
}else if(sum > t){
right--;
}else{
ret.add(Arrays.asList(nums[left],nums[right],nums[i],nums[j]));
left++;
right--;
while(nums[left] == nums[left-1] && left < right){
left++;
}
while(nums[right] == nums[right+1] && left < right){
right--;
}
}
}
j++;
while(nums[j] == nums[j-1] && j < n-2){
j++;
}
}
i++;
while(nums[i] == nums[i-1] && i < n-3){
i++;
}
}
return ret;
}
}