整数拆分题解

2020.07.30 力扣每日一题----整数拆分的动态规划解法

问题描述

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

示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1

示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
说明: 你可以假设 n 不小于 2 且不大于 58

解题思路

  拿到这题,第一反应就是利用数学分析肯定可以解出来,再想想,用动态规划肯定也行,只是在时间复杂度上会高一些,这里就不给数学分析法的了,很简单的代码,时间复杂度也绝对优于动态规划,但是最近在学动态规划,所以在这写个dp的题解。

直接粗暴的动态规划

  既然是动态规划,自然需要建立一个数组dp[ ]用于存放每个n的最优解,然后找到状态转移方程和出口。 题目就叫做整数拆分,自然先需要拆分成两个正整数,之后无非就两种情况,继续拆或者不拆了:
  首先将 i 拆分成 j +(i - j)
  不拆了:乘积为 i * (i - j);
  继续拆:乘积为 j *dp[ i - j ] ;
所以状态转移方程就是dp[i] = Max{ i * ( i - j ) , j * dp[ i - j ] } ;
出口就更简单了,因为0和1不可能拆分成两个正整数,所以dp[0] = dp[1] = 0
代码(我这里返回值用的是数组,这样能很直观的看出每个n的最优解):

public static int[] integerBreakByDp(int n) {
        int[] dp = new int[n + 1];
        for (int i = 2; i < n + 1; i++) {
            int curMax = 0;
            for (int j = 1; j < i; j++) {
                //因为不确定j是多少时能得出最大的乘积,所以加一层Max用来判断新的j做出的乘积是否比上一次结果更大
                curMax = Math.max(curMax, Math.max(j * (i - j), j * dp[i - j]));
            }
            dp[i] = curMax;
        }
        return dp;
    }

因为嵌套一次循环,所以很简单得出时间复杂度为O(n2)。

题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/integer-break

猜你喜欢

转载自blog.csdn.net/TreeCode/article/details/107702874