尺取法

尺取法

1. 算法分析

尺取法: 尺取法通常是对数组保存一对下标,即所选取的区间的左右端点,然后根据实际情况不断地推进区间左右端点以得出答案。尺取法通常可以把一个O(n2)的算法利用特殊性质优化到O(n)的复杂度。之所以能够使用尺取法,是因为元素的前缀和具有单调性,才能使得双指针不会回退。
for example:
给定一个数列a[n]和一个S, 要求找出连续的一段区间,使得区间和大于等于S,打印这个区间长度的最小值。

  • O(n2)算法:前缀和预处理,然后O(n2)枚举l和r,每次O(1)计算sum[r] - sum[l]=K的值,然后取得K >= S且长度最小的那个。
  • 尺取优化:数学性质:对于l1, r1 和l2, r2,如果l1 < l2, 那么当sum[r2] - sum[l2] >= S,则sum[r1] - sum[l1] >= S且r1 <= r2。由这个性质可以知道当l单调增加时,r也是单调不减的。因此利用这个可以优化算法。具体处理:l=1,r=1,然后不断将r向右移动,直到sum[r] - sum[l] >= S。然后右移l同时满足sum[r] - sum[l] >= S。更新一次区间长度。不断重复这个过程移动r和l,不断更新区间长度。

尺取流程
n = 5, S = 11
a[i]: 1 2 3 4 5
一开始:l = 1, r = 1, sum = 0
然后r不断右移:r = 5, sum = 15
右移l:l = 2, sum=15-1=14>=S
继续左移l直到:l = 3, sum = 12
此时找到最小区间长度为2。

2. 板子

2.1 一维尺取

#include <iostream>
#include <cstdio>

using namespace std;

int const N = 1e5 + 10, INF = 1e9 + 10;
int a[N], n, S, T;

int main() {
   
    cin >> T;
    while (T--) {
   
        cin >> n >> S;
        for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
        
        int l = 1, r = 1, sum = 0, res = INF;  // 初始化左、右边界、区间和
        while (1) {
   
            while (r <= n && sum < S) sum += a[r++];  // 计算区间和
            if (sum < S) break;  // 如果小于S说明找不到>=S的情况,直接break
            res = min(res, r - l);  // 更新区间
            sum -= a[l++];  // 右移l
        }
        if (res == INF) res = 0;
        cout << res << endl;
    }
    return 0;
}

2.2 二维尺取

#include <bits/stdc++.h>

using namespace std;
int const N = 305, INF = 1e9 + 7;

int r, c, kk, sum[N][N];
char mp[N][N];

int main() 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值