算法训练:整数拆分(动态规划)

手机游戏开发者 2024-9-10 00:50:49 22 0 来自 中国
一.媒介

迩来不绝在了解动态规划,这是LeetCode上面的一道动规的题。
343. 整数拆分
给定一个正整数 n ,将其拆分为 k 个 正整数 的和( k >= 2 ),并使这些整数的乘积最大化。
返回 你可以得到的最大乘积
示例1:
输入: n = 2
输出: 1
表明: 2 = 1 + 1, 1 × 1 = 1。
示例2:
输入: n = 10
输出: 36
表明: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
二.思绪

说到动态规划,我认为最重要的就是确定自己的 dp数组 的寄义,其次就是 递推公式 了。

  • 确定 dp 的寄义
我们重新浏览一遍题,给定一个正整数 n ,须要将它分成多少个整数,返回最大的乘积。因此我们可以界说 dp 表现每个正整数拆分为多少个正整数所对应的最大乘积,若要确定 dp 的值,我们可以根据 dp 从前的元素举行运算从而得到最大的
dp 的值。

  • 确定 dp 的值
dp 的值是由两种方式来共同确定的。
第一,dp = dp[i - j] * j 此中 i 代表外层循环, j 代表内层循环,j 从 1 开始逐个求出 dp ,最后取最大值。
第二,dp = (i - j) * j,同上,也是取最大值。上面那种方式是将 i 分成了 n 个 (n > 2)。而这种方式是将 i 分成了n 个 (n = 2)。

  • 确定递推公式
实在到这里,递推公式大抵样式也就出来了:
dp = Math.max(dp, Math.max(dp[i - j] * j, (i - j) * j)) ,那么大概会有人问为什么还要比力一次 dp 呢?因为我们内层循环中一周后,会算出许多 dp ,我们只须要生存最大的 dp
三.代码

class Solution {    public int integerBreak(int n) {        int[] dp = new int[n + 1];        //dp[2]对应的值应该是1,而dp[2]之前的元素在此题目中无现实意义,因此无需初始化        dp[2] = 1;        for(int i = 3; i <= n; i++){            for(int j = 1; j <= i - j; j++){                dp = Math.max(dp, Math.max(dp[i - j] * j, j * (i - j)));            }        }        return dp[n];    }}时间复杂度 O(n^2)

  • 题外话
    这道题用动态规划的话时间复杂度好像有点高,实在这道题可以用数学方法来写的,这里用到一个结论:当整数 n 尽大概地平分为 3时乘积最大。假如感爱好的同砚可以去证实一下。
class Solution {    public int integerBreak(int n) {        if(n <= 3) return n - 1;        int a = n / 3, b = n % 3;        //当 n 分刚好能分成多少个 3 时        if(b == 0) return (int)Math.pow(3, a);        //当 n 尽大概分成 3 时,余出一个 1         if(b == 1) return (int)Math.pow(3, a - 1) * 4;        //当 n 尽大概分成 3 时,余出一个 2        return (int)Math.pow(3, a) * 2;    }}时间复杂度:O(1)
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-12-4 16:49, Processed in 0.161518 second(s), 32 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表