精华内容
下载资源
问答
  • leetcode 分类 Leetcode-DP-Classification Follow an essay on ZhiHu about DP ...Programming问题的分类完成leetcode中相应...树形DP; 状态压缩DP; 数位DP; 计数型DP; 递推型DP; 概率型DP; 博弈型DP; 记忆化搜索
  • 之后我们考虑dp数组怎么存,一种使用树形数组存,另外就是dfs过程中存。对于这个题,dfs是一种很方便的方式,前序遍历就很方便,左右处理完后,中间看两边取或者不取的状态的最优值,这个和普通的打家劫舍定义不太...

    经典的选或者不选问题。这个问题应该是自底向上的一个过程,因为我们最终只看根节点状态就可以知道结果,而不用统计所有底部信息,是较为方便的。
    之后我们考虑dp数组怎么存,一种使用树形数组存,另外就是dfs过程中存。对于这个题,dfs是一种很方便的方式,前序遍历就很方便,左右处理完后,中间看两边取或者不取的状态的最优值,这个和普通的打家劫舍定义不太一样。普通的一个数就记录了,这边要两个数,还是比较有趣的,也不用看上一个,思想相当于后序遍历。

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
     * };
     */
    class Solution {
    public:
        vector<int> dfs(TreeNode* node)
        {
            if(node == nullptr)return vector<int>{0, 0};
            auto dp1 = dfs(node->left), dp2 = dfs(node->right);
    
            vector<int> dp(2);
            // 选这个节点
            dp[1] = dp1[0] + dp2[0] + node->val;
            // 不选这个节点
            dp[0] = max(dp1[1], dp1[0]) + max(dp2[1], dp2[0]);
            return dp;
        }
    
        int rob(TreeNode* root) {
            auto dp = dfs(root);
            return max(dp[0], dp[1]);
        }
    };
    
    展开全文
  • 第一次接触到树形dp的问题 本题对于某个结点进行分类讨论 1.当前结点拿,那么当前偷到的价值就是当前结点的价值加上左结点不拿时下面结点提供的价值和右节点不拿时下面结点提供的价值 2.当前结点不拿,那么当前偷到...

    题目链接
    在这里插入图片描述
    第一次接触到树形dp的问题
    本题对于某个结点进行分类讨论
    1.当前结点拿,那么当前偷到的价值就是当前结点的价值加上左结点不拿时下面结点提供的价值和右节点不拿时下面结点提供的价值
    2.当前结点不拿,那么当前偷到的价值就是左结点拿或者不拿的最大价值和右节点拿或者不拿的最大价值之和
    总结一下
    当前节点选择偷时,那么两个孩子节点就不能选择偷了
    当前节点选择不偷时,两个孩子节点只需要拿最多的钱出来就行(两个孩子节点偷不偷没关系)
    我们使用一个大小为 2 的数组来表示 int[] res = new int[2] 0 代表不偷,1 代表偷

       public int rob(TreeNode root) {
            int res[] = dp(root);
            return Math.max(res[0],res[1]);
        }
        public int[] dp(TreeNode root){
            if (root == null) return new int[2];
            // 分类讨论的标准是:当前结点偷或者不偷
            // 由于需要后序遍历,所以先计算左右子结点,然后计算当前结点的状态值
            int left[] = dp(root.left);
            int right[] = dp(root.right);
            int res[] = new int[2];
            // res[0]:以当前 node 为根结点的子树能够偷取的最大价值,规定 node 结点不偷
            // res[1]:以当前 node 为根结点的子树能够偷取的最大价值,规定 node 结点偷
            res[0] = Math.max(left[0],left[1])+Math.max(right[0],right[1]);
            res[1] = left[0]+right[0]+root.val;
            return res;
        }
    
    展开全文
  • LeetCode——DP

    2019-11-19 20:37:31
    将分门别类的对常见DP问题进行总结,文末附有GitHub链接字符串问题股票问题最长子序列问题0-1背包问题两个人抓数问题视频拼接问题零钱兑换问题 字符串问题 回文子串是连续的,而子序列则不一定连续。 5.最长回文子串...

    字符串问题

    回文子串是连续的,而子序列则不一定连续。
    5.最长回文子串
    647.回文子串
    516.最长回文子序列
    1143.最长公共子序列
    最长公共子串

    public int getLCS(String s, String t) {
            if (s == null || t == null) {
                return 0;
            }
            int result = 0;
            int sLength = s.length();
            int tLength = t.length();
            int[][] dp = new int[sLength + 1][tLength + 1];
            for (int i = 1; i <= sLength; i++) {
                for (int k = 1; k <= tLength; k++) {
                    if (s.charAt(i - 1) == t.charAt(k - 1)) {
                        dp[i][k] = dp[i - 1][k - 1] + 1;
                        result = Math.max(dp[i][k], result);
                    }
                }
            }
            return result;
        }
    

    股票问题

    121.买卖股票的最佳时机
    122.买卖股票的最佳时机II
    123.买卖股票的最佳时机III
    188.买卖股票的最佳时机IV
    309.最佳买卖股票时机含冷冻期
    714.买卖股票股票最佳时机含手续费

    最长子序列问题

    300和646的不同之处在于646会先排序,因此可以返回dp[len-1],而300是无序的,因此需要返回以全局的Max。
    300.最长上升子序列
    646.最长数对链
    673.最长递增子序列的个数
    712.两个字符串的最小ASCII删除和
    413.等差数列划分

    0-1背包问题

    416.分割等和子集
    1049.最后一块石头的重量II
    474.一和零
    有 N 件物品和一个容量为 V 的背包。第 i 件物品的体积是 C[i],价值是 W[i]。求解将哪些物品装入背包可使价值总和最大,求出最大总价值。

    	public static int zeroOnePack(int V, int[] C, int[] W){
    		if(V <= 0 || C.length != W.length)
    			return 0;
    		int n = C.length;
    		int[][] dp = new int[n + 1][V + 1];
    		for(int i = 0; i <= n; i++){
    			for(int j = 0; j <= V; j++){
    				if(j < C[i - 1])// 背包放不下第 i 个物品
    					dp[i][j] = dp[i - 1][j];
    				else// 背包能放下第 i 个物品,选择价值最大的方案
    					dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - C[i - 1]] + W[i - 1]);
    			}
    		}
    		return dp[n][V];
    	}
    	空间优化:
    	public static int zeroOnePackOpt(int V, int[] C, int[] W){
    		if(V <= 0 || C.length != W.length)
    			return 0;
    		int n = C.length;
    		int[] dp = new int[V + 1];
    		dp[0] = 0;// 背包为空时,价值为 0
    		for(int i = 0; i < n; i++){
    			for(int j = V; j >= C[i]; j--){
    				dp[j] = Math.max(dp[j], dp[j - C[i]] + W[i]);
    			}
    		}
    		return dp[V];
    	}
    

    两个人抓数问题

    486.预测赢家
    464.我能赢吗

    视频拼接问题

    1024.视频拼接

    零钱兑换问题

    322.零钱兑换
    983.最低票价
    718.最长重复子数组

    马跳棋盘问题

    688.“马”在棋盘上的概率
    576.出界的路径数
    935.骑士拨号器

    连续子序列/打家劫舍问题

    152.乘积最大子序列
    53.最大子序和
    713.成绩小于K的子数组
    198.打家劫舍
    213.打家劫舍II
    337.打家劫舍III

    二叉搜索树与Dp

    96.不同的二叉搜索树
    95.不同的二叉搜索树II

    路径问题

    64.最小路径和
    62.不同路径
    63.不同路径II

    其他

    467.环绕字符串中唯一的子字符串
    91.解码方法
    873.最长的斐波那锲子序列的长度
    898.子数组按位或操作
    221.最大正方形
    801.使序列递增的最小交换
    1027.最长等差数列
    139.单词拆分
    837.新21点
    877.石子游戏
    368.最大整除子集
    813.最大平均值和的分组
    120.三角形最小路径和

    有 N 堆金币排成一排,第 i 堆中有 C[i] 块金币。每次合并都会将相邻的两堆金币合并为一堆,成本为这两堆金币块数之和。经过N-1次合并,最终将所有金币合并为一堆。请找出将金币合并为一堆的最低成本。其中,1 <= N <= 30,1 <= C[i] <= 100

    //dp[i][j]:i-j的最小和
    import java.util.*;
    class Test{
        public static void main(String[] args) {
            Scanner in = new Scanner(System.in);
            int n = in.nextInt();
            int[] coin = new int[n+1];
            int[] preSum = new int[n+1];
            for(int i=1;i<=n;i++) {
                coin[i] = in.nextInt();
                if(i==1) preSum[i]=coin[i];
                else preSum[i]=preSum[i-1]+coin[i];
            }
            in.close();
            int[][] dp=new int[n+1][n+1];//i-j的最低成本
            for(int len=2;len<=n;len++){
                for(int i=1;i<=n-len+1;i++){
                    int j=i+len-1;
                    dp[i][j]=Integer.MAX_VALUE;
                    int sum=preSum[j]-preSum[i-1];
                    for(int k=i;k<j;k++){
                        dp[i][j]=Math.min(dp[i][j],dp[i][k]+dp[k+1][j]+sum);
                    }
                }
            }
            System.out.println(dp[1][n]);
        }
    }
    
    展开全文
  • 看了题解是树形dp,那么问题来了,为什么呢?这道题也没有什么最值,看起来距离之和是一个很固定的东西,一点都不动态。 其实我觉得,与其说是dp,不如说是递推。这里的中心思想就是从叶子往上推,处理距离 distSum...

    道题要求每个节点到其他所有节点的距离之和
    先考虑一个节点到其他所有节点的距离之和的问题。看到距离首先我想到的就是最短路,但是树上没啥最短路_(:з」∠)_
    然后我就没想出什么行之有效的方法_(:з」∠)_
    看了题解是树形dp,那么问题来了,为什么呢?这道题也没有什么最值,看起来距离之和是一个很固定的东西,一点都不动态。
    其实我觉得,与其说是dp,不如说是递推。这里的中心思想就是从叶子往上推,处理距离
    distSum[root] = sigma(distSum[root'sChild] + childSum[root'sChild]
    将这个递推用递归写出来

    void dfs(int node, int fa)
        {
            distSum[node] = 0;
            childNum[node] = 1;
            for (int i = 0; i < graph[node].size(); i++)
            {
                if (graph[node][i] == fa) continue;
                dfs(graph[node][i], node);
                childNum[node] += childNum[graph[node][i]];
                distSum[node] += distSum[graph[node][i]] + childNum[graph[node][i]];
            }
        }
    
    

    解决了这个问题之后,你可以把所有点都当做root跑一遍dfs,但是你看看根的儿子,它到所有节点的距离之和根本不用重新算,可以从父节点推出来。
    distSum[node] = distSum[fa] - childNum[node] + (N - childNum[node]);

    完整代码:

    class Solution {
    public:
        vector<vector<int>> graph;
        vector<int> distSum, childNum;
    
        void dfs(int node, int fa)
        {
            distSum[node] = 0;
            childNum[node] = 1;
            for (int i = 0; i < graph[node].size(); i++)
            {
                if (graph[node][i] == fa) continue;
                dfs(graph[node][i], node);
                childNum[node] += childNum[graph[node][i]];
                distSum[node] += distSum[graph[node][i]] + childNum[graph[node][i]];
            }
        }
    
        void changeRoot(int node, int fa)
        {
            if (fa != -1)
            {
                distSum[node] = distSum[fa] - childNum[node] + (graph.size() - childNum[node]);
            }
            for (int i = 0; i < graph[node].size(); i++)
            {
                if (graph[node][i] == fa) continue;
                changeRoot(graph[node][i], node);
            }
        }
    
        vector<int> sumOfDistancesInTree(int N, vector<vector<int>>& edges) {
            graph.resize(N, {});
            childNum.resize(N, 0);
            distSum.resize(N, 0);
            for (int i = 0; i < edges.size(); i++)
            {
                graph[edges[i][0]].push_back(edges[i][1]);
                graph[edges[i][1]].push_back(edges[i][0]);
            }
            dfs(0, -1);
            changeRoot(0, -1);
            return distSum;
        }
    };
    
    

    另,看到了两篇蛮不错的树形dp讲解
    这篇的重点是树形dp在设状态转移方程时都可以用f[i][]表示i这颗子树怎么怎么样的最优解,实现时一般都是用子树更新父亲
    这篇的重点是给出了树形dp的解题步骤:1、判断是否是树规题 2、建树 3、写树规方程

    展开全文
  • 用f(root)表示从root节点出发能盗取的最高金额 f(root) = max(f(root->left)+f(root->right), root->val + f(root->left->left)+f(root->left->right) + f(root->right->...
  • 关于 树形dp 套路,可以参考我的另一篇博客:左神算法:找到二叉树中的最大搜索二叉子树(Java版) 下面简述本题思路: 首先,如何判断一个节点 head 是否是 p、q 的公共祖先?只需要用二分查找的方式,判断以 head...
  • leetcode DP 打家劫舍

    2020-07-29 10:45:07
    树形DP 错误想法 错误想法:BFS,计算奇数层和,偶数层和中较大的那个。 错误示例如下:最大值不是【祖父-孙子】组合,而是【曾祖-曾孙】组合。 3 / 1 / 2 / 4 1.递归,超时 1.递归。return max(祖父...
  • 题目描述: 在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。...来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/house-robber-ii
  • LeetCode 663. 均匀树划分(树形DP

    千次阅读 2020-07-06 01:34:43
    给定一棵有 n 个结点的二叉树,你的任务是检查是否可以通过去掉上的一条边将分成两棵,且这两棵结点之和相等。 样例 1: 输入: 5 / \ 10 10 / \ 2 3 输出: True 解释: 5 / 10 和: 15 10 / \ 2...
  • Leetcode刷题指南之DP动态规划 文章目录Leetcode刷题指南之DP动态规划前言DP背包Leetcode139. Word BreakLeetcode198 House Robber ILeetcode213 House Robber IILeetcode322. Coin ChangeLeetcode518.Coin Change |...
  • 由于要考虑每个节点是否放置摄像头,又要考虑是否一棵都能被覆盖到。 状态a:当前节点安装相机的时候,且能整棵被覆盖到需要的最少相机数 状态b: 当前节点不需要安装相机,但是能被覆盖到这棵的时候,需要的...
  • 树形DP 实现 码前思考 由于之前做过了⭐LeetCode 124. Binary Tree Maximum Path Sum,这道题的思想和它是一样的,所以就没多想了。 代码实现 //我记得我之前做过一道“剥洋葱的题” //到时候回去看看 //这道题...
  • 对于树形DP的问题,其实说白了,我认为树形DP问题就是在树结构上,求解最优化问题。 有了上面的理解,树形DP问题的解题套路就是以当前子树根结点,结合当前子树根结点的左子树和当前子树根结点的右子树进行分情况...
  • 树形dp: 维护两个dp,dp1和dp2都以当前节点为根的子树,其中dp1是偷当前节点最大值,dp2是不偷当前节点的最大值,深度优先搜索,先求子树再向上,最后结果是max(dp1[root],dp2[root]) /** * Definition for a...
  • LeetCode #12 双周赛 5097. 力扣排行榜 题目:设计一个排行榜,满足插入、前缀和、排序。 分析:数据范围很小,用不到 logn 的数据结构,直接暴力即可。 用 mapmapmap 存编号对应成绩,每次查询暴力排序找前 k 和。 ...
  • 834. 中距离之和 难度困难143收藏分享切换为英文接收动态反馈 给定一个无向、连通的中有N个标记为0...N-1的节点以及N-1条边。 第i条边连接节点edges[i][0]和edges[i][1]。 返回一个表示节点i与其他所有...
  • 中距离之和 这道题目,很容易想到O(n2)O(n^2)O(n2)的做法。 如何只求出到一个点的距离: 状态:f[x]f[x]f[x]就表示所有的点到x的距离; DP方程: f[x]=f[y1]+f[y2]+……+f[yk]+……+s[y1]+s[y2]+……+s[yk]+……f...
  • 题目连接:Leetcode 124 Binary Tree Maximum Path Sum解题思路:每次递归遍历,返回结点单向的最大值,遍历过程中维护最大值。/** * Definition for a binary tree node. * struct TreeNode { * int val; * ...
  • 思考:什么情况下 dp 需要强制包含当前元素? dp 过程中,需要包含当前元素 的例子: leetcode 322. Coin Change | 322. 零钱兑换(动态规划) leetcode 300. Longest Increasing Subsequence | 300. 最长递增子序列...
  • 他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的,父结点就是子结点的直接上司。 现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 rir_iri​,但是呢,如果某个职员的直接上司来...
  • 路径 被定义为一条从中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。 路径和 是路径中各节点值的总和。 ...
  • 思路:如果选择的当前节点就不选择左右孩子节点,为了避免对节点重复dfs超时,使用map记录已经访问过的节点。 代码如下: class Solution { public: map<TreeNode *, int> mp; int dfs(TreeNode* tree, ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,120
精华内容 448
热门标签
关键字:

leetcode树形dp