鼠鼠的算法题解(双指针)

双指针概念

所谓双指针,并不是两个指针,而是两个表示下标的变量。我们根据条件对这两个指针进行迭代。一般分两种用法:对撞指针、快慢指针。

双指针模版

对撞指针

使用两个指针left,right,分别指向第一个与最后一个元素。

满足一定条件时左指针右移,满足另外条件时右指针左移,直至两指针相撞(left=right),退出循环。

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        String str = s.next();
        char []c = str.toCharArray();
        boolean is = true;
        for(int i = 0,j = c.length-1;i<j;i++,j--){
            if(c[i]!=c[j]){
                is = false;
                break;
            }
        }
        if(is)
            System.out.println("Y");
        else
            System.out.println("N");
    }
}

在这道例题中,分别用左右指针表示首尾两字符,如果两字符相同,左右指针同时向中间移动。直至二者对撞都相等,则判定为true。

快慢指针

两指针放在同一侧(不一定都是第一个元素),并且一个移动快,一个移动慢。

假设慢指针为l,快指针为r,二者构成区间[l,r]。

直至快指针达到终点,或快慢指针相交,或满足其他条件时退出循环。

int l = 0;
int r = 0;
while(r<n){
            sum += a[r];
            while(sum>=S){
                max=Math.min(max,r-l+1);
                sum-=a[l];
                l++;
            }//满足sum>S时l右移,否则仅r右移//
            r++;
        }

在这道例题中,我们设置l,r的初始值均为0。r始终右移,当sum>S时,若仅r继续右移必然使区间长度增大,这时使l右移。其余情况下仅r右移。

由于快慢指针的难度更大,再给出一道例题。

int l = 0;
int r = k-1;
int count;//记录区间内大于等于m的数字个数
while(r<n){
            count = 0;
            for(int i = l; i <= r; i ++){
                if (a[i] >= m) {
                    count ++;
                }
            }
            if(count==k){
                l++;
                ans += n-r;
                r=l+k-2;
            }
            r ++;
        }

这道例题中,由于子串带有区间属性,我们将r初始化为k-1,使得[l,r]区间的长度至少等于最小子串长度。

r始终右移,当区间内count==k时,后面的子串一定都满足条件,这时使l++,否则仅r++。在这道题中还需要注意l自增后,r的位置需要更新为新l的最小子串的右端点,防漏。又因为最后r会自增,所以将r更新为右端点前一位。

双指针变题

Arrays.sort(a);
        long ans = 0;
        for(int j = 0,k = 0,i = 0; i < n; i ++){
            while(j<n-1&&a[j]-a[i]<C){
                j++;
            }
            while(k<n&&a[k]-a[i]<=C){
                k++;
            }
            if(a[k-1]-a[i]==C&&a[j]-a[i]==C){
                ans+=k-j;
            }
        }

首先,面对无序的数组,很难有条理地计算出差值的组合,而题目对于顺序没有要求,只需要统计个数。因此我们可以对原数组进行排序(O(nlogn))。

这一题使用单纯的双指针很难解决,难点有二:

(1):不论是l还是r右移,差值C总是不严格单调增加。这也就导致使用传统双指针必然存在漏答案的可能,因为在差值小于C的情况下,l右移或者r右移均可能成立;差值大于C时,只能使l左移或者r左移,也均可能成立。

(2):可能存在同数字区间,例如连续的4,可能会漏。

因此,我们使用三个变量来表示数字的下标。使用[j,k]区间表示同数字区间。其中有几个小细节:

(1):为什么j与k的while判断条件有细微的差别->k取到n以及a[k]-a[i]大于C都是为了使得k处于j的右侧。当j为n-1时,k取n,才能使k-j=1。

(2):ans的数据类型设定为long。->n的范围为2e5,由排列组合可知最多存在2e10左右的答案,而int型的最大值只到2e9,因此使用long型才能得到全部的分数。

  • 27
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值