尺取法

文章介绍了尺取法作为一种高效的枚举区间的方法,用于解决数组中的特定问题,如寻找和为特定值的两个数、判断回文串以及找到和等于给定值的最小区间。通过反向和同向扫描策略,提高了算法效率,但强调需先判断是否适用尺取法。
摘要由CSDN通过智能技术生成

顾名思义,像尺子一样取一段,尺取法通常是对数组保存一对下标,即所选取的区间的左右端点,然后根据实际情况不断地推进区间左右端点以得出答案。尺取法比直接暴力枚举区间效率高很多,尤其是数据量大的时候,所以说尺取法是一种高效的枚举区间的方法,是一种技巧,一般用于求取有一定限制的区间个数或最短的区间等等。当然任何技巧都存在其不足的地方,有些情况下尺取法不可行,无法得出正确答案,所以要先判断是否可以使用尺取法再进行计算。

//题1(反向扫描):
//输入n(n<10000)个整数,放在数组a[]中,找出其中的两个数,它们
//之和等于整数m(假定肯定有解),且所有整数都是int型。
//输入第一行是a[]里的内容,第二行是m的值
//输出相加等于m的数
#include <iostream>
#include <algorithm> 
using namespace std;
void find_sum(int a[],int n,int m)
{
    sort(a,a+n);
    int i = 0,j = n-1;
    while(i<j)
    {
        int sum = a[i] + a[j];
        if(sum>m)j--;
        if(sum<m)i++;
        if(sum==m)
        {
            cout<<a[i]<<" "<<a[j]<<endl;
            i++;
        }
    }

int main()
{
    int a[10000],m,i=0;
    while(a[i]!=0)
    {
        cin>>a[i];
        i++;
    }
    cin>>m;
    find_sum(a,i,m);
    return 0;
}

//尺取法
//题2(反向扫描):
//输入一个正整数n,表示测试实例的个数,后面输入n个字符串
//输出如果是回文串,输出yes,否则输出no 
#include<iostream>
using namespace std;
int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        string s;
        cin>>n;
        bool ans = true;
        int i = 0,j = s.size() - 1;
        while(i<j)
        {
            if(s[i]!=s[j])
            {
                ans = false;
                break;
            }
            i++;
            j--;
        }
        if(ans)
            cout<<"yes"<<endl;
        else
            cout<<"no"<<endl;
    }
    return 0;

//尺取法
//题3(同向扫描):
//给定一个长度为n的数组a[]和一个数,在这个数组中找一个区间,使这个区间的数组元素之和等于s。
//输出区间的起点和终点位置。
//输入样例是第一行是数组 有多少个数
//第二行是数组里的数
//第三行是区间要求的和
void findsum(int *a,int n,int s)
{
    int i=0,j=0;
    int sum = a[0];
    while(j<n)
    {
        if(sum>=s)
        {
            if(sum==s)
            {
                cout<<i<<" "<<j<<endl;
            }
            sum-=a[i];
            i++;
            if(i>j)
            {
                sum=a[i];
                j++;
            }
        }
        if(sum<s)
        {
            j++;
            sum+=a[j];
        }
    }

输入: s = 7, nums = [2,3,1,2,4,3] 输出: 2 解释: 子数组 [4,3] 是该条件下的长度最小的子数组。

代码如下:

#include<iostream>
#include<vector>
using namespace std;
int minSubArrayLen(int s, vector<int>& nums) 
{
    int len = nums.size();
    int min_len = len + 1; // 初始化最小长度
    int l = 0, r = -1; // 定义左右指针
    int sum = 0; // 定义累加和
    while(l < len){ // 左指针移动
        if(sum < s && r + 1 < len)
        { // 如果累加和小于s且右指针未越界
            r++;
            sum += nums[r];
        }
        else
        { // 否则左指针向右移动
            sum -= nums[l];
            l++;
        }
        if(sum >= s)
        { // 如果累加和大于等于s,更新最小长度
            min_len = min(min_len, r - l + 1);
        }
    }
    if(min_len == len + 1)
    { // 如果最小长度未被更新,说明没有符合条件的子数组
        return 0;
    }
    else
    {
        return min_len;
    }
}
int main()
{
    int s = 7;
    vector<int> nums = {2,3,1,2,4,3};
    cout<<minSubArrayLen(s, nums)<<endl; // 输出2
    return 0;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值