您的位置:首页 > 其它

OJ-2:区间问题【九度1554】

2015-01-17 18:21 197 查看
题目描述:
给定一个数组,判断数组内是否存在一个连续区间,使其和恰好等于给定整数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

来源:2014年王道论坛计算机考研机试全真模拟考试
我的解答:

package jobdu.wangdao;

import java.io.IOException;
import java.io.StreamTokenizer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* 题目描述: 给定一个数组,判断数组内是否存在一个连续区间,使其和恰好等于给定整数k。
*
*/
public class Question1554 {

/**
* 暴力求和比较
*
* @param array
* @param k
* @return
*/
public static Section solve(int[] array, int k) {
boolean find = false;
for (int i = 0; i < array.length; i++) {
if (!find) {
int sum = 0;
for (int j = i; j < array.length; j++) {
sum += array[j];
if (sum == k) {
find = true;
System.out.println((i + 1) + " " + (j + 1));
return new Section(i + 1, j + 1);
}
}
}
}
if (!find)
System.out.println("No");
return null;
}

public static Section solve2(int[] array, int k) {
int[] sumList = new int[array.length];// 先计算出前0-i个数的和存入sumList
Map<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
// 记录前i个数的和和值相同的下标
int sum = 0;
for (int i = 0; i < array.length; i++) {
sum = sum + array[i];
sumList[i] = sum;
if (map.containsKey(sum)) {// 将和的下标存入map
List<Integer> indexList = map.get(sum);
indexList.add(i);
} else {
List<Integer> indexList = new ArrayList<Integer>();
indexList.add(i);
map.put(sum, indexList);
}
}

boolean find = false;
List<Section> list = new ArrayList<Section>();
for (int j = 0; j < sumList.length; j++) {
int sumi = sumList[j];// 当前遍历的前j个数的和为sumi
if (sumi == k) {// 如果前j个数的和就是k,那么直接为一组解
Section node = new Section(1, (j + 1));
list.add(node);// 加入解集合
find = true;
continue;
}
int temp = sumi + k;// 计算出对应的和已保证a[i]-a[j]=k
if (map.containsKey(temp) && map.get(temp).size() > 0) {
// 如果存在a[i]-a[j]=k,那么从第j+1个数到第i个数之和就为k,这里下标从0开始
int start = j + 2;
int end = -1;
for (Integer integer : map.get(temp)) {// 从和相同的下标中选离j最近比i大的下标作为最后的解
if (integer >= j) {
end = integer + 1;
break;
}
}
if (end >= 0) {
list.add(new Section(start, end));
find = true;
}
}
}

if (!find)
System.out.println("No");
else {
Collections.sort(list);// 对可能的解做一次排序,找到符合题意的解
Section section = list.get(0);
System.out.println(section.start + " " + section.end);
return section;
}
return null;
}

/**
* 确保List的排序
*
*/
public static class Section implements Comparable<Section> {
int start, end;

public Section(int start, int end) {
this.start = start;
this.end = end;
}

@Override
public int compareTo(Section o) {
if (this.start == o.start)
return this.end - o.end;
return this.start - o.start;
}

}

public static void main(String[] args) throws IOException {

@SuppressWarnings("deprecation")
StreamTokenizer st = new StreamTokenizer(System.in);
while (st.nextToken() != StreamTokenizer.TT_EOF) {
int n = (int) st.nval;
int[] array = new int
;
for (int i = 0; i < n; i++) {
st.nextToken();
array[i] = (int) st.nval;
}
st.nextToken();
int k = (int) st.nval;
solve2(array, k);
}
}
}


View Code
  其中一开始使用Scanner的方法作为输入,优化许久还是超时,查看其它成功代码采用的是StreamTokenizer方式作为输入。也改为StreamTokenizer方式后,提交通过。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: