-
题目描述:
-
给定一个数组,判断数组内是否存在一个连续区间,使其和恰好等于给定整数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
package jobdu.wangdao; import java.util.Scanner; /** * 题目描述: 给定一个数组,判断数组内是否存在一个连续区间,使其和恰好等于给定整数k。 * */ public class Question1554 { private static void 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)); break; } } } } if (!find) System.out.println("No"); } public static void main(String[] args) { @SuppressWarnings("resource") Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { int n = scanner.nextInt(); int[] array = new int[n]; for (int i = 0; i < n; i++) { array[i] = scanner.nextInt(); } int k = scanner.nextInt(); solve(array, k); } } }
这个解答用的是暴力o(n*n)破解,提交后九道提示超时。
用动态规划的思想,记录从a[0]开始到a[i]的和存入sum[i],那么当sum[i]-sum[j]=k的时候从a[j+1]到a[i]的和就为k。
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[n]; for (int i = 0; i < n; i++) { st.nextToken(); array[i] = (int) st.nval; } st.nextToken(); int k = (int) st.nval; solve2(array, k); } } }
其中一开始使用Scanner的方法作为输入,优化许久还是超时,查看其它成功代码采用的是StreamTokenizer方式作为输入。也改为StreamTokenizer方式后,提交通过。