最近準備筆試的過程中,發現好多算法題,有點套路的感覺,只怪自己平時積累不多,現在只能亡羊補牢了。
關於尺取法的概念我就不介紹了,網上這方面講解很多,主要說一些應用的方面,積累下目前遇到的一些可以用尺取法可以來解決的題目,不定期更新下。
尺取法參考博客
在此說明,我的夢想是進入網易,校招進入網易已經不可能了,我就在這裏立一個誓言,將來一定會進網易
沒想到曾經的網易,現在也因爲"暴力拆遷"事件,而變得風聲鶴唳,網易就不指望了。
尺取法的應用
簡單可以理解爲,所有求連續的一段區間的相關問題(比如求和,求差),都可以考慮下尺取法。注意,尺取法需要保證所有點按順序排列好,只能勇往直前,而不能後退。
尺取法要維護
左右
兩個點,左邊這個點慢一些,右邊這個點走的快一些,兩個點間的尺
不能超過最大的臨界
,否則就要移動點。
1:搜狗校招9月08號筆試題
題意:同一個圓上面有n個點,n個點按照從小到大排列,每個點有一個角度a(0<=a<=360),代表圓心角,問題是讓你求這些點構成的所有劣弧對應最大的圓心角(按劣弧來算,比如,10,193,圓心角就爲177)
思路:這裏就以180爲’臨界’,左右兩個點距離爲’尺’,兩個點都從原點出發,順時針走,如果大於180,左點前進一位,如果小於180,右點向前進一位。因爲圓是循環的,所以左邊這個點必須走遍圓中所有點,才能訪問完所有的最大的劣弧(注意,不需要訪問所有劣弧,只需要訪問所有最大的劣弧,這裏的最大,是指對於某個點來說的最大)。右邊的點在沒走完一圈之前,採用a[right]-a[left]計算,右點走完一圈之後,採用360-a[left]+a[right%n]來計算。
代碼如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
bool exp(double a,double b){
if(a-b>1e-12)
return true;
else
return false;
}
int main()
{
int n;
scanf("%d",&n);
double a[n+10];
for(int i=0;i<n;i++){
scanf("%lf",&a[i]);
}
double ans = -1;
int left=0,right=0;
while(left<n){
if(right<n){
double temp = a[right]-a[left];
if(exp(temp,180)){
left++;
}else{
ans = max(ans,temp);
right++;
}
}
else{
double temp = 360-a[left]+a[right%n];
if(exp(temp,180)){
left++;
}else{
ans = max(ans,temp);
right++;
}
}
}
printf("%.8lf\n",ans);
return 0;
}
/*
4
10.00000000
180.00000000
183.00000000
198.00000000
3
10.00000000
180.00000000
190.00000000
*/
小優化 :第一次尋找最大尺的時候,可以採用二分法。這個題必須是有序的,如果無序,需要先排序再操作,否則,不滿足
變量遞增
的效果。
2.最長子區間問題
題意:要求求出最長連續子區間,區間要求所有值加起來,是k的倍數。例如,區間1,2,3,4,5,給出k=5,那麼滿足要求的區間有[1,2,3,4],[2,3],[1,2,3,4,5],顯然[1,2,3,4,5]最長
思路:這個題跟尺取法唯一相同點就是連續問題。需要記錄前綴和。因爲題目要求爲最大,所以需要記錄第一個出現該值的位置,再次出現該值時,說明從第一次出現到當前出現位置,所有數加起來爲k的倍數。
memset(dp,-1,sizeof(dp));
int temp=0,ans=0;
for(int i=0;i<n;i++){
temp = (temp+a[i])%k;
if(dp[temp]!=-1){
len = i-dp[temp];
ans = max(ans,len);
}else{
dp[temp] = i;
}
}
printf("%d\n",ans);
3.滴滴出行9月10號 xor問題
題意:給你一段區間,求出最大的滿足不重疊連續子區間的個數,子區間要求區間內所有數異或爲0
參考博客Xor(滴滴筆試題)
思路:這裏和上面一道題目很像,不同的是本題要求的操作爲異或。搞清楚一點:從左往右掃,滿足條件的第一個區間,中間肯定沒有子區間滿足條件,所以這個區間一定構成最大子區間個數中的其中一個(即使中間部分可能和後面的連續序列異或後滿足條件,也不在做計算,比如[4,3,2,4,3,2,3,2],[432432]爲子區間[3232]也可以爲子區間,但是一定不會選擇[3232],因爲他所消耗的區間長度比[4,3,2,4,3,2]長,[3,2,3,2]相當於消耗了這一整個序列)。
這裏稍微說一下相似的題目,畢竟找工作,多拓展一點沒壞處。
題目:求最大不相交區間的個數。
這個題採用貪心的算法,要記錄下所有區間的left點和right點,然後根據right點的大小來排序,排序後從左往右找,
##後記:
還有一些尺取法的應用,都可以採用尺取法套路一下,後面再接着更新,如果有錯誤的地方,希望大家不吝賜教,畢竟本人小菜雞