算法原理
双指针
常见的双指针有两种形式,一种是对撞指针,一种是左右指针
对撞指针:一般用于顺序结构中,也称左右指针,对撞指针一般从两端向中间移动,终止条件一般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循环)
快慢指针:又叫龟兔赛跑算法,基本思想就是使用两个移动速度不同的指针在数组或链表等结构上移动(我们在数据结构学习链表解决链表有环问题的时候用到了这种算法)
题目解析
5.有效三角形的个数
https://leetcode.cn/problems/valid-triangle-number/
题目解析
给定一个包含非负整数的数组nums,返回其中可以组成三角形三条边的三元组个数
三角形两边之和大于第三边,两步之差小于第三边
如果a<=b<=c--->只要a+b>c就可以构成三角形
算法原理
解法一:暴力枚举
先固定一个数,然后再找两个数,三层for循环
时间复杂度较高
解法二:利用单调性,使用双指针算法
根据题目解析中"如果a<=b<=c--->只要a+b>c就可以构成三角形",并且题目中对返回的数字顺序并未要求,那么我们可以先对数组排序

数组此时已经按照从小到大的顺序排列,我们可以从后固定一个c,然后一个left,一个right指针进行移动
如果a+b>c 那么这个c对应着right-left种组合,中间的一定可以构成三角形 然后right--
如果a+b<=c,那么left左移
代码实现
public int triangleNumber(int[] nums) {
Arrays.sort(nums);
int n=nums.length;
int ret=0;
for(int c=n-1;c>=0;c--){
int left=0,right=c-1;
while(left<right){
if(nums[left]+nums[right]>nums[c]){
ret+=right-left;
right--;
}else{
left++;
}
}
}
return ret;
}
6.和为s的两个数
https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/description/
题目解析
输入一个递增的数组和一个数字s,在数组中查找两个数,使得他们的和正好为s,如果有多对,则随意输出一对即可
算法原理
解法一:暴力枚举 时间复杂度过高
for(int i=0;i<nums.length;i++)
for(int j=i+1;i<nums.length;j++)
check(nums[i]+nums[j],s]
解法二:利用单调性,使用双指针

代码实现
public int[] twoSum(int[] price, int t) {
int left=0,right=price.length-1,sum=0;
while(left<right){
sum=price[left]+price[right];
if(sum==t){
return new int[] {price[left],price[right]};
}else if(sum>t){
right--;
}else{
left++;
}
}
return new int[]{};
}
7.三数之和
https://leetcode.cn/problems/3sum/description/
题目解析
给一个整数数组nums,判断是否存在【nums【i】,nums【j】,nums【k】】,满足i!=k,j!=k,i!=j,同时三数相加为0,返回所有和为0且不重复的三元组(注意:输出的顺序和三元组的顺序并不重要)
算法原理
解法一:排序(因为题目说输出的顺序和三元组的顺序并不重要)+暴力枚举+set去重
解法二:排序+双指针

1.排序 2.固定一个数a(并且这个数要小于0,否则在已经有序的情况下不可能找到符合要求的两个数)
3.在该数后的区间。利用双指针算法,找到和为-a
ps:1.去重 找到一种结果之后,left和right必须要跳过重复的元素 使用完一次双指针算法后,i也要跳过重复的元素
2.不漏:找到一种结果后,不要停,缩小区间,继续寻找
代码实现
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ret=new ArrayList<>();
Arrays.sort(nums);
for(int i=0;i<nums.length-2;i++){
if(nums[i]>0) break;
int t=-nums[i];
if(i>0&&nums[i]==nums[i-1]) continue;
int left=i+1,right=nums.length-1;
while(left<right){
int sum=nums[left]+nums[right];
if(sum==t){
ret.add(new ArrayList<Integer>(Arrays.asList(nums[i],nums[left],nums[right])));
while(left<right&&nums[left]==nums[++left]);
while(left<right&&nums[right]==nums[--right]);
}else if(sum>t){
while(left<right&&nums[right]==nums[--right]);
}else{
while(left<right&&nums[left]==nums[++left]);
}
}
}
return ret;
}
}
8.四数之和
https://leetcode.cn/problems/4sum/description/
题目解析
给n个整数组成的数组nums和一个目标值t,返回满足全部条件并且不重复的四元组 0<=a,b,c,d<n
a b c d 互不相同
nums[a]+nums[b]+nums[c]+nums[d]==t
算法原理
解法一:排序+暴力枚举+set去重
解法二:排序+双指针
1.依次固定一个数a
2.在a后的区间内,利用"三数之和",使三数之和=t-a
细节:1.不重 跳过重复元素
2.不漏 找到一种结果后,不要停,缩小区间,继续寻找
代码实现
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
int n=nums.length;
List<List<Integer>> ret=new ArrayList<>();
for(int i=0;i<n;){
for(int j=i+1;j<n;){
int left=j+1,right=n-1;
long t=(long)target-nums[i]-nums[j];
while(left<right){
int sum=nums[left]+nums[right];
if(sum>t){
right--;
}else if(sum<t){
left++;
}else{
ret.add(Arrays.asList(nums[i],nums[j],nums[left++],nums[right--]));
while(left<right&&nums[left]==nums[left-1]){
left++;
}
while(left<right&&nums[right]==nums[right+1]){
right--;
}
}
}
j++;
while(j<n&&nums[j]==nums[j-1]){
j++;
}
}
i++;
while(i<n&&nums[i]==nums[i-1]){
i++;
}
}
return ret;
}
}