面试算法总结系列——尺取法的应用,滑动窗口

最近准备笔试的过程中,发现好多算法题,有点套路的感觉,只怪自己平时积累不多,现在只能亡羊补牢了。

关于尺取法的概念我就不介绍了,网上这方面讲解很多,主要说一些应用的方面,积累下目前遇到的一些可以用尺取法可以来解决的题目,不定期更新下。
尺取法参考博客

在此说明,我的梦想是进入网易,校招进入网易已经不可能了,我就在这里立一个誓言,将来一定会进网易
没想到曾经的网易,现在也因为"暴力拆迁"事件,而变得风声鹤唳,网易就不指望了。

尺取法的应用

简单可以理解为,所有求连续的一段区间的相关问题(比如求和,求差),都可以考虑下尺取法。注意,尺取法需要保证所有点按顺序排列好,只能勇往直前,而不能后退。

尺取法要维护左右两个点,左边这个点慢一些,右边这个点走的快一些,两个点间的不能超过最大的临界,否则就要移动点。

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点的大小来排序,排序后从左往右找,
##后记:
还有一些尺取法的应用,都可以采用尺取法套路一下,后面再接着更新,如果有错误的地方,希望大家不吝赐教,毕竟本人小菜鸡

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章