题意:
给你n个结点,求所有不同形态的二叉搜索树(BST)。
思路:
枚举每个结点作为根节点时的BST,对于每个根节点,枚举所有不同形态的左子树和右子树,根据BST的定义,左子树和右子树必须也是BST,那么求不同形态子树时又可以用同样的方法,这就成了求解子问题(dp)题目。
由于这题给的数据是1~n的整数,所以当i为根节点时,左子树的值有小于i(即1~i-1),同理右子树为(i+1~n);
java代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<TreeNode> generateTrees(int n) {
if(n<1){
return new ArrayList();
}
return dfs(1,n);
}
public List<TreeNode> dfs(int s,int e){
if(s>e){
List<TreeNode> temp = new ArrayList();
temp.add(null);
return temp;
}
List<TreeNode> ans = new ArrayList();
for(int i = s;i<=e;i++){
List<TreeNode> lList = dfs(s,i-1);
List<TreeNode> rList = dfs(i+1,e);
for(TreeNode left:lList){
for(TreeNode right:rList){
TreeNode root = new TreeNode(i);
root.left = left;
root.right = right;
ans.add(root);
}
}
}
return ans;
}
}
如果用dfs来求解子问题,子问题并不能保存起来,某个子问题在递归过程会重复进行求解,这大大浪费时间(例如,求1~5的BST时1~4这个子问题求了以此,在求1~6的BST,1~4这个子问题又求了一次,同时1~5又重复求了一遍),所以可以开空间来节省时间,开一个二维数组(元素为链表)dp来保存每个子问题所有的BST形态。
//注意用":"方法访问时,只能访问List接口,不能直接访问ArrayList抽象类。
java代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<TreeNode> generateTrees(int n) {
if(n<1){
return new ArrayList();
}
List[][] dp = new List[n+2][n+2];
for(int i = 0;i<n+2;i++){
for(int j = 0;j<n+2;j++){
if(i==0){
dp[i][j] = new ArrayList();
dp[i][j].add(null);
}
else{
dp[i][j] = new ArrayList();
}
}
}
for(int i = 1;i<=n;i++){
for(int j = 1;j<=n-i+1;j++){
for(int k = j;k<j+i;k++){
List<TreeNode> lList = dp[k-j][j];
List<TreeNode> rList = dp[j+i-1-k][k+1];
for(TreeNode left : lList){
for(TreeNode right : rList){
TreeNode temp = new TreeNode(k);
temp.left = left;
temp.right = right;
dp[i][j].add(temp);
}
}
}
}
}
return dp[n][1];
}
}