LeetCode DP(下)
本篇是LeetCode DP类别的高级(Hard)题目:
- Palindrome Partitioning II
- Word Break II
- Wildcard Matching
- Regular Expression Matching
- Maximal Rectangle
- Scramble String
- Interleaving String
#1.Palindrome Partitioning II LeetCode回文数题目集锦
#2.Word Break II ref
Given a string s and a dictionary of words dict, add spaces in s to construct a sentence where each word is a valid dictionary word.
Return all such possible sentences.
For example, given
s = “catsanddog”,
dict = [“cat”, “cats”, “and”, “sand”, “dog”].
A solution is [“cats and dog”, “cat sand dog”].
Word Break解题思路
本题大意是给定一个字符串和一个字典,将字符串分割成一个句子,使得句子中的所有单词都在字典中,返回所有的不同句子。
####思路
- 首先遍历字符串,记录每一个存在于字典中的子串;
- vbreak[i][j]=true表示单词s[i…j] 在字典中,否则不在字典中;
- DFS构造所有的句子;
#3.Wildcard Matching ref
Implement wildcard pattern matching with support for ‘?’ and ‘*’.
'?' Matches any single character.
'*' Matches any sequence of characters (including the empty sequence).
The matching should cover the entire input string (not partial).
The function prototype should be:
bool isMatch(const char *s, const char *p)
Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false
通配符(wildcard)匹配问题,这个题目有多种不同的解法,可以用回溯法,可以用动态规划,也可以用贪心,尝试了两个动态规划算法, 不是Time Limit Exceeded就是Memory Limit Exceeded.
####回溯 思路
- 这个问题的难点就是处理*,它可以匹配0个,也可以匹配到结尾;
- 从前向后进行匹配,记录*最后出现的位置star,以便后面发生匹配时,进行回溯;
- 为准确回溯,除了记录的位置,还要记录搜索字符串匹配到的位置ss;
- *先匹配0个,每次回溯增加一个;
#4.Regular Expression Matching ref
Implement regular expression matching with support for ‘.’ and ‘*’.
'.' Matches any single character.
'*' Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).
The function prototype should be:
bool isMatch(const char *s, const char *p)
Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true
正则表达式匹配,它和通配符匹配的不同在于*是匹配前一个字符0次或者多次,这里的’.’相当于前一题的’?’.这个题目同样有回溯和动态规划两种解法。
#5.Maximal Rectangle ref
Given a 2D binary matrix filled with 0’s and 1’s, find the largest rectangle containing all ones and return its area.
###朴素思路
这个问题有点难,将问题分解成n个子问题Largest Rectangle in Histogram
#6.Scramble String ref
Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.
Below is one possible representation of s1 = “great”:
great
/ \
gr eat
/ \ / \
g r e at
/ \
a t
To scramble the string, we may choose any non-leaf node and swap its two children.
For example, if we choose the node “gr” and swap its two children, it produces a scrambled string “rgeat”.
rgeat
/ \
rg eat
/ \ / \
r g e at
/ \
a t
We say that “rgeat” is a scrambled string of “great”.
Similarly, if we continue to swap the children of nodes “eat” and “at”, it produces a scrambled string “rgtae”.
rgtae
/ \
rg tae
/ \ / \
r g ta e
/ \
t a
We say that “rgtae” is a scrambled string of “great”.
Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.
###一般思路
- 将字符串s1分成左子树s1ltree和右子树s1rtree,将字符串s2分成左子树s2ltree和右子树s2rtree;
- return (isScramble(s1ltree, s2ltree) && isScramble(s1rtree, s2rtree)) || (isScramble(s1ltree, s2rtree) && isScramble(s1rtree, s2ltree));
- 这里有一个问题,ltree和rtree的长度并不一定相等,所以进行isScramble(s1ltree, s2ltree)和isScramble(s1ltree, s2rtree)时要进行两次不同的划分,确保isScramble的参数长度相等,就像例子中的eat子树和tae子树一样;
注意题目第一句话Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.
,最初对题目理解偏差,以为是将字符串划分成尽可能的平衡树,实际上是划分成任意长度的子树(non-empty substrings)
###递归方法(超时)
简化的递归树如下
从上图看出,有很多重复的子问题,下面用动态规划来解决。
使用了一个三维数组bool ss[len][len][len],其中第一维为子串的长度,第二维为s1的起始索引,第三维为s2的起始索引。
ss[k][i][j]表示s1[i…i + k-1]是否可以由s2[j…j + k-1]变化得来。
#7.Interleaving String ref
Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
For example,
Given:
s1 = “aabcc”,
s2 = “dbbca”,
When s3 = “aadbbcbcac”, return true.
When s3 = “aadbbbaccc”, return false.
设状态 f[i][j] ,表示 s1[0, i] 和 s2[0, j] ,匹配 s3[0, i + j] 。如果 s1 的最后一个字符等 于 s3 的最后一个字符,则 f[i][j] = f[i - 1][j] ;如果 s2 的最后一个字符等于 s3 的最后一个字符,则 f[i][j] = f[i][j - 1] 。 因此状态转移方程如下:
f[i][j] = (s1[i - 1] == s3[i + j - 1] && f[i - 1][j])|| (s2[j - 1] == s3[i + j - 1] && f[i][j - 1]);
留下评论