LeetCode每日1题--343. 整数拆分

106 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 10 天,点击查看活动详情

前言

算法的重要性不言而喻!区分度高!

现在学习的门槛低了,只有能上网每个人都可以学编程!培训班6个月就可以培养出来能干活的人,你怎么从这些人中脱颖而出?没错!就是学算法,学一些底层和基础的东西。

说的功利点是为了竞争,卷死对手。真心话说就是能提高自己的基础能力,为技术可持续发展做好充分的准备!!!

提前入门学习书籍:CPrimerPlus、大话数据结构

image-20220705103735001

刷题网站

代码随想录 (programmercarl.com)

leetcode

我是按照代码随想录提供的刷题顺序进行刷题的,大家也可以去刷leetcode最热200道,都可以

刷题嘛,最重要的就是坚持了!!!

画图软件

OneNote

这个要经常用,遇见不懂的流程的话就拿它画一画!

笔记软件

Typoral

题目

343. 整数拆分 - 力扣(LeetCode)

image.png

解析

当一个问题有很多重叠的子问题,每一个状态都是由上一个状态推导出来的,使用DP是最有效的!

这题直接就是看题解,看到别人用数学公式推导得出

① 当所有拆分出的数字相等时,乘积最大。

② 最优拆分数字为 3。

我们就不用去证明了,直接拿来用。原文链接为:343. 整数拆分(数学推导,清晰图解) - 整数拆分 - 力扣(LeetCode)

我们需要学会用DP去解决这个问题

动态规划解题套路

  1. 确定dp数组以及下标的含义

dp[i]:拆分数字i,dp[i]为最大乘积

后面我们要贯彻这个思想,如果忘了就来想一下,dp[i]表示拆分数字i的最大乘积

  1. 确定递推公式

前面解析我们知道,想要获得最大乘积有两种方式:

  • 当所有拆分出的数字相等时,乘积最大。
  • 最优拆分数字为 3。

那么递推公式(状态转移方程)该怎么写呢?

  • 我们可以让j从1开始遍历,然后就能得到dp[i] = j * (i - j)
  • 一个是dp[i] = j * dp[i-j]

所以递推公式为:

dp[i] = Math.max(dp[i],Math.max(i*(i-j),i*dp[i-j]))

dp[i-j]什么意思???

想一下dp[i]的定义,dp[i]表示拆分数字i的最大乘积

那么dp[i-j],dp[i-j]表示拆分数字i-j的最大乘积

举例说明:i = 10,j = 1求整数拆分后的最大乘积

  • dp[i] = j * (i - j) --> 10 = 1 + 9 --> 1 * (10 -1) = 9
  • dp[i] = j * dp[i-j] --> 10 = 1 + 1 + 8 --> 1 * 1 * 8 = 8

当 j = 2 时,推导如下:

  • dp[i] = j * (i - j) --> 10 = 2 + 8 --> 2 * (10 -2) = 16
  • dp[i] = j * dp[i-j] --> 10 = 2 + 2 + 6 --> 2 * 2 * 6 = 24

当 j = 3 时,推导如下:

  • dp[i] = j * (i - j) --> 10 = 3 + 7 --> 3 * (10 -3) = 21
  • dp[i] = j * dp[i-j] --> 10 = 3 + 3 + 4 --> 3 * 3 * 4 = 36

...

  1. dp数组如何初始化

dp[0]和dp[1]怎么定义呢?它们怎么拆分呢?我们不定义,我们直接定义dp[2]

dp[2] = 1

  1. 确定遍历顺序

dp[i]的状态依赖dp[i-j]所以肯定是从前向后遍历

至于j枚举的时候,我们可以做一点优化,j <= i / 2,因为j大于i / 2 的话其实就是重复计算

  1. 举例推导dp数组
  • dp[i] = j * (i - j) --> 10 = 1 + 9 --> 1 * (10 -1) = 9
  • dp[i] = j * dp[i-j] --> 10 = 1 + 1 + 8 --> 1 * 1 * 8 = 8

当 j = 2 时,推导如下:

  • dp[i] = j * (i - j) --> 10 = 2 + 8 --> 2 * (10 -2) = 16
  • dp[i] = j * dp[i-j] --> 10 = 2 + 2 + 6 --> 2 * 2 * 6 = 24

当 j = 3 时,推导如下:

  • dp[i] = j * (i - j) --> 10 = 3 + 7 --> 3 * (10 -3) = 21
  • dp[i] = j * dp[i-j] --> 10 = 3 + 3 + 4 --> 3 * 3 * 4 = 36

...

是不是非常的神奇呢?

第一次写要多理解DP的套路,然后多练习就可以了!

完整代码

看不懂?没办法,多写多练多总结!

还是带入代码到示例中多去总结多练习!

class Solution {
    public int integerBreak(int n) {
        int[] dp = new int[n+1];
        dp[2] = 1;
        for(int i = 3;i<=n;i++){
            for(int j = 1;j<= i-j;j++){
                dp[i] = Math.max(dp[i],Math.max(j * (i-j),j*dp[i-j]));
            }
        }
        return dp[n];
    }
}