不同的二叉查找树I:
题目内容:
给出 n,问由 1…n 为节点组成的不同的二叉查找树有多少种?
样例:
给出n = 3,有5种不同形态的二叉查找树:
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
算法分析:
先来看一下二叉查找树的特点,当选定一个节点i作为中间节点时:
①位于该节点左子树中的所有节点均小于i,假设该节点的左子树的排列情况有m种;
②位于该节点右子树中的所有节点均大于i,假设该节点的右子树的排列情况有n种;
③综合①和②,当节点i作为当前二叉查找树的首节点时,该二叉查找树的总排列数目有m*n;
因此对于一个拥有n个节点的二叉查找树,其每一个节点均能成为某一二叉查找树的首节点,因此动态规划的表达式为:
DP[i] = sum{ DP[j-1] * DP[i-j] },其中1=< j <=i,DP[i]表示i个节点所能组成的二叉查找树的数目;
代码:
public int numTrees(int n) { // write your code here if(n==0) return 1; int[] result = new int[n+1]; result[0]=1; result[1]=1; for(int i=2;i<=n;i++){ for(int j=1;j<=i;j++){ int left=result[j-1]; int right=result[i-j]; result[i]+=left*right; } } return result[n]; }
不同的二叉查找树II:
题目内容:
给出n,生成所有由1…n为节点组成的不同的二叉查找树;
样例:
给出n = 3,有5种不同形态的二叉查找树:
1 3 3 2 1
\ / / / \ \
3 2 1 1 3 2
/ / \ \
2 1 2 3
算法分析:
本题在 I 的基础上要求返回的不是组数而是具体的组合,很明显本题需要用递归的方式来解决问题,和 I 的思想基本一致,在递归的过程中找出所有的左右子树的排列组合,然后分别连接到当前节点的左子树和右子树,将结果作为当前层的二叉查找树的所有排列组合进行返回。
代码:
HashMap<String,List<TreeNode>> map = new HashMap<>(); public List<TreeNode> findSolution(int begin, int end){ List<TreeNode> result = new ArrayList<>(); if(begin>end){ result.add(null); return result; } if(begin==end){ TreeNode temp = new TreeNode(begin); result.add(temp); return result; } String tag = String.valueOf(begin)+"-"+String.valueOf(end); if(map.get(tag)!=null){ return map.get(tag); } for(int i=begin;i<=end;i++){ List<TreeNode> left = findSolution(begin,i-1); List<TreeNode> right = findSolution(i+1,end); if(left.size()!=0&&right.size()!=0){ for(TreeNode t1:left){ for(TreeNode t2:right){ TreeNode temp = new TreeNode(i); temp.left = t1; temp.right=t2; result.add(temp); } } } if(left.size()!=0&&right.size()==0){ for(TreeNode t1:left){ TreeNode temp = new TreeNode(i); temp.left = t1; result.add(temp); } } if(left.size()==0&&right.size()!=0){ for(TreeNode t2:right){ TreeNode temp = new TreeNode(i); temp.right = t2; result.add(temp); } } } map.put(tag,result); return result; } public List<TreeNode> generateTrees(int n) { // write your code here map = new HashMap<>(); return findSolution(1,n); /*long startTime=System.nanoTime(); List<TreeNode> result = findSolution(1,n); long endTime=System.nanoTime(); System.out.println("运行时间为:"+(endTime-startTime)); return result;*/ }
代码中我还建立了一个map作为中间结果的记录,用来降低一些重复区间段求解的时间开销,其效果还是很明显的,当n=11时,没有map的算法时间开销为124313992ns,而有map的算法时间开销为82106610ns;但是这题我我试了下即使不用map也能够AC;