PIPIOJ 1185 1186 1187 子序列问题1 2 3

在这里插入图片描述
在这里插入图片描述
子序列问题第一题,题目中给的n的范围为10<n<=1000,时间复杂度可以取到O(N³),采用暴力法,看代码

#include<bits/stdc++.h>
using namespace std;
main()
{
    int n,s,sum;
    int A[10010],minn;
    while(scanf("%d%d",&n,&s)!=EOF)
    {
        minn=1e9;
        for(int i=1; i<=n; i++)
        {
            scanf("%d",&A[i]);
        }
        for(int l=1; l<=n; l++)  //子序列的左端点
        {
            for(int r=l; r<=n; r++)//子序列的右端点
            {
                int sum=0;
                for(int k=l; k<=r; k++) //左端点到右端点的和
                {
                    sum+=A[k];
                }
                if(sum>=s)
                    minn=min(minn,r-l+1); //左端点到右端点的字符个数
            }
        }
        if(minn<1e9)
            printf("%d",minn);
        else
            printf("0\n");
    }
    return 0;
}

在这里插入图片描述
在这里插入图片描述
子序列问题第一题,题目中给的n的范围为10<n<=10000,n的范围增加,时间复杂度至少要降到O(N²),看代码

#include<bits/stdc++.h>
using namespace std;
int pre[10010]; //pre数组为全局变量,pre数组中的值全为0
main()
{
    int n,s,sum;
    int A[10010],minn;
    while(scanf("%d%d",&n,&s)!=EOF)
    {
        minn=1e9;
        for(int i=1; i<=n; i++) scanf("%d",&A[i]);
        for(int i=1; i<=n; i++) pre[i]=pre[i-1]+A[i]; //前缀和,该方法定义pre[i]为A[i]中前i个数的和
        printf("%d",pre[0]);
        for(int l=1; l<=n; l++) //左端点
        {
            for(int r=l; r<=n; r++)//右端点
            {
                int sum=0;
                sum=pre[r]-pre[l-1];
                if(sum>=s)
                    minn=min(minn,r-l+1);
            }
        }
        if(minn<1e9)
            printf("%d\n",minn);
        else
            printf("0\n");
    }
    return 0;
}

在这里插入图片描述
在这里插入图片描述
题目不变,当数据量再次扩大到100000时,必须要再次优化代码,将时间复杂度降到(nlogn),这里采用二分法

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int A[N],pre[N];
int n,s;
bool judge(int x) //判断当子序列长度为x时,是否存在长度为x的子序列的和>s
{                  
    for(int l=1;l+x-1<=n;l++)//从1开始枚举x个连续的值,判断是否大于s
    {
        int r=l+x-1;
        int sum=pre[r]-pre[l-1];
        if(sum>=s) return 1;
    }
    return 0;
}
int main()
{
    while(scanf("%d%d",&n,&s)!=EOF)
    {
        for(int i=1;i<=n;i++) scanf("%d",&A[i]);
        for(int i=1; i<=n; i++) pre[i]=pre[i-1]+A[i]; //前缀和的公式
        int l=1,r=n,mid;
        while(l<r) //二分法,判断长度为mid时,是否存在子序列和大于s,这里时间复杂度为nlogn
        {
            mid=(l+r)/2;
            if(judge(mid))
                r=mid;
            else
                l=mid+1;
        }
        if(l==n&&pre[n]<s)
            printf("0\n");
        else
            printf("%d\n",l);
    }
    return 0;
}

发布了28 篇原创文章 · 获赞 7 · 访问量 1174

猜你喜欢

转载自blog.csdn.net/weixin_44433678/article/details/103898295