【初识算法】尺取法

尺取法:简单来说,我可以把两重循环转化为一重循环,从而把时间复杂度从 O(n^2) 提高到 O(n)。

for(int i = 0; i < n; i++)           //i从头扫到尾
    for(int j = n-1; j >= 0; j--){   //j从尾扫到头
        ......
    }

其中 i 从 0​​ 循环到 n-1,j 反过来从 n−1​​ 循环到 0​​ 。这两重循环的时间复杂度是 O(n^2)​ 的。
如何把两重循环变为一个循环?
我可以在一个循环中一起处理 i,j,代码如下,这样复杂度就从 O(n^2)变成了 O(n)。

for (int i = 0, j = n - 1; i < j; i++, j--) {
    ......
}

诶等等,这?你在耍我呢?这不是瞎扯淡嘛?这两重循环凭啥变成下面的一重循环了?

em,我这不是还没说完嘛。。。我的局限性很大,因为我有 i < j 的一个小限制,也就是说 i从头到尾走、j从尾到头走,两者可以中间位置相会。所以我的应用场合并不多。

好吧,我还以为你是万能的,原来只能应用在有限场合啊…诶你这个有限场合大概是什么样的场合啊?还有你这个一重循环的代码。。。就不能写的好看点?

有限场合一般指代和区间有关的问题;如果你觉得 for 循环不好看,那就来看看我的 while 写法吧。

//用while实现:
int i = 0, j = n - 1;
while (i < j) {      //i和j在中间相遇。这样做还能防止i、j越界
        ......       //满足题意的操作
        i++;         //i从头扫到尾
        j--;         //j从尾扫到头
}

嗯,这代码看起来还是很舒服的。

以上是被称为「反向扫描」的尺取法,另外还有一种「同向扫描」。

你说的这「同向扫描」又是咋样的?

我对尺取法的概念做了总结,你看看下面就会明白了:

把循环指针 i 、j称为「扫描指针」,在尺取法中,这两个指针 i、j,有两种扫描方向:

反向扫描。i、j方向相反,i 从头到尾,j从尾到头,在中间相会。也可以把反向扫描的 i、j指针称为「左右指针」。
同向扫描。i、j方向相同,都从头到尾,但是速度不一样,比如可以让 j跑在 i前面。也可以把同向扫描的 i、j 指针称为「快慢指针」,此时由于 i 和 j 速度不同,i 和 j 之间在序列上产生了一个大小可变的「滑动窗口」,这是尺取法的优势,有灵活的应用。
注意,用尺取法的最关键之处在于,两个指针 i、j 在总体上只能有一个循环,例如:i 循环一遍,对应的 j 只能跟随 i 循环一遍。这样才能实现计算复杂度从 O(n^2)到 O(n)的优化。

算法练习题:回文判定
题目描述
给定一个长度为 nn 的字符串 S。请你判断字符串 S 是否回文。

输入描述
输入仅 11 行包含一个字符串 S。

1≤∣S∣≤10^6
,保证 S只包含大小写、字母。

输出描述
若字符串 S为回文串,则输出 Y,否则输出 N。

样例输入

abcba

样例输出

Y

这题是「反向扫描」最直接的应用,似乎不需要任何解释吧

我的代码如下:

#include <bits/stdc++.h>
using namespace std;
int main(){
    string s;  cin >> s;          //读一个字符串
    bool ans = true;
    int i = 0, j = s.size() - 1;  //双指针
    while(i < j){
        if(s[i] != s[j]){
           ans = false;
           break;
        }
        i++;   j--;               //移动双指针
    }
    if(ans)   cout << "Y" << endl;
    else      cout << "N"  << endl;    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

007的米奇妙妙屋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值