算法笔记——双指针法

最近几天想把寒假做的有关算法的笔记整理出来,其中有很多例题都是出自leetcode,还有一些是参考
《算法竞赛入门经典》,用得比较多的方法有动态规划法、双指针法、回溯法、二分法、递归法等。
今天先双指针法:双指针法的形式有好几种,如同侧出发,两侧逼近(需要先排序,其实遍历两次也可以,但是算法复杂度比较高),两侧远离。
形式一:同侧出发

乘积小于K的子数组 :
给定一个正整数数组 nums。
找出该数组内乘积小于 k 的连续的子数组的个数。
示例 1:
输入: nums = [10,5,2,6], k = 100
输出: 8
解释: 8个乘积小于100的子数组分别为: [10], [5], [2], [6], [10,5], [5,2], [2,6], [5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于100的子数组。
双指针法:
class Solution {
public int numSubarrayProductLessThanK(int[] nums, int k) {
if (k <= 1) return 0;
int now = 1, times = 0, left = 0;
for (int right = 0; right < nums.length; right++) {
now *= nums[right];
while (now >= k) now /= nums[left++]; 不符合要求时,将left指针右移至符合要求处
times += right - left + 1;
}
return times;
}
}
要明白各个指针的含义和作用,快指针往后拉伸,到某处不符合要求了,再让慢指针往后移。
在字符串题、子数组题中很受用,因为二者通常都要求连续。(要看清是子数组还是子序列)
这种方法用的比较多。

替换后的最长重复字符
给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。

注意:
字符串长度 和 k 不会超过 104。

示例 1:

输入:
s = “ABAB”, k = 2

输出:
4

解释:
用两个’A’替换为两个’B’,反之亦然。
public int characterReplacement(String s, int k) {
int i,j,max=0;
int[] a=new int[26];
for(i=0,j=0;j<s.length()😉
a[s.charAt(j)-‘A’]++;j++;
if(check(a,k)) {
max=Math.max(max, j-i);
}
else {
do {
a[s.charAt(i)-‘A’]–;
i++;
}while(!check(a,k));
}
}
return max;
}
private boolean check(int[] a, int k) {
int sum=0,i,max=0;
for(i=0;i<a.length;i++) {
sum+=a[i];
max=Math.max(max,a[i]);
}
return sum-max<=k;
}

形式二:两侧逼近
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
最简单粗暴的方法是遍历四次,但是首先算法题出成这样已经很明显是考察降低复杂度的了,n^4肯定只能解决一些小数据,那么下面这种方法能降低一个数量级。
public List<List> fourSum(int[] nums, int target) {
List<List> list=new ArrayList<>();
Arrays.sort(nums);
int a,b,c,d;
for(a=0;a<nums.length-3;a++) {
if(a>0&&nums[a]==nums[a-1])continue;
for(b=a+1;b<nums.length-2;b++) {
if(b>a+1&&nums[b]==nums[b-1])continue;
c=b+1;d=nums.length-1;
while(c<d) {
if(nums[a]+nums[b]+nums[c]+nums[d]<target) {
c++;
}
else if(nums[a]+nums[b]+nums[c]+nums[d]>target) {
d–;
}
else {
List slist=new ArrayList<>();
slist.add(nums[a]);slist.add(nums[b]);slist.add(nums[c]);slist.add(nums[d]);
list.add(slist);
while(c<d&&nums[c+1]==nums[c])c++;
while(c<d&&nums[d-1]==nums[d])d–;
c++;d–;
}
}
}
}

    return list;

}

形式三:两侧远离
这是一道抛物线题,属于分类讨论
如果数组内存在拐点,那么每次看左右指针哪个离中心轴近,这里要注意的细节是越界问题
在这里插入图片描述
以上是属于比较经典的例题了,双指针法的适用面很广。
思考指针的含义和作用,就能在找到合适的解决方法。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值