22括号生成
解题思路:2n个格子,每个格子可以存放两种,
限制条件:1.左括号必须在第一个位置,并且左扩号的个数不大于n
2.右括号的个数不大于左括号的个数
3.插入左括号的代码要在右括号之上
4.当左括号个数与右括号个数都等于n时,往结果集里加入字符串,
class Solution {
private List<String> list;
public List<String> generateParenthesis(int n) {
list = new ArrayList<String>();
generate(0,0,n,"");
return list;
}
public void generate(int left,int right,int n,String s){
if(left==n&&right==n){
list.add(s);
return;
}
if(left<n){
generate(left+1,right,n,s+"(");
}
if(left>right){
generate(left,right+1,n,s+")");
}
}
}
98验证二叉搜索树
思路:
这里得拒绝人肉递归,可以想到中序遍历的一个性质:就是遍历出来的数是按顺序递增的,所以我们只要在中间检查当前位置值是否小于前一个元素值。
class Solution {
long lastval=Long.MIN_VALUE;//初始化一个最小值
public boolean isValidBST(TreeNode root){
return helper(root);
}
public boolean helper(TreeNode root){
if(root==null){//根节点为空,则返回true
return true;
}
if(!helper(root.left)){//先遍历左子树
return false;
}
if(root.val<=lastval){//中序遍历一个特征就是遍历的树会从小到大排列,所以如果当前值小于上一个值,则返回false
return false;
}
lastval=(long)root.val;//并将当前值赋给lastval,
if(!helper(root.right)){//遍历右子树
return false;
}
return true;
}
}
226翻转二叉树
题目描述
class Solution {
public TreeNode invertTree(TreeNode root) {
if(root==null){
return null;
}
TreeNode right=invertTree(root.right);
TreeNode left=invertTree(root.left);
root.left=right;
root.right=left;
return root;
}
}
111二叉树的最小深度
题目描述
三段代码,时间0ms,这里与最大深度很相似,最大深度是递归查找左右子树的最大深度最后加一,那我们想着最小深度可以求最小深度加一,但其实漏了特殊情况,就是当节点左孩子为空或者右孩子为空的时候,若是按正常取最小值,返回的是0,但题目是到叶子节点,所以应该返回左右子树最大的那个。
class Solution {
public int minDepth(TreeNode root) {
if(root==null){
return 0;
}
if(root.left==null||root.right==null){//当节点的左孩子为空或者右孩子为空时,需要返回的是左右子树的最大值,因为是到叶子节点。
return Math.max(minDepth(root.left),minDepth(root.right))+1;
}
return Math.min(minDepth(root.left),minDepth(root.right))+1;
}
}
236最近公共祖先
题目描述
思路
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(root==null||root==p||root==q){//节点为空或者节点为p,q则返回
return root;
}
TreeNode left=lowestCommonAncestor(root.left,p,q);
TreeNode right=lowestCommonAncestor(root.right,p,q);
if(left==null){//如果左节点为空,说明祖先在root的右子树,返回右子树继续查找
return right;
}
if(right==null){//如果右子树为空,说明祖先在root的左子树,返回左子树继续查找
return left;
}
return root;//如果左,右子树都不为空,说明祖先为root,返回即可
}
}
105从前序遍历与中序遍历构造二叉树
题目描述
思路
1.构建二叉树包括三部分:root、左子树、右子树
2.左右子树的构建,又包括 root 和 左右子树
3.题目关键是如何划分左右子树,然后递归构建左右子树
定位出根节点的位置,划分左右子树
1.preorder 的第一项肯定是根节点 —— [ 根 | 左右 ]
2.根据根节点,在 inorder [左 | 根 | 右]中划分出左、右子树的 inorder 序列
3.通过 inorder 中左右子树的 size,在 preorder 中确定左、右子树的 preorder 序列
4.得到左、右子树的 preorder 和 inorder 序列,则传入函数,构建左右子树
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder == null || preorder.length == 0 || inorder == null || inorder.length == 0 || preorder.length != inorder.length) {//前序遍历数组或中序遍历数组为空,返回空
return null;
}
return help(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
}
private TreeNode help(int[] preorder, int pStart, int pEnd, int[] inorder, int iStart, int iEnd) {pstart为前序的头结点,pEnd为前序的尾结点
//递归的第一步:递归终止条件,避免死循环
if (pStart > pEnd || iStart > iEnd) {//头结点大于尾结点,返回空
return null;
}
//重建根节点
TreeNode treeNode = new TreeNode(preorder[pStart]);
int index = 0; //index找到根节点在中序遍历的位置
while (inorder[iStart + index] != preorder[pStart]) {
index++;
}
//重建左子树
treeNode.left = help(preorder, pStart + 1, pStart + index, inorder, iStart, iStart + index - 1);//中序遍历iStart+index为根节点的位置,所以iStart到iStart+index-1为左子树的范围,长度为index-1,则前序遍历中,左子树开始的结点为pStart+1,长度为index-1,所以结束的结点为pStart+1+index-1=pStart+index.
//重建右子树
treeNode.right = help(preorder, pStart + index + 1, pEnd, inorder, iStart + index + 1, iEnd);//中序遍历中右子树的开始的结点为iStart+index+1,结束结点为iEnd,所以前序遍历右子树开始的结点为pStart+index+1,结束的结点为pEnd
return treeNode;
}
}
106由后序遍历和中序遍历构造二叉树
题目描述
思路:
1.构建二叉树包括三部分:root、左子树、右子树
2.左右子树的构建,又包括 root 和 左右子树
3.题目关键是如何划分左右子树,然后递归构建左右子树
定位出根节点的位置,划分左右子树
1.postorder 的第一项肯定是根节点 —— [ 左右|根 ]
2.根据根节点,在 inorder [左 | 根 | 右]中划分出左、右子树的 inorder 序列
3.通过 inorder 中左右子树的 size,在 postorder 中确定左、右子树的 preorder 序列
4.得到左、右子树的 postorder 和 inorder 序列,则传入函数,构建左右子树
class Solution {
public TreeNode buildTree(int[] inorder, int[] postorder) {
if(inorder==null||inorder.length==0||postorder==null||postorder.length==0||inorder.length!=postorder.length){
return null;
}
return helper(inorder,0,inorder.length-1,postorder,0,postorder.length-1);
}
public TreeNode helper(int[]inorder,int iStart,int iEnd,int[] postorder,int pStart,int pEnd){
if(iStart>iEnd||pStart>pEnd){
return null;
}
TreeNode treenode=new TreeNode(postorder[pEnd]);//重建根节点,后序遍历所有根节点总是在末尾
int index=0;
//定位inorder中根节点的位置
while(inorder[iStart+index]!=postorder[pEnd]){//以此找出中序遍历中根节点的位置
index++;
}
//重建左子树
treenode.left=helper(inorder,iStart,iStart+index-1,postorder,pStart,pStart+index-1);//由中序遍历可以知道左子树的范围是iStart到iStart+index-1,长度为index-1,所以后序遍历中左子树开始节点为pStart,末尾节点为pStart+index-1.
//重建右子树
treenode.right=helper(inorder,iStart+index+1,iEnd,postorder,pStart+index,pEnd-1);//由中序遍历可知,右子树的开始节点为iStart+inde+1到iEnd,后序遍历的右子树开始节点为pStart+index,末尾节点为pEnd-1.
return treenode;
}
}