*leetcode刷题_(DP,recursion,tree)_code124(树的最大值path)_code136_(分裂单词)

code124: Binary Tree Maximum Path Sum

non-empty binary tree, find the maximum path sum.

For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.

Example 1:

Input: [1,2,3]

   1
  / \
 2   3

Output: 6
Example 2:

Input: [-10,9,20,null,null,15,7]

-10
/
9 20
/
15 7

Output: 42

解答:
对于这种比较复杂的问题,思考下能否用动态规划,尤其是树类的题目,一般是可以用到DP的解法。
将之前的某些值保留到后面的递归中并进行处理。
本题中寻找最大的路径经过点的和
一般来说,三点情况:
1 双边三点最大
2 单边两点最大
3 单点最大

继续扩展到更多点:
1 单边存储下其最大值(都要依靠单边或者点,不能是双边),然后整合当前双边的最大值(意思是两边可以无限延长)
2 单边存储最大值,加新增点后的 左右单边的最大值 进行比较选取max
3 对于单点可以归纳进单边最大值里面,比较对象+1 node.val

终止情况:(double_max:双边最大值 single_max: 单边最大值 all_max:目前的最大值)
1 没有左右分支: double_max = node.val single_max = node.val #all_max = node.val
2 左右均有分支:double_max = node.val+left.single_max + right.single_max #single_max = max(node.val+left.single_max,node.val+right.single_max,node,val)
all_max = max(double_max, single_max, left.all_max, right.all_max)
3 左右仅有一个分支:参照 2 的公式。可以将其上级变为 0 。这样可以沿用
4 点不存在时: 全部为0

可优化的部分:
double_max只存在于本层中,所以不需要传递,只需要传递single_max以及all_max即可

带入发现,all_max 初始设置应该为无穷小,因为最大值可能为负数
然后发现1 2 3 因为 4 的存在 都能概括在一起了。
也就是目前两个判断:
1 左右均有分支:double_max = node.val+left.single_max + right.single_max #single_max = max(node.val+left.single_max,node.val+right.single_max,node,val)
all_max = max(double_max, single_max, left.all_max, right.all_max)
2 点不存在时: single_max = 0 all_max = float(’-inf’)

最终代码:

class Solution:
    def maxPathSum(self, root) -> int:

        def re(node):
            if not node:
                return [0,float('-inf')]
            else:
                res_l = re(node.left)
                res_r = re(node.right)
                double_max = res_l[0]+res_r[0]+node.val
                single_max = max(res_l[0]+node.val,res_r[0]+node.val,node.val)
                all_max = max(double_max,single_max,res_r[1],res_l[1])
                res = [single_max,all_max]
                return res

        res = re(root)
        return res[1]

总结:
1 归纳条件
2 寻找终止点
3 一步步合并条件:
1)single_max 最终包含了当前点的值的比较
2) double_max 无需继续传递,仅存在于本层中比较
3)对于点的判断,最终合并为:点 是否为None

##################################################

code139. Word Break

Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.

Note:

The same word in the dictionary may be reused multiple times in the segmentation.
You may assume the dictionary does not contain duplicate words.
Example 1:

Input: s = “leetcode”, wordDict = [“leet”, “code”]
Output: true
Explanation: Return true because “leetcode” can be segmented as “leet code”.
Example 2:

Input: s = “applepenapple”, wordDict = [“apple”, “pen”]
Output: true
Explanation: Return true because “applepenapple” can be segmented as “apple pen apple”.
Note that you are allowed to reuse a dictionary word.
Example 3:

Input: s = “catsandog”, wordDict = [“cats”, “dog”, “sand”, “and”, “cat”]
Output: false

解答:
寻找字符串是否能用数组元素完全分离
1 想到遍历时分割,左边存在则继续后面的检测
wrong:由于数组存在像 a abc ab这样的组合时,可能导致分割后的right不能被继续检测到(abc优先被分裂为a bc)
2 既然这样,我们做回溯,即return A or B,一旦有一个发现没问题,则返回true。
wrong:
TLE,回溯难免会出现这样的问题。如果str本身很长,而且数组中包含的单元数字母太多,会导致分支过多。尤其遇到False的情况会全部走完分支,耗时极大。
3 一般针对回溯的问题,尝试看下是否存在DP的解法:
如果某一段存在于数组中,则看其余段是否也存在。 转变为:如果最后一部分存在于数组中,看前面的是否全部存在。这个是逆向的DP,也就是回溯的思想了。
从正向走的话,我们先判断前面部分是否存在,然后再判断后面的。然后前面部分判断我们要尽量避免产生多余的步骤。 一旦我们发现目前为止到这里是没问题的,那么前面部分的分支那样的步骤就应该马上停下来。
从答案中发现这样操作的:
o(n^2)的遍历操作。i起点,j终点。如果i:j+1的部分存在于数组而且起点i之前就是满足的,则将终点设置到j+1 为True 。最后检查终点处的标识是否为TRUE。
################
字符串常用的DP方法!!!!!!!!
################
代码:

class Solution:
    def wordBreak(self, s: str, wordDict) -> bool:
        dp = [False]*(len(s)+1)
        dp[0] = True
        for i in range(len(s)):
            for j in range(i,len(s)):
                if dp[i] and s[i:j+1] in wordDict:
                    #print(dp[i],s[i:j+1],i,j)
                    dp[j+1] = True
        #print(dp)
        return dp[-1]

使用DP来记录当前位置是否满足条件。(长度为len+1,因为标记的位置是当前数组的末尾+1)

思想:
1 字符串的DP可以多次遍历记录。或者排列式记录(O n方)
2 回溯优化的DP
3 避免重复

简化代码:

class Solution:
    def wordBreak(self, s: str, wordDict) -> bool:
        dp = [True]
        for i in range(1,len(s)+1):
            dp += [any(dp[j] and s[j:i] in wordDict for j in range(i))]
            #print(dp,s[0:1])
        return dp[-1]

理论上是一样的,但是使用了any可以简化代码。
而且并不需要初始化数组,直接进行加和即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值