1.トピック
正の整数のターゲットを入力し、合計がターゲットであるすべての連続する正の整数シーケンス(少なくとも2つの数値を含む)を出力します。
シーケンス内の番号は最小から最大に配置され、異なるシーケンスは最初の番号に従って最小から最大に配置されます。
例1:
输入:target = 9
输出:[[2,3,4],[4,5]]
例2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
制限:
- 1 <=ターゲット<= 10 ^ 5
二、解く
1.スライディングウィンドウ
アイデア:
スライディングアレイ:アレイのフレーム部分と見なすことができます。プログラミングの便宜のために、左閉と右開の間隔に設定されています。
初期値:i = 1、j = 1、スライディングウィンドウはシーケンスの左端にあり、ウィンドウサイズは0です。
自然:ウィンドウの左右の境界線は常に右にのみ移動できますが、左には移動できません。
プロセス:
- 定義:ウィンドウ内のいくつかの数値の合計
sum
、左端点i
と右端点j
。 - ウィンドウの移動と結果記録:
2.1場合sum < target
、sum
増やす必要がある、ウィンドウを展開し、右マージンが右に移動しますj++
;
場合は2.2sum > target
、sum
であることを、減少させる必要がウィンドウを縮小、及び左移動右側の余白i++
、;
2.3。の場合sum = target
、この時点で結果を記録します。つまり、[i, j)
要素を書き留めます。これはi
、最初の唯一のシーケンスでもあります。次に、左マージンを右に移動しますi++
、; - トラバーサルが完了すると、結果セットが返されます。
質問:ウィンドウを移動してすべての解決策を見つけることができますか?
分析:
1) 1 + 2 +...+ 8 < target
2) 1 + 2 +...+ 8 + 9 > target
由1)2)可得,说明 1 开头的序列找不到解。
3)寻找以2开头的序列:2+...+8 < 1+2+...+8 < target.
2+3+...+8+9 ? target,如果两端相等,则记录下该序列,然后左边界右移。
结论:该2开始的序列唯一。
进一步推论,每个元素开始的序列都有判断,如果与target相等,均唯一,所以能找到全部解。
コード:
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];
for (int k = i; k < j; k++) {
arr[k-i] = k;
}
res.add(arr);
// 左边界向右移动
sum -= i;
i++;
}
}
return res.toArray(new int[res.size()][]);
}
}
時間計算量: O(n)O(n)O (n )
スペースの複雑さ: O(n)O(n)O (n )
2.累積特性
アイデア:
2つの連続する数値が等しいtarget
場合、差は1で(target - 1) % 2 == 0
あり、配列(target - 1) / 2
は配列要素の先頭からでなければなりません2
。
3
連続配列の場合、番号31、2,(target - 1 - 2) % 3 == 0
と配列の間の位相差(target - 1 - 2) / 3
は、配列要素の先頭からでなければなりません3
。
類推しtarget
ますが0
、それは、より大きい数でなければならず、res
順序を逆にする必要があることに注意してください。まだ理解していない場合は、理解のtarget=9
代わりに使用できます。
コード:
class Solution {
public int[][] findContinuousSequence(int target) {
List<int[]> result = new ArrayList<>();
int i = 1;
while(target/2 > 0) {
target -= i++;
if(target>0 && target%i == 0) {
int[] array = new int[i];
for(int k = target/i, j = 0; k < target/i + i; k++, j++) {
array[j] = k;
}
result.add(array);
}
}
Collections.reverse(result);
return result.toArray(new int[0][]);
}
}
時間計算量: O(n)O(n)O (n )
スペースの複雑さ: O(n)O(n)O (n )
拡張:829と同様です。連続する整数の合計ですが、戻り値が異なります。いくつかのアイデアと方法を参照に使用できます。
3、参照
1.スライディングウィンドウとは何ですか。スライディングウィンドウを使用してこの問題を解決する方法(C ++ / Java / Python)
2。数学の問題、数学的な解決策
3. Java double 100%