双指针法详细讲解(例一:给定一个递增序列和一个正整数。例二:序列合并问题)

4.6.1什么是双指针?

双指针是一个编程技巧。由于是一个编程技巧,所以更适合结合着题练习。

例 一:

给定一个递增的正整数序列和一个正整数M,求序列的两个不同位置的数 a 和 数 b,使得它们的和恰好为M,输出所有的满足的方案。例如给定序列{1,2,3,4,5,6}和 正整数M=8,就存在 2+ 6= 8 和 3+5=8.
本题的一个很直观的想法是双重for循环,这里不多赘述。这种做法的时间复杂度为O(n^2),对于n在 10^5的规模是不可承受的。

我们来看看这种做法的复杂度高的原因:

1.对于一个确定的a[i],如果a[i] + a[j] > M,显然a[i] + a[j+1]>M,因此就不需要对a[j]之后的数进行枚举。

2.对于某个a[i]来说,如果找到一个a[j],使得a[i] + a[j] > M ,恰好成立,那么a[i+1] + a[j] >M,

所以我们也不需要进行枚举。

我们可以看出,i 和 j 似乎有种某种联系,因此本题我们采用双指针法:

它针对本题的算法如下:

令 i =0 , j = n - 1.及i指向第一个元素,j指向最后一个。利用 a[j] + a[i] 与M的关系来不断进行判断。使i不断右移,j不断左移,知道i>=j成立。

1.如果a[i] + a[j] =M,说明找到了一组方案,由于数列地政a[i + 1] + a[j] > M, a[i] + a[j - 1] <M 成立,但是a[i+1] + a[j -1]的大小未知,因此接下来就在[i+1,j-1]中找。

2.如果a[i] + a[j] >M,a[ i+1] + a[j] >M,但是a[i] + a[j - 1] 与M的大小未知,所以在[i,j-1]中找

3.如果a[i] + a[j] <M,a[i] + a[j - 1] <M,但是a[i + 1] + a[j] 与M的大小未知,所以在[i + 1,j]中找

while(i < j)
{
if(a[i] + a[j] == M)
{
	printf("%d %d\n",i,j);//打出合适方案
	i++;
	j--;
}else if(a[i] + a[j] < M)
{
	i++;
}else
{
  j--;
}
}

例二

合并问题

假设有两个递增的序列a,b.要求将它们合并为一个递增序列c.

同样的,可以设置两个下标i 和 j.初值均设为0。表示分别指向序列a,b的第一个元素。然后根据a[i] 和 b[j]的大小来判断把那个放入c中。

1.如果a[i]<b[j],我们就把a[i]放进去,并且执行i++;b[j] < a[i]时也是一样的。

2.如果两个相等的话随便放进一个,并且只递增放进去的数组的下标,另一个在下一回合会被放进去。当然你也可以两个同时放,同时递增。

3.当一个数组被放完后,另一个剩下的元素一次放入C中。

int merge(int A[],int B[],int C[], int n, int m)
{
    int i = 0 ;
    int j = 0;
    int k =0;
    // 当短的那个到达顶点后,另一个剩下的全部全部加上
    while(i<n && j<m)
    {
        if(A[i] == B[j])
        {
            C[k++] = A[i++];
            C[k++] = B[j++];
        }
        else if(A[i] < B[j])
        {
            C[k++] = A[i++];
        }
        else if(B[j] < A[i])
        {
            C[k++] = B[j++];
        }
    }
    while(i<n)
    {
        C[k++] = A[i++];
    }
    while( j < m)
    {
        C[k++] = B[j++];
    }
    return k;//返回C的长度
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值