剑指offer14-I.剪绳子

剑指offer14-I.剪绳子_第1张图片

 昨天写的那道题是数组中除了一个元素外其余元素的乘积,这道题自然就想到了把一个数分成两个的和,然后积就是这两个数的积,而这两个数中的每个数又可以分成两个数,所以可以用动态规划的方法,dp[i] = dp[j]*dp[i-j]。但是这样的话就会有重复,就是j和i-j后面会交换,而且这样会少一个i*1也就是说dp[j]也会少一个j*1,所以可以用dp[i] = j * dp[i-j],这样的话还漏了一种情况就是j*(i-j),因为dp[i-j]里面是没有(i-j)*1的,只有(i-j-1)*1,所以要把这种情况补上,也就是说当其中一个加数为j时的最大积是Math.max(j*(i-j), j*dp[i-j]),dp[i]的值是要把所有j都遍历完取其中的最大值。

class Solution {
    public int cuttingRope(int n) {
        int[] dp = new int[n+1];
        dp[0] =0;dp[1]=0;
        for(int i = 2;i<=n;i++){
            int max = 0;
            for(int j=1;j

题解的动态的规划是把绳子全拆成2的段或者3的段,这样的乘积最大,而且是要更多的拆分出3,它的证明非常长,记结论就好了,我记的算法课上老师讲过的一个找出假币的题目,也是把所有币分成2堆或者3堆是能最快找出假币的,这是题解代码:

class Solution {
    public int cuttingRope(int n) {
        if (n <= 3) {
            return n - 1;
        }
        int[] dp = new int[n + 1];
        dp[2] = 1;
        for (int 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];
    }
}

题解还有一种用高数解的,看完这个就知道为什么要分成2和3了。

剑指offer14-I.剪绳子_第2张图片

剑指offer14-I.剪绳子_第3张图片 通过求极限的方法求到驻点是e,但是只能取整数,所以取和e相邻的2和3,然后又算到3更好,但是不是每个数都能全分成3的,所以有时候也要分成2。

什么时候取2,取多少个2呢?

剑指offer14-I.剪绳子_第4张图片

 于是就有以下代码:

class Solution {
    public int cuttingRope(int n) {
        if (n <= 3) {
            return n - 1;
        }
        int quotient = n / 3;
        int remainder = n % 3;
        if (remainder == 0) {
            return (int) Math.pow(3, quotient);
        } else if (remainder == 1) {
            return (int) Math.pow(3, quotient - 1) * 4;
        } else {
            return (int) Math.pow(3, quotient) * 2;
        }
    }
}

你可能感兴趣的:(剑指offer,动态规划,算法,leetcode,java)