什麼是尺取法(取尺法)
其實我也不太懂到底是尺取法還是取尺法,好像都可以= =下文統一尺取法。其實很多人寫的雙指針就就是尺取法,只是突然換個名字,大概的思路以及應用都是類似的,雙指針是2個指針移動,尺取法就是設定尺子的兩端位置,然後移動。
簡單的例子
假設給出一串01組成的字符串,要求找出連續的0或者連續的1的最長長度,比較簡單的寫法就是雙指針,定義兩個指針,指針範圍內右指針先一直右移,直到碰見不一樣的字符,此時用變量記錄兩個指針間的距離(由於指針是一下一下移動的,所以每次變量自加1即可)。然後左指針直接移動到右指針所在位置,然後繼續重複。比較每次結束的時候的距離,更新一個最大值即可。
尺取法基本一樣,這裏上一下代碼:
int l,r;
int ans = 0;
for(l = 0,r = 0;l < n-1;l++){
int sum = 0;
while(r+1 < n && arr[r+1] == arr[l]){
r++;
sum++;
}
ans = ans > sum ? ans : sum;
}
基本也比較簡單,大概就是用l、r定義區間,先固定l爲初始,然後r一直累加,直到發現不同的字符出現。然後l++,也就是左邊少一位,然後r繼續移動。
實際上對於這個問題而言,雙指針是要優於尺取法的,因爲中間連續的部分完全可以跳過。那麼如果改一下問題呢?
給出一段數字,再給出一個數字k,要求子串的和大於這個k的所有子串,最短長度是多少。
那麼雙指針就gg了,因爲左指針跳到右指針的時候就錯過了很多子串的開頭。但是我們如果還是想用雙指針的話,就直接變成了尺取法了。我們維護一個區間,每次右邊移動一位,同時累加到sum,當sum>k的時候,就計算當前長度。雙指針仍然需要計數,但是尺取法就不用了,r-l即可得到長度。然後左邊移動一位,同時減去這個sum。就這樣,當sum<=k的時候就一直右移,當sum>k的時候左移一下,然後重複。
尺取法使用的前提
上面也看到了,尺取法的使用需要一定的前提才能發揮最大的作用。第一個問題雙指針就可以了,但是第二個就需要尺取法來維護一個區間。
1.能夠維護一個區間,保證這個區間能夠獲得答案。
2.維護的具體操作可以左邊移動一位、右邊移動一位。
3.區間的變化是連續的而不是跳躍的。問題1就是比較跳躍的,雙指針比較好,問題2不能跳躍。
4.必須符合題意:答案越小越好。
當然,4感覺不太必要,如果答案越大越好就沒有意義了。
尺取法的一個模板題-poj 3061-Subsequence
題意其實就是上面的問題2了,就不再贅述,直接上代碼:
#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<utility>
#include<queue>
#include<sstream>
#include<iterator>
#include<math.h>
#include<malloc.h>
#include<string.h>
#include<stack>
#include<functional>
#define TIME std::ios::sync_with_stdio(false)
#define LL long long
#define MOD 1000000007
#define MAX 101000
#define INF 0x3f3f3f3f
using namespace std;
int T, N, S;
LL arr[MAX];
LL Min(LL a, LL b) {
return a > b ? b : a;
}
int main() {
TIME;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &N, &S);
for (int i = 0; i < N; i++) {
scanf("%lld", &arr[i]);
}
LL ans = INF;
LL sum = arr[0];
int l = 0;
int r = 0;
if (N == 0) {
printf("1\n");
}else {
for (; l < N; l++) {
while (r + 1 < N && sum < S) {
r++;
sum += arr[r];
}
if (sum >= S) {
ans = Min(ans, r - l+1);
}
sum -= arr[l];
}
if (ans == INF) {
printf("0\n");
}else {
printf("%lld\n", ans);
}
}
}
system("pause");
return 0;
}
這個題其實有一點很蛋疼,得考慮0的情況,否則會WA的。其他還好。