給定一個數組,判斷數組內是否存在一個連續區間,使其和剛好等於給定整數k。php
輸入包含多組測試用例,每組測試用例由一個整數n(1<=n<=10000)開頭,表明數組的大小。
接下去一行爲n個整數,描述這個數組,整數絕對值不大於100。
最後一行爲一個整數k(大小在int範圍內)。java
對於每組測試用例,若存在這個連續區間,輸出其開始和結束的位置,s,e(s <= e)。
若存在多個符合條件的輸出,則輸出s較小的那個,若仍然存在多個,輸出e較小的那個。
若不存在,直接輸出"No"。node
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。ide
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方式後,提交經過。測試