“人的一生是短暂的,但如果卑鄙地过这短暂的一生,那就太长了。”
文章目录
- 前言
- 文章有误敬请斧正 不胜感恩!
- 双指针
- 简介
- 对撞指针
- 快慢指针
- 例题
- 聪明的小羊肖恩
- 神奇的数组
- 盛最多的水
- 总结
前言
写在开始:
双指针算法是一种经典且高效的算法技巧,常用于数组、字符串等线性数据结构中的各种问题。它通过两个指针的协同移动,解决了传统暴力法需要 O(n²) 复杂度的问题,优化至 O(n)。双指针算法主要分为对撞指针和快慢指针两类,前者常用于解决有序数组和字符串的问题,后者更适合处理需要区间或步长变化的场景。掌握双指针技巧,不仅能提高解题效率,还能帮助我们更深入理解数据结构的特性与变化规律。
双指针算法其实就是通过两个“指针”来操作数据,虽然我们叫它指针,但实际上就是两个变量,
它们指的是数据中的不同位置。这个方法特别适合解决像数组、字符串这类线性结构的问题。
传统的暴力算法可能需要遍历很多次才能找到答案,而双指针通过巧妙的移动指针,
大大减少了重复操作,从而提高了效率。常见的双指针有两种,一种是从两边往中间走的对撞指针,
另一种是快慢指针,一个快一个慢,逐步缩小范围来解决问题。
文章有误敬请斧正 不胜感恩!
以下是本篇文章正文内容,
双指针
简介
双指针算法是一种常用的算法技巧,它通常用于在数组或字符串中进行快速查找、匹配、排序或移动操作
双指针并非真的用指针实现,一般用两个变量来表示下标 (在后面都用指针来表示)
双指针算法使用两个指针在数据结构上进行迭代,并根据问题的要求移动这些指针
双指针往往也和单调性、排序联系在一起,在数组的区间问题上,暴力法的时间复杂度往往是O(n^2)的,但双指针利用“单调性”可以优化到O(n).
常见的双指针模型有:
- 对撞指针
- 快慢指针
对撞指针
指的是两个指针 left、right (简写为l,r) 分别指l向序列第一个元素和最后一个元素
然后l指针不断递增,r不断递减,直到两个指针的值相撞或错开 (即 l >= r),或者满足其他要求的特殊条件为止。
对撞指针一般用来解决有序数组或者字符串问题 (常见于区间问题)
查找有序数组中满足某些约束条件的一组元素问题: 比如二分查找、数字之和等问题字符串反转问题:反转字符串、回文数等问题.
- 使用两个指针 left,right。let 指向序列第一个元素,即: left = l,right 指向序列最后一个元素,即: right = n。
- 在循环体中将左右指针相向移动,当满足一定条件时,将左指针右移,let ++。当满足另外定条件时,将右指针左移,right –
- 直到两指针相撞(即 left == right),或者满足其他要求的特殊条件时,跳出循环体
快慢指针
快慢指针一般比对撞指针更难想,也更难写
指的是两个指针从同一侧开始遍历序列,且移动的步长一个快一个慢
移动快的指针被称为快指针,移动慢的指针被称为慢指针
为了方便理解,我们成快指针为r,慢指针为1,这样慢指针和快指针构成区间[l,r]
两个指针以不同速度、不同策略移动,直到快指针移动到数组尾端,或者两指针相交,或者满足其他特殊条件时为止
- 使用两个指针1、r1一般指向序列第一个元素,即: 1= 1,r一般指向序列第零个元素,即:r = 0。即初始时区间[l, r]= [1,]表示为空区间
- 在循环体中将左右指针向右移动。当满足一定条件时,将慢指针右移,即1++。当满足另外一定条件时 (也可能不需要满足条件) ,将快指针右移,即r++,保持[l,r]为合法区间
- 到指针移动到数组尾端 (即l== n且r== n),或者两指针相交,或者满足其他特殊条件时跳出循环体
例题
聪明的小羊肖恩
import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int left = scan.nextInt();
int right = scan.nextInt();
int[] arr = new int[n];
for(int i=0;i<n;i++){
arr[i] = scan.nextInt();
}
Arrays.sort(arr);
System.out.println(calc(arr,right)-calc(arr,left-1));
scan.close();
}
static long calc(int[] arr,int t){
long ans = 0;
int l = 0 , r = arr.length - 1;
while(l < r){
while(l<r && arr[r] + arr[l] > t){
r--;
}
ans += r - l;
l++;
}
return ans;
}
}
神奇的数组
import java.util.*;
// 1:无需package
// 2: 类名必须Main, 不可修改
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] arr = new int[n];
for(int i=0;i<n;i++){
arr[i] = scan.nextInt();
}
int l=0,r=0,rs=0;
long ans = 0;
while(l<n){
while(r<n && ((rs^arr[r]) == (rs + arr[r]))){
rs ^= arr[r];
r++;
}
ans += r - l;
rs ^= arr[l];
l++;
}
System.out.println(ans);
scan.close();
}
}
盛最多的水
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
class Solution {
public int maxArea(int[] height) {
int i = 0, j = height.length - 1, res = 0;
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/056355574f954b2794e5e37b99b20360.jpeg#pic_center)
res = height[i] < height[j] ?
Math.max(res, (j - i) * height[i++]):
Math.max(res, (j - i) * height[j--]);
}
return res;
}
}
总结
双指针算法的核心在于两个指针的相互配合,通过灵活调整指针的移动策略,能够有效地解决很多复杂度较高的问题。无论是对撞指针,还是快慢指针,都是在特定场景下优化问题求解的一种利器。在面对算法问题时,我们要善于通过分析数据的单调性、区间的划分来运用双指针算法,从而提升代码的效率和简洁性。