算法学习day41动态规划part03-34396

Posted lipin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法学习day41动态规划part03-34396相关的知识,希望对你有一定的参考价值。

package LeetCode.DPpart03;
/**
 * 343. 整数拆分
 * 给定一个正整数 n ,将其拆分为 k 个 正整数 的和( k >= 2 ),并使这些整数的乘积最大化。
 * 返回 你可以获得的最大乘积 。
 * 示例:
 * 输入: n = 2
 * 输出: 1
 * 解释: 2 = 1 + 1, 1 × 1 = 1。
 * */
public class IntegerBreak_343 
    public static void main(String[] args) 
        int num = 2;
        int result = integerBreak(num);
        System.out.println(result);
    

    public static int integerBreak(int n) 
        //dp[i] 为正整数 i 拆分后的结果的最大乘积
        int[] dp = new int[n+1];
        dp[2] = 1;
        for(int i = 3; i <= n; i++) 
            for(int j = 1; j <= i-j; j++) 
                // 这里的 j 其实最大值为 i-j,再大只不过是重复而已,
                //并且,在本题中,我们分析 dp[0], dp[1]都是无意义的,
                //j 最大到 i-j,就不会用到 dp[0]与dp[1]
                dp[i] = Math.max(dp[i], Math.max(j*(i-j), j*dp[i-j]));
                // j * (i - j) 是单纯的把整数 i 拆分为两个数 也就是 i,i-j ,再相乘
                //而j * dp[i - j]是将 i 拆分成两个以及两个以上的个数,再相乘。
            
        
        return dp[n];
    

package LeetCode.DPpart03;
/**
 * 96. 不同的二叉搜索树
 * 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。
 * 示例:
 * 输入:n = 3
 * 输出:5
 * */

public class UniqueBinarySearchTrees_96 
    public static void main(String[] args) 
        int num = 3;
        int result = numTrees(num);
        System.out.println(result);
    
    public static int numTrees(int n) 
        //初始化 dp 数组
        int[] dp = new int[n + 1];
        //初始化0个节点和1个节点的情况
        dp[0] = 1;
        dp[1] = 1;
        for (int i = 2; i <= n; i++) 
            for (int j = 1; j <= i; j++) 
                //对于第i个节点,需要考虑1作为根节点直到i作为根节点的情况,所以需要累加
                //一共i个节点,对于根节点j时,左子树的节点个数为j-1,右子树的节点个数为i-j
                dp[i] += dp[j - 1] * dp[i - j];
            
        
        return dp[n];
    

 

LeetCode刷题笔记-动态规划-day6

文章目录

LeetCode刷题笔记-动态规划-day6

152. 乘积最大子数组

1.题目

原题链接:152. 乘积最大子数组

2.解题思路

算法:动态规划 + 滚动数组优化

  1. f[i]表示所有从0到i并且选用a[i]获得的最大乘积
  2. g[i]表示所有从0到i并且选用a[i]获得的最小乘积

则有这样几种情况:

  • 当a[i] >= 0时,f[i] = max(a[i], f[i - 1] * a[i])
  • 当a[i] < 0时,f[i] = max(a[i], g[i - 1] * a[i])
  • 当a[i] >= 0时,g[i] = min(a[i], g[i - 1] * a[i])
  • 当a[i] < 0时,g[i] = min(a[i], f[i - 1] * a[i])

可以合并为:

  1. a[i] >= 0f[i] = max(a[i], max(f[i-1] * a[i],g[i-1]*a[i]))
  2. a[i]<0f[i] = max(a[i], max(g[i-1] * a[i],f[i-1]*a[i])

可以用滚动数组优化空间。详细见代码。

3.代码

class Solution 
public:
    int maxProduct(vector<int>& a) 
        int f=a[0],g=a[0];
        int res=a[0];
        for(int i=1;i<a.size();i++)
            int t=a[i],fa=f*t,ga=g*t;
            f=max(t,max(fa,ga));
            g=min(t,min(fa,ga));
            res=max(res,f);
        
        return res;
    
;

1567. 乘积为正数的最长子数组长度

1.题目

原题链接:1567. 乘积为正数的最长子数组长度

2.解题思路

算法:动态规划

我们可以用两个数组f[i]g[i]

  • f[i]表示以下标i结尾乘积为正数的最长子数组长度
  • g[i]表示以下标i结尾乘积为负数的最长子数组长度

这里我们可以得到递推公式:

  1. 如果当前数大于0,即nums[i]>0,之前的乘积乘以当前数,正负性是不会发生改变的,所以:
    1. f[i]=f[i-1]+1
    2. 如果g[i-1]不等于0的话,才加一,如果g[i-1]本身为0,这里为正数也不会改变
  2. 如果当前数小于0,即nums[i]<0,之前的乘积乘以当前数会改变乘积的正负性,所以:
    1. 这时候g[i]应该等于f[i-1]+1,因为f[i-1]包含的数乘积是正数,乘以当前数刚好为负数。
    2. f[i]需要考虑g[i-1]情况,如果g[i-1]为0,这里f[i]也还是为0,否则f[i]=g[i-1]+1,负数乘负数为正数
  3. 如果当前数为0,即nums[i]==0,将f[i]g[i]赋值为0
  4. 每次遍历维护最大值:res=max(res,f[i]);

3.代码

class Solution 
public:
    int getMaxLen(vector<int>& nums) 
        int f=0,g=0;
        if(nums[0]>0) f=1;
        else if(nums[0]<0) g=1;

        int res=f;
        for(int i=1;i<nums.size();i++)
            if(nums[i]>0)
                f++;
                g=(g==0)?0:g+1;
            else if(nums[i]<0)
                int t=f;
                f=(g==0)?0:g+1;
                g=t+1;
            else
                f=0,g=0;
            
            res=max(res,f);
        
        return res;
    
;

以上是关于算法学习day41动态规划part03-34396的主要内容,如果未能解决你的问题,请参考以下文章

算法导论-动态规划学习笔记day01

算法学习day27回溯part03-3940131

算法学习day24回溯part01-77

算法学习day28回溯part04-937890

算法学习day31贪心part01-45553376

算法学习day08字符串part01-344541offer05151offer58