文章目录
- 最长回文子串
- 代码解答:
- 不同的二叉搜索树
- 代码解答:
最长回文子串
首先我们应该先了解什么是回文子串:
单个字符 例如 a 这也是回文字符串
2个字符 aa 或者 bb 这也是回文字符串
3个字符 aba 或者 bab
多个字符 abba ababa 这些也被叫做回文子串
从前到后和从后到前念的顺序一样的被叫做回文字符串
再回到题目,这道题我们采用动态规划来解决:
我们需要先定义1个容器dp(dp 为二维数组)
//其中len为题目给的字符串s的长度
boolean[][] dp = new boolean[len][len];
我们定义1个i和j,i和j表示的是从i到j的所组成的数组
因为我们之前谈过单个字符也是回文子串,因此当i和j相等时表示的就是单个字符 例如: ad dp[0][0]表示的就是 a,因此我们将dp[i][i] 全部设置为true
boolean[][] dp = new boolean[len][len];
for(int i = 0;i<len;i++){
dp[i][i] = true;
}
对应的容器:
在这个容器中我们只需要看左下脚,因为我们定义的是从i到j,i必须要小于j
之后我们就需要将左下角的填满
char[] c = s.toCharArray();
for(int j = 1;j<len;j++){
for(int i = 0;i<len-1&&i<j;i++){
if(c[i] != c[j]){
dp[i][j] = false;
}else{
if(j-i+1 < 3){
dp[i][j] = true;
}else{
dp[i][j] = dp[i+1][j-1];
}
}
从容器中可以看出我们i是从0到3即0到 len - 1,j是从1到4即 1到 len,
如果dp[i] 和 dp[j] 不一样那肯定是不符合题意的,如 abc , a 和 c不相等,直接置为false;
如果相等我们又要考虑 aa 这种情况,如果两边的都相等了,长度还是小于3就没必要再往里走了。就可以直接置为true, 如果长度大于3我们就往里走,即dp方程 dp[i][j] = dp[i+1][j-1]; 这个dp方程的意思就是i往左走,j往右走,即
之后我们只需要拿到最大的长度max,通过切割就可以得到
if(dp[i][j] && j-i+1 > max){
max = j-i+1;
start = i;
}
}
}
return s.substring(start,start+max);
代码解答:
class Solution {
public String longestPalindrome(String s) {
int len = s.length();
if(len == 1){
return s;
}
//定义容器
boolean[][] dp = new boolean[len][len];
for(int i = 0;i<len;i++){
dp[i][i] = true;
}
int start = 0;
int max = 1;
char[] c = s.toCharArray();
for(int j = 1;j<len;j++){
for(int i = 0;i<len-1&&i<j;i++){
if(c[i] != c[j]){
dp[i][j] = false;
}else{
if(j-i+1 < 3){
dp[i][j] = true;
}else{
dp[i][j] = dp[i+1][j-1];
}
}
if(dp[i][j] && j-i+1 > max){
max = j-i+1;
start = i;
}
}
}
return s.substring(start,start+max);
}
}
不同的二叉搜索树
这道题也是动态规划,我们需要先定义容器
int[] dp = new int[n+1];
这道题要找到dp方程我们就需要将每个数都当作一次根节点,将它们能二叉搜索树相加就可以,我们这里画出一个区间更好理解:
我们在i个元素中选择1个j当作根节点 那么比j小的 j-1个数就可以组成j的左子树,比j大的就可以组成j的右子树。 它们总共能组成的二叉搜索树也就是相乘的关系。
for(int i = 1;i<=n;i++){
//让n个节点都当一次头节点
for(int j = 1;j<=i;j++){
dp[i] += dp[j-1] * dp[i-j];
}
}
代码解答:
class Solution {
public int numTrees(int n) {
//动态规划
int[] dp = new int[n+1];
dp[0] = 1;
for(int i = 1;i<=n;i++){
//让n个节点都当一次头节点
for(int j = 1;j<=i;j++){
dp[i] += dp[j-1] * dp[i-j];
}
}
return dp[n];
}
}