欢迎使用CSDN-markdown编辑器

来源:互联网 发布:网络电视如何看翡翠台 编辑:程序博客网 时间:2024/05/21 17:13

区间问题

问题描述:

给定一个数组,判断数组内是否存在一个连续区间,使其和恰好等于给定整数k。

输入:
输入包含多组测试用例,每组测试用例由一个整数n(1<=n<=10000)开头,代表数组的大小。
接下去一行为n个整数,描述这个数组,整数绝对值不大于100。
最后一行为一个整数k(大小在int范围内)。

输出:
对于每组测试用例,若存在这个连续区间,输出其开始和结束的位置,s,e(s <= e)。
若存在多个符合条件的输出,则输出s较小的那个,若仍然存在多个,输出e较小的那个。
若不存在,直接输出”No”。

样例输入: 5
-1 2 3 -4 9
5
3
-1 2 -3
7
2
-1 1
0
样例输出: 2 3
No
1 2


此题如果使用二重循环,逐个计算区间段的和比较,算法复杂度为o(n^2),将会导致超出time limit。
正确的做法是利用记录索引,首先计算每个数字与他之前所有数字的和sum[i]。 再利用sum[j]-sum[i] 来匹配k。

#include<iostream>#include<cstring>using namespace std;const int maxsize = 10005;const int M = 1000005;int sum[maxsize];int a[maxsize];int location[M * 2] ;int nex[maxsize];//2*m 是为了存放负数 locationint main(){    int n;    while (cin>>n){        memset(sum, 0, sizeof(sum));        memset(location, 0, sizeof(location));        memset(nex, 0, sizeof(nex));        sum[0] = M;// 将原点位置挪到M,        for (int i = 1; i <= n; i++){            cin >> a[i];            sum[i] = sum[i - 1] + a[i];        }        for (int i = n; i >0; i--){ //倒叙,因要输出最小的区间            nex[i] = location[sum[i]]; //相等求最小            location[sum[i]] = i;        }        int k = 0;        cin >> k;        bool check = false;        if (k > M){            cout << "No" << endl;        }        else {            for (int i = 1; i <= n; i++){                int j = location[sum[i-1] + k];                while (j != 0 && j<i) j = nex[j]; // 求最小                if (j != 0){                    cout << i << " " << j << endl;                    check = true;                    break;                }            }        }        if (!check){            cout << "No" << endl;        }    }    return 0;}

注意数组location,用来倒排索引,之所以建立2*M大小的数组,是为了适应负数。本身这个算法不加修正的话是不能适应含有负数的区间和的。

0 0