1

题目要求:

给定一个序列和一个m的值,要求分割字符串让其和等于M,如果有多个按照i的顺序输出下标i-j,如果没有使得分割的字符串的和等于M,那么找到最接近m的字符串分割,如果有多个按照i的从小到大输出下标i-j

算法思路:

最开始使用了二维数组保存每个起点到各个终点的和,不过内存超限了,因此改用一维数组,我们可以采用partialSum数组保存起点1到i的和,
然后任意i到j位置的连续子序列和为partialSum[j]-partialSum[i-1],因为在查找的时候有可能会找的到等于m的和也可能找不到,所以我们先遍历一次,如果可以找的到就让min_num=M然后退出循环即可,如果没有就让min_num一直更新为最小的大于m的值,由于partialSum数组是递增的可以采用二分查找。这里的二分查找使用STL库中自带的upper_bound函数来实现。

注意点:

1、使用二维数组的方式求解极有可能出现段错误和内存超限的情况。

提交结果:

截屏2020-10-19 上午9.12.28.png

AC代码:

#include <cstdio>
#include <algorithm>

using namespace std;

int main(){
    int N,M;
    scanf("%d %d",&N,&M);
    int partialSum[N+1];// 保存起点1到任意一点的数字和
    partialSum[0] = 0;// 起点0不存在,但是需要参与计算所以赋值为0.
    for (int i = 1; i <= N; ++i) {
        scanf("%d",&partialSum[i]);
        partialSum[i] += partialSum[i-1];
    }
    int min_num = 0x3fffffff;//保存最小的数字,如果存在等于M的数字即为M,如果没有则为大于M的最小数
    for (int i = 1; i <= N; ++i) {
        // 获得第一个大于partialSum[i-1]+M的位置pos,pos-1就是最大的小于等于partialSum[i-1]+M的位置
        int pos = upper_bound(partialSum+i,partialSum+N+1,partialSum[i-1]+M)-partialSum;
        if(partialSum[pos-1]-partialSum[i-1]==M){
            // 找到恰好等于M的序列和
            min_num = M;
            break;
        }
        // 走到这里说明没有找到等于M的序列和
        if(pos<=N){
            // 找到了大于partialSum[i-1]+M才需要保存大于它的最小值,否则会出现取值出错
            min_num = min(partialSum[pos]-partialSum[i-1],min_num);
        }
    }
    // 第二次查找等于min_sum的值,一定可以找到
    for(int i=1;i<=N;++i){
        // 获得第一个大于partialSum[i-1]+min_num的位置pos,pos-1就是等于partialSum[i-1]+min_num的位置
        int pos = upper_bound(partialSum+i,partialSum+N+1,partialSum[i-1]+min_num)-partialSum;
        if(partialSum[pos-1]-partialSum[i-1]==min_num){
            printf("%d-%d\n",i,pos-1);
        }
    }
    return 0;
}

乔梓鑫
569 声望17 粉丝

主要分享个人学习经验和心得