您的位置:首页 > 其它

【九度】题目1554:区间问题

2015-05-25 23:18 218 查看
题目描述:

给定一个数组,判断数组内是否存在一个连续区间,使其和恰好等于给定整数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


分析:本题的输入数据量过大,不宜采用暴力法。定义一个数组num[i],表示0~i号元素之和(第0号元素设为0).那么当num[j]-num[i]=k,j>i时,可知在i+1~j区间上的元素之和为k。现在问题转化为在一个数组num上找出一对最小的i,j使得,i<j,num[j]-num[i]==k。一种方法是将num的元素排序,然后依次遍历num的元素e,并且用二分查找法在有序的num上查找e+k。效率在nlogn内,但是比较麻烦,因为没一个num元素需要记录位置信息,排序后下标有所改变,而且每一次二分查找必须将所有值为e+k的元素都找出来,才能找出相对应最小的下标j。另一种简便的方法是采用map,first值为num值,second值为取first值的所有num的下标。这样可以在logn内查找到j,建立map需要nlogn时间,时间复杂度为nlogn,但代码量以及要考虑的情况简单多了。

代码如下:

#include<stdio.h>

#include<vector>

#include<map>

using namespace std;

#define N 1001

int num
;

int main()

{

int n;

while(scanf("%d",&n)!=EOF)

{

num[0]=0; //数组的第0个元素取为0

for(int i=1;i<=n;++i)

{

int tmp;

scanf("%d",&tmp);

num[i]=num[i-1]+tmp; //num[i]存储数组从0~i的元素之和

}

int k;

scanf("%d",&k);

map<int,vector<int>> Hash;

map<int,vector<int>>::iterator it;

for(int i=1;i<=n;++i)

{

it=Hash.find(num[i]);

if(it==Hash.end())

{

Hash[num[i]].push_back(i);

}

else

{

(it->second).push_back(i);

}

}

int s=-1,e=-1;

bool flag=false;

for(int i=0;i<n;++i)

{

it=Hash.find(num[i]+k);

if(it!=Hash.end())

{

for(int j=0;j<(it->second).size();++j)

{

int t=(it->second)[j];

if(t>i)

{

s=i+1;

e=t;

flag=true;

break;

}

}

}

if(flag)

break;

}

if(flag)

printf("%d %d\n",s,e);

else

printf("No\n");

}

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: