练车加端盘子也挡不住我学习系列——two pointers算法思想

什么是two pointers?

two pointers是算法编程中的一种非常重要的思想,但是很少会有教材单独拿出来讲解,它更倾向于一种编程技巧。其思想非常简洁,能够很好的降低程序的时间复杂度,它提供了非常高的算法效率。
在这里插入图片描述

经典案例

我给你一个递增的正整数序列a[n],让你找出序列中满足任意两个数a[i]和a[j]相加等于给定的数值M的数组元素,即a[i]+a[j]=M。
你可能会说:我丢!这玩意太简单了,直接双循环枚举不就完事了。
下面这个算法是我们的直观思维。

for(int i=0;i<n-1;i++)
        for(int j=i+1;j<n;j++)
        if(a[i]+a[j]==M) cout<<a[i]<<" "<<a[j]<<endl;

但从算法时间复杂度的角度去分析,利用大O表示法可知,其算法复杂度为O(n^2) ,这个算法复杂度在n为10^5时就已经不可承受了,那么对于序列长度较为大的正整数递增序列而言,这个算法有点low。
我们可以分析一下为何上面这个算法的效率会如此底下,当枚举至a[i]+a[j]大于M时,这时候循环依旧向下进行,可想而知a[i+1]+a[j]肯定是大于M的,因此这个算法进行了大量的无效枚举。
在这里插入图片描述

two pointers算法实现

根据上面的分析可知,当a[i]+a[j]>M时i再往后枚举时就没有什么意义了。所以可知,i和j的枚举是相互牵制的。
算法伪代码:

1. 另i指向数组头部,j指向数组尾部。开始反向扫描数组
2. 当a[i]+a[j]==M时,可知,a[i+1]+a[j]>M,a[i]+a[j-1]<M,但a[i+1]+a[j-1]与M的关系是未知的,此时变换扫描区间为[i+1,j-1]。
3. 当a[i]+a[j]>M时,可知此时a[i]+a[j-1]的关系未知,所以扫描区间变换为[i,j-1]。
4. 当a[i]+a[j]<M时,可知此时a[i+1]与a[j]的关系未知,所以扫描区间变换为[i+1,j]。

    while(i<j)
    {
        if(a[i]+a[j]==M)
        {
            cout<<a[i]<<"+"<<a[j]<<"="<<M<<endl;
            i++;
            j--;
        }
        else if(a[i]+a[j]<M) i++;
        else j--;
    }

分析可得其算法时间复杂度为O(n)。

在这里插入图片描述

序列合并问题

假设有两个递增序列A与B,将他们合并为一个递增的序列C

通过two pointers算法思想的学习可以很快的解决这个问题

int merge(int A[],int B[],int n,int m,int C[])
{
    int i=0,j=0,counts=0;
    while(i<n&&j<m)
    {
        if(A[i]>=B[j]) C[counts++]=A[i++];
        else C[counts++]=B[j++];
    }
    while(i<n) C[counts++]=A[i++];
    while(j<m) C[counts++]=B[j++];
    return counts;//返回序列长度
}

好了,今天的算法学习内容就到这里,没什么特殊情况明天见!
在这里插入图片描述
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/pipihan21/article/details/107415568