劍指 offer 第 24 天
阿新 • • 發佈:2021-09-28
第 24 天
數學(中等)
劍指 Offer 14- I. 剪繩子
給你一根長度為 n
的繩子,請把繩子剪成整數長度的 m
段(m、n都是整數,n>1並且m>1),每段繩子的長度記為 k[0],k[1]...k[m-1]
。請問 k[0]*k[1]*...*k[m-1]
可能的最大乘積是多少?例如,當繩子的長度是8時,我們把它剪成長度分別為2、3、3的三段,此時得到的最大乘積是18。
示例 1:
輸入: 2
輸出: 1
解釋: 2 = 1 + 1, 1 × 1 = 1
示例 2:
輸入: 10
輸出: 36
解釋: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
提示:
2 <= n <= 58
題解思路:動態規劃、貪婪演算法
動態規劃:不斷計算切一刀後乘積的變化
class Solution { public int cuttingRope(int n) { // 記錄長度為 i 的繩子乘積最大值 int[] dp = new int[n + 1]; dp[2] = 1; // 從繩子長度為 3 開始計算,因為長度為 2 時為1 for (int i = 3; i <= n; i ++) { // 計算減長度為 j 的一刀後是否繼續減,如果剪完 j 後繼續剪,乘積為 dp[i-j]*j,如果不減,則乘積為 (i-j)*j for (int j = 2; j < i; j ++) { dp[i] = Math.max(dp[i], Math.max(dp[i-j]*j, (i-j)*j)); } } return dp[n]; } }
複雜度:時間 O(n*n) 空間 O(n)
貪婪演算法:獲得儘可能多的 3,可以用求導證明
class Solution {
public int cuttingRope(int n) {
if(n < 4){
return n - 1;
}
int res = 1;
while(n > 4){
res *= 3;
n -= 3;
}
return res * n;
}
}
複雜度:時間 O(n) 空間 O(1)
劍指 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
題解思路:滑動視窗
滑動視窗:雙指標構成滑動視窗,搜尋所有可以的集合
class Solution {
public int[][] findContinuousSequence(int target) {
int i = 1, j = 2;
int sum = 3;
List<int[]> res = new ArrayList<>();
while(i < j) {
if(sum > target) {
sum -= i;
i ++;
}
else if (sum < target){
j ++;
sum += j;
}
else if (sum == target) {
int[] ans = new int[j - i + 1];
for(int k = i; k <= j; k++) {
ans[k - i] = k;
}
res.add(ans);
sum -= i;
i++;
}
}
return res.toArray(new int[0][]);
}
}
複雜度:時間 O(n) 空間 O(n)
劍指 Offer 62. 圓圈中最後剩下的數字
0,1,···,n-1這n個數字排成一個圓圈,從數字0開始,每次從這個圓圈裡刪除第m個數字(刪除後從下一個數字開始計數)。求出這個圓圈裡剩下的最後一個數字。
例如,0、1、2、3、4這5個數字組成一個圓圈,從數字0開始每次刪除第3個數字,則刪除的前4個數字依次是2、0、4、1,因此最後剩下的數字是3。
示例 1:
輸入: n = 5, m = 3
輸出: 3
示例 2:
輸入: n = 10, m = 17
輸出: 2
限制:
1 <= n <= 10^5
1 <= m <= 10^6
題解思路:模擬、動態規劃、遞迴
模擬:迴圈佇列模擬
class Solution {
public int lastRemaining(int n, int m) {
ArrayList<Integer> list = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
list.add(i);
}
int idx = 0;
while (n > 1) {
idx = (idx + m - 1) % n;
list.remove(idx);
n--;
}
return list.get(0);
}
}
複雜度:時間 O(n) 空間 O(n)
動態規劃:
class Solution {
public int lastRemaining(int n, int m) {
int f = 0;
for (int i = 2; i != n + 1; ++i) {
f = (m + f) % i;
}
return f;
}
}
複雜度:時間 O(n) 空間 O(1)
遞迴:
class Solution {
public int lastRemaining(int n, int m) {
return f(n, m);
}
public int f(int n, int m) {
if (n == 1) {
return 0;
}
int x = f(n - 1, m);
return (m + x) % n;
}
}
複雜度:時間 O(n) 空間 O(n)