1. 程式人生 > 其它 >leetcode 劍指 Offer 57 - II. 和為s的連續正數序列

leetcode 劍指 Offer 57 - II. 和為s的連續正數序列

技術標籤:指標演算法資料結構dfsleetcode

劍指 Offer 57 - II. 和為s的連續正數序列

輸入一個正整數 target ,輸出所有和為 target 的連續正整數序列(至少含有兩個數)。序列內的數字由小到大排列,不同序列按照首個數字從小到大排列。

示例 1:

輸入:target = 9
輸出:[[2,3,4],[4,5]]

示例 2:

輸入:target = 15
輸出:[[1,2,3,4,5],[4,5,6],[7,8]]

限制:

1 <= target <= 10^5

解法一:dfs深度優先搜尋

思路:

dfs深度優先搜尋,每次新增之前先判斷temp是否為空或者 temp 是是否包含 i - 1,

 1 class Solution {
 2     public int[][] findContinuousSequence(int target) {
 3         ArrayList<LinkedList<Integer>> res = new ArrayList<LinkedList<Integer>>();
 4         LinkedList<Integer> temp = new LinkedList<Integer>();
 5         // 使用dfs將所有的組合都找到並存在res列表中
 6         dfs(0, target, 0, res, temp);
 7         //System.out.println(res);
 8         // 將res中的內容拷貝到一個二維陣列中
 9         int[][] ret = new int[res.size()][];
10         for(int i= 0; i < res.size(); i++){
11             ret[i] = new int[res.get(i).size()];
12             for(int j = 0; j < res.get(i).size(); j++){
13                 ret[i][j] = res.get(i).get(j);
14             }
15         }
16         return ret;        
17     }
18 
19     // dfs遞迴
20     public void dfs(int nowSum, int target, int nowNum, ArrayList<LinkedList<Integer>> res, LinkedList<Integer> temp){
21         if(nowSum == target){
22             res.add(new LinkedList<Integer>(temp));
23             return;
24         }
25         if(nowSum > target){
26             return;
27         }
28         // 嘗試新增每個大於當前數字的元素
29         for(int i = nowNum + 1; i < target; i++){
30             //System.out.println(i);
31             // 只能是連續的數字組合
32             if((temp.isEmpty() || temp.contains(i-1)) && nowSum + i <= target){
33                 temp.addLast(i);
34                 dfs(nowSum + i, target, i, res, temp);
35                 temp.removeLast();  // 回溯之後消除上次新增元素的影響
36             }
37         }
38 
39     }
40 }

這個方法當target比較大的時候會超時,只通過了22個測試用例

解法二:迭代

思路:

迭代, 以1-target/2的所有元素為起點,尋找滿足條件的組合

 1 class Solution {
 2     public int[][] findContinuousSequence(int target) {
 3         ArrayList<int[]> res = new ArrayList<>();
 4         
 5         int sum = 0, limit = target / 2;    // 因為最少兩個數,所以上界為target / 2
 6         for(int i = 1; i <= limit; i++){
 7             for(int j = i; ; j++){
 8                 sum += j;
 9                 if(sum > target){
10                     sum = 0;
11                     break;
12                 }else if(sum == target){
13                     int[] arr = new int[j - i + 1];
14                     for(int k = i; k <= j; k++){
15                         arr[k-i] = k;
16                     }
17                     res.add(arr);
18                 }
19             }
20         }
21 
22         return res.toArray(new int[res.size()][]);        
23     }
24 }

leetcode執行時間為8ms, 空間為36.6MB

複雜度分析:

空間複雜度:除了儲存結果的陣列只需要常數個變數,所以空間複雜度為O(1)

解法三:滑動視窗

思路:

滑動視窗,這個解法其實是對上個解法的改進,當我們判斷到[i,j+1]的元素之和已經大於 target了,解法二是直接從( i + 1)開始,加上(i + 2), 一直到 下次sum 大於 target, 假設區間為 [i+1, k], 但是其實這個區間的[i+1,j]的和在上一次迭代的時候就已經求出來了,所以我們只需要在上一次迭代的sum減去 i, 然後從j開始累加,一直累加到k, 這樣可以避免很多重複計算

 1 class Solution {
 2     public int[][] findContinuousSequence(int target) {
 3         ArrayList<int[]> res = new ArrayList<>();
 4         
 5         int sum = 0, limit = target / 2;    // 因為最少兩個數,所以上界為target / 2
 6         int i = 1, j = 1;
 7         while(i <= limit){
 8             if(sum < target){
 9                 sum += j;
10                 j++;        // 右指標後移
11             }else if(sum > target){
12                 sum -= i;
13                 i++;        // 左指標右移
14             }else{
15                 int[] arr = new int[j-i];       // j還沒被新增到sum中,所以區間大小為j - i
16                 for(int k = i; k < j; k++){
17                     arr[k-i] = k;
18                 }
19                 res.add(arr);
20                 sum -= i;
21                 i++;
22             }
23                
24         }
25 
26         return res.toArray(new int[res.size()][]);        
27     }
28 }

leetcode執行時間為:2ms, 空間為36.9MB

複雜度分析:

時間複雜度:右指標沒有回溯,所以相當於兩個指標都從 1增大到了 target/2, 所以時間複雜度為O(target)

空間複雜度:除了儲存結果的陣列只需要常數個變數,所以空間複雜度為O(1)