Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
前言
每天一道算法题,死磕算法
今天我们再把上次讲的动态规划的模板拿来解今天这道题目
我们再来回忆一下我们的模板
- 定义新数组
- 找到最简单的子问题
- 找到父问题
- 找到如何把父问题化成子问题(自顶向下推理不出来,就自底向上推理试试,想办法怎么把子问题在父问题循环里面使用)
题目
给你一根长度为 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
分析
1.定义新数组
let arr = [];
2.找到最简单的子问题 2还是可以分割的,所以不能分割的是1
arr[1] = 1;
3.找到父问题
以示例一为例,就是让求arr[8]为多少,那么你就要求出arr[1]到arr[7],基本动态规划的题目都这样
4.找到如何把父问题化成子问题
既然让求长度为8的绳子的最大乘积,他和让求长度为7的绳子的最大乘积有什么关系呢?
7+1=8
所以arr[7]*1是得出arr[8]的一个备选答案
还有一点需要注意的就是我们绳子最小可以分为两段,所以这也是备选答案
题解
1.首先定义一个数组
var cuttingRope = function(n) {
let arr = [];
};
2.添加最简单的子问题
var cuttingRope = function(n) {
let arr = [];
arr[1] = [1];
};
3.遍历所有的子数组
var cuttingRope = function(n) {
let arr = [];
arr[1] = 1;
// 求出所有的子数组,从第二个数字该开始,因为我们已经知道arr[1]了
for(let i=2;i<=n;i++){
}
// 返回结果
return arr[n];
};
4.要求一个最大值
var cuttingRope = function(n) {
let arr = [];
arr[1] = 1;
// 求出所有的子数组
for(let i=2;i<=n;i++){
// 我们先设置最小值为-1
let res = -1;
for(let j=1;j<i;j++){
// 求出分为两半的时候左半边
let left = Math.floor(i/2);
// arr[j]*(i-j)为根据最优子结构求值
// left*(i-left)根据最小分成两段求解
res = Math.max(res,arr[j]*(i-j),left*(i-left));
}
arr[i] = res;
}
return arr[n];
};
5.所以答案为
var cuttingRope = function(n) {
let arr = [];
arr[1] = 1;
// 求出所有的子数组
for(let i=2;i<=n;i++){
// 我们先设置最小值为-1
let res = -1;
for(let j=1;j<i;j++){
// 求出分为两半的时候左半边
let left = Math.floor(i/2);
// arr[j]*(i-j)为根据最优子结构求值
// left*(i-left)根据最小分成两段求解
res = Math.max(res,arr[j]*(i-j),left*(i-left));
}
arr[i] = res;
}
return arr[n];
};
总结
为什么我们第一步是定义新数组呢?
原因很简单,就是说明解动态规划第一步就是通过定义一个新数组