[Alg] 尺取法

尺取法是在线性结构中进行搜寻满足某一条件的区间的方法。

该方法保存两个索引——首索引begin、尾索引end。判断 [begin, end] 区间是否满足条件。

移动 [begin, end] 区间的方法是将 end 固定,begin 向前移动,得到中间区间 [begin + 1, end],随后将 end 再向前移动,直到找到满足条件的区间。

在 begin 往前移动之后,[begin + 1, end] 区间的状态都已经保存,无需再次进行计算其中的状态。这一部分是尺取法比 Brute-Force 高效的关键。

这种方法的移动过程有点像尺蠖,日本语叫尺取法,这种昆虫的移动过程为:(头部固定,撅起屁股,把尾部向前移动)-> (尾部固定,放下屁股,把头部向前移动)。

尺蠖

以上是尺取法的简介。

下面是例题:
牛客网:[编程题]彩色宝石项链
https://www.nowcoder.com/questionTerminal/321bf2986bde4d799735dc9b493e0065

有一条彩色宝石项链,是由很多种不同的宝石组成的,包括红宝石,蓝宝石,钻石,翡翠,珍珠等。有一天国王把项链赏赐给了一个学者,并跟他说,你可以带走这条项链,但是王后很喜欢红宝石,蓝宝石,紫水晶,翡翠和钻石这五种,我要你从项链中截取连续的一小段还给我,这一段中必须包含所有的这五种宝石,剩下的部分你可以带走。如果无法找到则一个也无法带走。请帮助学者找出如何切分项链才能够拿到最多的宝石。

输入描述:

我们用每种字符代表一种宝石,A表示红宝石,B表示蓝宝石,C代表紫水晶,D代表翡翠,E代表钻石,F代表玉石,G代表玻璃等等,我们用一个全部为大写字母的字符序列表示项链的宝石序列,注意项链是首尾相接的。每行代表一种情况。

输出描述:

输出学者能够拿到的最多的宝石数量。

代码:

#include <iostream>
#include <string>
using namespace std;
int main(){
    string s;
    while(cin>>s){
        int begin = 0, end = 0;
        int len = s.size(), minLen = s.size();
        int book[5] = {0, 0, 0, 0, 0}; // 这里使用int数组,而不是bool数组,因为int数组可以记录出现的次数,方便begin向前移动。
        int num = 0;
        while (begin < len){ // 从起点开始
            // end 没有置0操作
            while ((end < begin + len) && num < 5) {
                if (s[end % len] - 'A' < 5) {
                    book[s[end % len] - 'A']++;
                    if (book[s[end % len] - 'A'] == 1) {
                        ++num;
                    }
                }
                ++end;
            }
            // 遍历一遍都没有能够找到5种宝石,后面都不可能找到了
            if (num < 5) break;
            minLen = minLen > (end - begin) ? (end - begin) : minLen;
            if (s[begin] - 'A' < 5) {
                if (--book[s[begin] - 'A'] == 0) {
                    --num;
                }
            }
            ++begin;
        }
        cout << (len - minLen) << endl;
    }
}

相关题目:https://leetcode.com/problems/gas-station/description/

参考:1. http://www.jianshu.com/p/64abe526fe91

posted @ 2017-09-17 12:04  JingeTU  阅读(345)  评论(0编辑  收藏  举报