代码编织梦想

_35LeetCode代码随想录算法训练营第三十五天-动态规划

题目列表

  • 343.整数拆分
  • 96.不同的二叉搜索树

代码随想录地址

https://programmercarl.com/0343.%E6%95%B4%E6%95%B0%E6%8B%86%E5%88%86.html

https://programmercarl.com/0096.%E4%B8%8D%E5%90%8C%E7%9A%84%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91.html

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。

提示:

  • 2 <= n <= 58

思路

动态规划五部曲

  • 确定dp数组以及其下标的含义

dp[i]:分拆数字i,可以得到的最大乘积为dp[i]。

  • 递推公式

递推公式:dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j});

dp[i]:为什么与它比,因为每一次都更新要更新dp[i],要选择最大的存到dp[i]的。

(i - j) * j:将数字拆分为两个数字相乘。

dp[i - j] * j:将数字拆分为三个及以上的数字相乘。为什么不拆分j,因为在遍历过程种j的所有可能都包含了。

  • 初始化dp数组

dp[0] = 0;dp[1] = 0;dp[2] = 1。

但是本题中,只给dp[2]赋值为1。

  • 遍历顺序

从前往后遍历。

代码

动态规划

  • 时间复杂度:O(n^2)
  • 空间复杂度:O(n)
/*
 * @lc app=leetcode.cn id=343 lang=cpp
 *
 * [343] 整数拆分
 */

// @lc code=start
class Solution {
public:
    int integerBreak(int n) {
        //定义dp数组
        vector<int> dp(n + 1, 0);
        //初始化dp数组
        dp[2] = 1;
        //遍历求得最大乘积
        for(int i = 3; i <= n; i++)
            for(int j = 1; j <= i/2; j++)//为什么要只遍历到i/2, 因为要求得乘积最大值,要求拆分的数越相近越好,j越大,就越偏离最大乘积
                dp[i] = max({dp[i], j * (i - j), j * dp[i - j]});
        return dp[n];
    }
};
// @lc code=end

贪心

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

每次拆成n个3,如果剩下是4,则保留4,然后相乘,但是这个结论需要数学证明其合理性!

class Solution {
public:
    int integerBreak(int n) {
        if (n == 2) return 1;
        if (n == 3) return 2;
        if (n == 4) return 4;
        int result = 1;
        while (n > 4) {
            result *= 3;
            n -= 3;
        }
        result *= n;
        return result;
    }
};

96.不同的二叉搜索树

题目

给你一个整数 n ,求恰由 n 个节点组成且节点值从 1n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。

示例 1:

输入:n = 3
输出:5

示例 2:

输入:n = 1
输出:1

提示:

  • 1 <= n <= 19

思路

思考

在这里插入图片描述
dp[3],就是 元素1为头结点搜索树的数量 + 元素2为头结点搜索树的数量 + 元素3为头结点搜索树的数量

元素1为头结点搜索树的数量 = 右子树有2个元素的搜索树数量 * 左子树有0个元素的搜索树数量

元素2为头结点搜索树的数量 = 右子树有1个元素的搜索树数量 * 左子树有1个元素的搜索树数量

元素3为头结点搜索树的数量 = 右子树有0个元素的搜索树数量 * 左子树有2个元素的搜索树数量

有2个元素的搜索树数量就是dp[2]。

有1个元素的搜索树数量就是dp[1]。

有0个元素的搜索树数量就是dp[0]。

所以dp[3] = dp[2] * dp[0] + dp[1] * dp[1] + dp[0] * dp[2]
在这里插入图片描述

动态规划五部曲

  • 确定dp数组(dp table)以及下标的含义

i个不同元素节点组成的二叉搜索树的个数为dp[i]

  • 确定递推公式

dp[i] += dp[以j为头结点左子树节点数量] * dp[以j为头结点右子树节点数量]

j相当于是头结点的元素,从1遍历到i为止。

递推公式:dp[i] += dp[j - 1] * dp[i - j]; ,j-1 为j为头结点左子树节点数量,i-j 为以j为头结点右子树节点数量

  • dp数组如何初始化

dp[0] = 1;//表示0个节点也是二叉搜索树,一种情况

其他的可以根据递推公式推导出来。

  • 遍历顺序

从左往右的遍历顺序。

代码

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
  • 空间复杂度: O ( n ) O(n) O(n)
/*
 * @lc app=leetcode.cn id=96 lang=cpp
 *
 * [96] 不同的二叉搜索树
 */

// @lc code=start
class Solution {
public:
    int numTrees(int n) {
        //定义dp数组及其初始化
        //i个不同元素节点组成的二叉搜索树的个数为dp[i] 
        vector<int> dp(n + 1, 0);
        //dp[0] = 1;//表示0个节点也是二叉搜索树,一种情况,其他的可以根据递推公式推导出来。
        dp[0] = 1;
        for(int i = 1; i <= n; i++)
            for(int j = 0; j < i; j++)//左面有j个节点
                dp[i] += dp[j] * dp[i - j - 1];
                //dp[i - j - 1]是指右面有i - j - 1个节点
        return dp[n];
    }
};
// @lc code=end
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_44410704/article/details/128785731

-爱代码爱编程

_2LeetCode代码随想录算法训练营第二天-C++ LeetCode 题目列表: 977.有序数组的平方209.长度最小的子数组59.螺旋矩阵II 977.有序数组的平方 题目所述数组含有负数。 双指针的思路

-爱代码爱编程

_4LeetCode代码随想录算法训练营第四天-C++ 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II 24.两两交换链表中的节点 整体思路

-爱代码爱编程

_6LeetCode代码随想录算法训练营第六天-C++哈希表 454.四数相加II383.赎金信15.三数之和18.四数之和 454.四数相加II 本题不用去重,相比力扣18题相对来说简单一点。 整体思路 使用ma

-爱代码爱编程

_8LeetCode代码随想录算法训练营第八天-C++字符串 28.实现strStr()459.重复的字字符串 28.实现 strStr() KMP算法 什么是KMP 是由三位学者发明的:Knuth,Morris和

-爱代码爱编程

_7LeetCode代码随想录算法训练营第七天-C++字符串 344.反转字符串541.反转字符串II剑指Offer05.替换空格151.翻转字符串里的单词剑指Offer58-II.左旋转字符串 344.反转字符串 题

-爱代码爱编程

_12LeetCode代码随想录算法训练营第十二天-C++二叉树 二叉树基础知识 二叉树的种类 满二叉树 满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。

-爱代码爱编程

_13LeetCode代码随想录算法训练营第十三天-C++二叉树 题目列表 102.二叉树的层序遍历107.二叉树的层次遍历II199.二叉树的右视图637.二叉树的层平均值429.N叉树的层序遍历515.在每个树行中找

-爱代码爱编程

_14LeetCode代码随想录算法训练营第十四天-C++二叉树 题目列表 104.二叉树的最大深度559.n叉树的最大深度111.二叉树的最小深度222.完全二叉树的节点个数 104.二叉树的最大深度 题目 给定

-爱代码爱编程

_18LeetCode代码随想录算法训练营第十八天-C++二叉树 题目列表 530.二叉搜索树的最小绝对差501.二叉搜索树中的众数236.二叉树的最近公共祖先 530.二叉搜索树的最小绝对差 题目 给你一个二叉搜

-爱代码爱编程

_19LeetCode代码随想录算法训练营第十九天-C++二叉树 题目列表 235.二叉搜索树的最近公共祖先701.二叉搜索树中的插入操作450.删除二叉搜索树中的节点 235.二叉搜索树的最近公共祖先 题目 给定

-爱代码爱编程

_24LeetCode代码随想录算法训练营第二十四天-回溯算法 题目列表 93.复原IP地址78.子集90.子集II 代码随想录地址: https://programmercarl.com/0093.%E5%A4%8

-爱代码爱编程

_27LeetCode代码随想录算法训练营第二十七天-贪心算法 题目列表 理论基础455.分发饼干376.摆动序列53.最大子序和 代码随想录地址: https://programmercarl.com/%E8%B4

-爱代码爱编程

_29LeetCode代码随想录算法训练营第二十九天-贪心算法 题目列表 1005.K次取反后最大化的数组和134.加油站135.分发糖果 代码随想录地址: https://programmercarl.com/10

代码随想录算法训练营第三十五天|贪心:860.柠檬水找零-爱代码爱编程

这个题目自己能想出来,逻辑和代码随想录一样。重点就在于20找零需要先看有没有一个10一个5。再看有没有三个5,比较容易实现。 class Solution { public: bool lemonadeChange(vector<int>& bills) { int five = 0; in

-爱代码爱编程

_32LeetCode代码随想录算法训练营第三十二天-贪心算法 题目列表 738.单调递增的数字714.买卖股票的最佳时机含手续费968.监控二叉树总结 代码随想录地址 https://programmercarl.

-爱代码爱编程

_33LeetCode代码随想录算法训练营第三十三天-动态规划 题目列表 理论基础509.斐波那契数70.爬楼梯746.使用最小花费爬楼梯 代码随想录地址 https://programmercarl.com/%E5

-爱代码爱编程

_34LeetCode代码随想录算法训练营第三十四天-动态规划 题目列表 62.不同路径63.不同路径II 代码随想录地址 https://programmercarl.com/0062.%E4%B8%8D%E5%9

_1leetcode代码随想录算法训练营第一天c++数组 | 704.二分查找、35.搜索插入位置、34.在排序数组中查找元素的第一个和最后一个位置、27 移除元素-爱代码爱编程

_1LeetCode代码随想录算法训练营第一天C++数组 | 704.二分查找、35.搜索插入位置、34.在排序数组中查找元素的第一个和最后一个位置、27 移除元素 LeetCode 题目列表: 704.二分查找35.搜

_5leetcode代码随想录算法训练营第五天-爱代码爱编程

_5LeetCode代码随想录算法训练营第五天-C++ 哈希表| 242.有效的字母异位词、349.两个数组的交集、202.快乐数、1.两数之和 LeetCode 242.有效的字母异位词LeetCode 349.两个数组

_16leetcode代码随想录算法训练营第十六天-爱代码爱编程

_16LeetCode代码随想录算法训练营第十六天-C++二叉树 | 513.找树左下角的值、112.路径总和、113.路径总和ii、106.从中序与后序遍历序列构造二叉树、105.从前序与中序遍历序列构造二叉树 题目列表

_17leetcode代码随想录算法训练营第十七天-爱代码爱编程

_17LeetCode代码随想录算法训练营第十七天-C++二叉树 | 654.最大二叉树、617.合并二叉树、700.二叉搜索树中的搜索、98.验证二叉搜索树 题目列表 654.最大二叉树617.合并二叉树700.二叉搜