一天一大 leet(整数拆分)难度:中等-Day20200730

img

题目:

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。

示例:

  1. 示例 1
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
  1. 示例 2
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。

说明:

你可以假设 n 不小于 2 且不大于 58。

抛砖引玉

img

思路

拆成 n 个数,n 不固定
这种类型的题目:规则确定,起始条件不确定

  • 动态规划
  • 递归

动态规划

枚举 n,dp 记录不同 n 的结果值,dp[n]即查询结果:

  • 确定拆分的整数个数: 2 < = i < = n 2<=i<=n 2<=i<=n
  • dp[i]为 i 拆分的整数乘积最大值
    • 拆分两个以上j,dp[i - j] -> dp[i - j]拆分两个即以上子集
    • 拆分两个j,i-j
/**
 * @param {number} n
 * @return {number}
 */
var integerBreak = function (n) {
  let dp = Array(n + 1).fill(1)
  for (let i = 2; i <= n; i++) {
    let curMax = 0
    for (let j = 1; j < i; j++) {
      curMax = Math.max(curMax, Math.max(j * (i - j), j * dp[i - j]))
    }
    dp[i] = curMax
  }
  return dp[n]
}

递归

  • 参数,要拆分的整数
  • 终止条件:
    • 遇到已经拆分过的数组

递归的逻辑基本和动态规划一致:

  • 拆分一个数字j出来
  • 属于的i-j可以独立作为一个数字,也可以继续拆分
/**
 * @param {number} n
 * @return {number}
 */
var integerBreak = function (n) {
  let dp = Array(n + 1).fill(1)
  function dfs(n){
    if (dp[n]) return dp[n];
    let curMax = 0;
    for (let i = 1; i < n; i++) {
      curMax = Math.max(curMax, i * (n - i), i * dfs(n - i));
    }
    return dp[n] = curMax;
  };
  return dp[n]
}

优化的动态规划

/**
 * @param {number} n
 * @return {number}
 */
var integerBreak = function (n) {
  if (n < 4) return n - 1;
  let dp = Array(n + 1).fill(1)
  for (let i = 3; i <= n; i++) {
    dp[i] = Math.max(Math.max(2 * (i - 2), 2 * dp[i - 2]), Math.max(3 * (i - 3), 3 * dp[i - 3]));
  }
  return dp[n];
}

img

题目:

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。

示例:

  1. 示例 1
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
  1. 示例 2
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。

说明:

你可以假设 n 不小于 2 且不大于 58。

抛砖引玉

img

思路

拆成 n 个数,n 不固定
这种类型的题目:规则确定,起始条件不确定

  • 动态规划
  • 递归

动态规划

枚举 n,dp 记录不同 n 的结果值,dp[n]即查询结果:

  • 确定拆分的整数个数: 2 < = i < = n 2<=i<=n 2<=i<=n
  • dp[i]为 i 拆分的整数乘积最大值
    • 拆分两个以上j,dp[i - j] -> dp[i - j]拆分两个即以上子集
    • 拆分两个j,i-j
/**
 * @param {number} n
 * @return {number}
 */
var integerBreak = function (n) {
  let dp = Array(n + 1).fill(1)
  for (let i = 2; i <= n; i++) {
    let curMax = 0
    for (let j = 1; j < i; j++) {
      curMax = Math.max(curMax, Math.max(j * (i - j), j * dp[i - j]))
    }
    dp[i] = curMax
  }
  return dp[n]
}

递归

  • 参数,要拆分的整数
  • 终止条件:
    • 遇到已经拆分过的数组

递归的逻辑基本和动态规划一致:

  • 拆分一个数字j出来
  • 属于的i-j可以独立作为一个数字,也可以继续拆分
/**
 * @param {number} n
 * @return {number}
 */
var integerBreak = function (n) {
  let dp = Array(n + 1).fill(1)
  function dfs(n){
    if (dp[n]) return dp[n];
    let curMax = 0;
    for (let i = 1; i < n; i++) {
      curMax = Math.max(curMax, i * (n - i), i * dfs(n - i));
    }
    return dp[n] = curMax;
  };
  return dp[n]
}

优化的动态规划

/**
 * @param {number} n
 * @return {number}
 */
var integerBreak = function (n) {
  if (n < 4) return n - 1;
  let dp = Array(n + 1).fill(1)
  for (let i = 3; i <= n; i++) {
    dp[i] = Math.max(Math.max(2 * (i - 2), 2 * dp[i - 2]), Math.max(3 * (i - 3), 3 * dp[i - 3]));
  }
  return dp[n];
}

博客: 小书童博客

每天的每日一题,写的题解会同步更新到公众号一天一大 lee 栏目
欢迎关注留言

公号: 坑人的小书童

坑人的小书童

探险家小扣的行动轨迹,都将保存在记录仪中。expeditions[i] 表示小扣第 i 次探险记录,用一个字符串数组表示。其中的每个「营地」由大小写字母组成,通过子串 -> 连接。例:"Leet->code->Campsite",表示到访了 "Leet"、"code"、"Campsite" 三个营地。expeditions[0] 包含了初始小扣已知的所有营地;对于之后的第 i 次探险(即 expeditions[i] 且 i > 0),如果记录中包含了之前均没出现的营地,则表示小扣 新发现 的营地。 请你找出小扣发现新营地最多且索引最小的那次探险,并返回对应的记录索引。如果所有探险记录都没有发现新的营地,返回 -1。注意: 大小写不同的营地视为不同的营地; 营地的名称长度均大于 0。用python实现。给你几个例子:示例 1: 输入:expeditions = ["leet->code","leet->code->Campsite->Leet","leet->code->leet->courier"] 输出:1 解释: 初始已知的所有营地为 "leet" 和 "code" 第 1 次,到访了 "leet"、"code"、"Campsite"、"Leet",新发现营地 2 处:"Campsite"、"Leet" 第 2 次,到访了 "leet"、"code"、"courier",新发现营地 1 处:"courier" 第 1 次探险发现的新营地数量最多,因此返回 1。示例 2: 输入:expeditions = ["Alice->Dex","","Dex"] 输出:-1 解释: 初始已知的所有营地为 "Alice" 和 "Dex" 第 1 次,未到访任何营地; 第 2 次,到访了 "Dex",未新发现营地; 因为两次探险均未发现新的营地,返回 -1
04-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值