1 題目描述
輸入一個正整數 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
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
2 解題思路
- 方法:滑動窗口
什麼是滑動窗口
滑動窗口可以看成數組中框起來的一個部分。在一些數組類題目中,我們可以用滑動窗口來觀察可能的候選結果。當滑動窗口從數組的左邊滑到了右邊,我們就可以從所有的候選結果中找到最優的結果。
對於這道題來說,數組就是正整數序列 [1,2,3,…,n]。我們設滑動窗口的左邊界爲 i,右邊界爲 j,則滑動窗口框起來的是一個左閉右開區間 [i,j)。注意,爲了編程的方便,滑動窗口一般表示成一個左閉右開區間。在一開始,i=1,j=1,滑動窗口位於序列的最左側,窗口大小爲零。
如何用滑動窗口解這道題
要用滑動窗口解這道題,我們要回答兩個問題:
第一個問題,窗口何時擴大,何時縮小?
第二個問題,滑動窗口能找到全部的解嗎?
對於第一個問題,回答非常簡單:
- 當窗口的和小於 target 的時候,窗口的和需要增加,所以要擴大窗口,窗口的右邊界向右移動
- 當窗口的和大於 target 的時候,窗口的和需要減少,所以要縮小窗口,窗口的左邊界向右移動
- 當窗口的和恰好等於 target 的時候,我們需要記錄此時的結果。設此時的窗口爲 [i,j),那麼我們已經找到了一個 i 開頭的序列,也是唯一一個 i 開頭的序列,接下來需要找 i+1 開頭的序列,所以窗口的左邊界要向右移動
對於第二個問題,我們可以稍微簡單地證明一下:
我們一開始要找的是 1 開頭的序列,只要窗口的和小於 target,窗口的右邊界會一直向右移動。假設 1+2+⋯+8 小於 target,再加上一個 9 之後, 發現 1+2+⋯+8+9 又大於 target 了。這說明 1 開頭的序列找不到解。此時滑動窗口的最右元素是 9。
接下來,我們需要找 2 開頭的序列,我們發現,2+⋯+8<1+2+⋯+8<target。這說明 2 開頭的序列至少要加到 9。那麼,我們只需要把原先 1~9 的滑動窗口的左邊界向右移動,變成 2~9 的滑動窗口,然後繼續尋找。而右邊界完全不需要向左移動。
以此類推,滑動窗口的左右邊界都不需要向左移動,所以這道題用滑動窗口一定可以得到所有的解。時間複雜度是 O(n)。
作者:nettee
鏈接:https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/solution/shi-yao-shi-hua-dong-chuang-kou-yi-ji-ru-he-yong-h/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
3 解決代碼
- 方法:滑動窗口《java代碼》
class Solution {
public int[][] findContinuousSequence(int target) {
int i = 1;
int j = 1;
int sum = 0;
List<int[]> res = new ArrayList<>();
while(i <= target/2){
if(sum < target){
// 右邊界向右移動
sum += j;
j++;
}
else if(sum > target){
// 左邊界向右移動
sum -= i;
i++;
}
else{
// 記錄結果
int[] arr = new int[j - i];
//對應位置打印,k-i是0,放i,爲1,放i+1,依次遞增
for(int k = i; k <j; k++){
arr[k-i] = k;
}
res.add(arr);
// 左邊界向右移動
sum -= i;
i++;
}
}
//最後輸出的是二維數組
return res.toArray(new int[res.size()][]);
}
}
- 方法:滑動窗口《python3代碼》
class Solution:
def findContinuousSequence(self, target: int) -> List[List[int]]:
i = 1
j = 1
sum = 0
res = []
while i <= target//2:
if sum < target:
sum += j
j += 1
elif sum > target:
sum -= i
i += 1
else:
arr = list(range(i, j))
res.append(arr)
sum -= i
i += 1
return res