minStack及tree学习
//实现一个类,实现栈的功能:(构建单链表,有一个头结点,head)
class MinStack {
private class ListNode {
int val;
ListNode next;
int min;
ListNode(int x) { val = x; }
}//leetcode自带的ListNode定义,加入min值,指示从当前值到栈底元素(也就是单链表最后一个节点的值)之间的最小值,
ListNode head=new ListNode(-1);//如果这样定义,那么会默认head.next==null。不用再重复写
int min;
public void push(int x) {
ListNode p=new ListNode(x);
if(head==null||head.next==null){
p.min=x;
}else{
p.min=Math.min(head.next.min,x);//每个节点的min表示从该节点到栈底元素中的最小值,在每次插入元素时,都与当前的栈顶元素比较,确定自身携带的min(在之后的getMin函数中不用再进行获取,降低时间复杂度。)
}
p.next=head.next;
head.next=p;
}
public void pop() {
if(head!=null)
head=head.next;
}
public int top() {
if(head==null||head.next==null)
return -1;
int top=head.next.val;
return top;
}
public int getMin() {
return head.next.min;
}
}
********************************************************
关于树的题:
//判断两个数是否一模一样sameTree问题,树的问题要擅于使用递归!(开始一直想树的结构由前,中序可以决定,如果得到结果相同,则树一致,但是在遍历中使用递归带来一些麻烦)
public class Solution {
public boolean isSameTree(TreeNode p, TreeNode q) {
if(p==null&&q==null)
return true;
if((p==null&&q!=null)||(p!=null&&q==null))
return false;
if(p.val==q.val){
if(isSameTree(p.left,q.left)&&isSameTree(p.right,q.right))//判断左子树与右子树是否same
{ return true;}else{
return false;
}
}
if(p.val!=q.val)
return false;
return true;
}
}
//我的代码略繁琐:贴上别人的代码:
**********************************************************************************************************
判断树是否对称(注意:对称的树中序遍历结果同样对称)使用递归:
给定的代码格式如下:
public class Solution {
public boolean isSymmetric(TreeNode root) {
}
想到一颗对称的树必定是首先找到头结点的左右两个节点(p,q),然后p.left==q.right,p.right==q.left,可是看到给定的函数只有一个参数就傻眼了,后来发现可以自己再定义一个函数,传两个节点作为参数,并使用了贴图中的一行简约代码:
public class Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null) return true;
if(root.left==null&&root.right==null) return true;
if((root.left==null&&root.right!=null)||(root.left!=null&&root.right==null))
return false;
return ifSym(root.left,root.right);
}
public static boolean ifSym(TreeNode p,TreeNode q) {
if(p==null&&q==null) return true;
if((p==null&&q!=null)||(p!=null&&q==null)) return false;
if(p.val!=q.val) return false;
return (ifSym(p.left,q.right))&&(ifSym(p.right,q.left));
}
}
**************************************************************************************
用非递归的方式写一下遍历:
先序遍历:preorder traverse:
public class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
ArrayList<Integer> result=new ArrayList<Integer>();
Stack<TreeNode> stack=new Stack<TreeNode>();
if(root==null) return result;
while(root!=null){
result.add(root.val); //判断root不为空后,打印
if(root.left==null) {//左子树如果为空,右子树赋值给root
root=root.right;
}else{//左子树如果不为空
if(root.right!=null)
stack.push(root.right);//注意:如果当前结点有右子树,那么要将右结点放入栈中,之后需要用到时取出
root=root.left;//继续往左走
}
if(root==null){//此时root==null,此时只表明之前判断左子树为空时把右子树赋给结点,但是右子树是为空的,需要进行栈操作
if(!stack.empty()){//判断栈是否空,不空则取出,并赋给root
root=stack.pop();}else {
break;//栈空,此时root==null,那么程序结束
}
}
}
return result;
}
}
***************************************************************
中序遍历:从先序遍历改过来
public List<Integer> inorderTraversal(TreeNode root) {
ArrayList<Integer> result=new ArrayList<Integer>();
Stack<TreeNode> stack=new Stack<TreeNode>();
if(root==null) return result;
while(root!=null){
if(root.left==null) {//如果左子树为空
result.add(root.val);//可以打印当前结点,因为左侧已空
root=root.right;//把右结点赋给root
}else{
stack.push(root);//如果左子树不为空,那么要继续往左走,为了之后能够回溯,所以把当前结点放入栈中(先序中)
root=root.left;//继续往左走
}
if(root==null){//此时root==null,考虑栈操作
while(!stack.empty()){//!!注意这里使用while,而不是if!!
root=stack.pop();
result.add(root.val);//取出栈中内容后打印
if(root.right!=null) {root=root.right;break;}//如果取出的结点的右子树不空,那么复制给root,跳出当前循环,而如果右子树为空,那么需要继续从栈中取出结点,所以使用while,而不是if
if(stack.empty()) {root=null;break;}//这句之前没写,发生错误,会出现栈不空时进入此循环,取出结点后赋值给了root,root!=null,此时栈空,虽然会跳出此层循环,但是会进入大循环中,出错。
}
}
}
return result;
*****************************************判断是否为二叉查询树*****************************
1、利用中序遍历结果:二叉查询树中序遍历严格递增(注意,是严格!!!) 代码不贴。
2、采用递归。二叉查询树
特点:(1)左结点数值小于当前结点数值,右结点数值大于当前结点数值(2)左子树上所有结点的值小于当前结点值,右子树上所有结点值大于当前结点值
递归写了好像有点问题。待更新。。。。。
********************************************利用广度优先搜索解决树的大高度与最小高度**********************************
首先贴出广度优先搜索的代码,确实不是一个好的代码。。。。要求对于树的每一层输出一个list,最终输出多个list的集合list(leet:Binary Tree Level Order Traversal)
public class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result=new ArrayList<>();
if(root==null) return result;
Stack<TreeNode> s1=new Stack<TreeNode>();
Stack<TreeNode> s2=new Stack<TreeNode>();
TreeNode t=null;
s1.push(root);
while(!s1.empty()){
ArrayList<Integer> sub=new ArrayList<Integer>();
while(!s1.empty()){
s2.push(s1.pop());
}
while(!s2.empty()){
t=s2.pop();
sub.add(t.val);
if(t.left!=null) s1.push(t.left);
if(t.right!=null) s1.push(t.right);
}
result.add(sub);
}
return result;
}
}时间复杂度太高。。。。。
利用这段代码写了最大高度和最小高度,最大高度很简单,就是变成对于每一层+1,最小高度在判断左右孩子是否为空时引入判断左右孩子是否同时为空,同时为空时直接输出当前的int值。如下为最小高度代码:
public int minDepth(TreeNode root) {
int d=0;
if(root==null) return 0;
Stack<TreeNode> s1=new Stack<TreeNode>();
Stack<TreeNode> s2=new Stack<TreeNode>();
TreeNode t=null;
s1.push(root);
while(!s1.empty()){
d+=1;
while(!s1.empty()){
s2.push(s1.pop());
}
while(!s2.empty()){
t=s2.pop();
if(t.left==null&&t.right==null) return d;
if(t.left!=null) s1.push(t.left);
if(t.right!=null) s1.push(t.right);
}
}
return d;
}
*****************************************************树的深广度优先搜索********************************************************************************
(此处引用下其他博主的内容)http://www.blogjava.net/fancydeepin/archive/2013/02/03/395073.html
********************************深度优先搜索算法(Depth First Search),********
是搜索算法的一种。是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。
当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。
如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。
如右图所示的二叉树:
A 是第一个访问的,然后顺序是 B、D,然后是 E。接着再是 C、F、G。
那么,怎么样才能来保证这个访问的顺序呢?
分析一下,在遍历了根结点后,就开始遍历左子树,最后才是右子树。
因此可以借助堆栈的数据结构,由于堆栈是后进先出的顺序,由此可以先将右子树压栈,然后再对左子树压栈,
这样一来,左子树结点就存在了栈顶上,因此某结点的左子树能在它的右子树遍历之前被遍历。
*********************广度优先搜索******************
广度优先搜索算法(Breadth First Search),又叫宽度优先搜索,或横向优先搜索。
是从根节点开始,沿着树的宽度遍历树的节点。如果所有节点均被访问,则算法中止。
如右图所示的二叉树,A 是第一个访问的,然后顺序是 B、C,然后再是 D、E、F、G。
那么,怎样才能来保证这个访问的顺序呢?
借助队列数据结构,由于队列是先进先出的顺序,因此可以先将左子树入队,然后再将右子树入队。
这样一来,左子树结点就存在队头,可以先被访问到。
利用该广度优先算法,可以计算之前的:
**************求树最小高度问题:*****************************
设置一个最右结点,当当前遍历的结点是最右结点时,高度加1,并且将当前遍历结点的最右结点设置为新的最右结点。
public int minDepth(TreeNode root) {
if (root == null) return 0;
Queue<TreeNode> q = new LinkedList<>();
q.add(root);
TreeNode rightMost = root;
int depth = 1;
while (!q.isEmpty()) {
TreeNode node = q.poll();
if (node.left == null && node.right == null) break;
if (node.left != null) q.add(node.left);
if (node.right != null) q.add(node.right);
if (node == rightMost) {
depth++;
rightMost = (node.right != null) ? node.right : node.left;//因为之前判断过左右孩子都为空的情况,直接break,所以此处不存在左右孩子均不存在的情况。
}
}
return depth;
}
**********求树的层次遍历结果(leet:Binary Tree Level Order Traversal)************
这段代码应该还可以进行优化。。。写的有点乱。。。。
核心问题在于rightMost的确定:当前结点走到rightMost后,需要确定下一轮的rightMost,而如果当前结点的左右孩子结点都是null,那么rightMost就应该是当前层上的当前结点的前一个结点(左兄弟)的右孩子/左孩子。所以需要一直保存前一个遍历结点的rightMost,来应对可能出现的这种情况。
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result=new ArrayList<List<Integer>>();//结果链表
Queue<TreeNode> tempQ=new ArrayDeque<TreeNode>();//中途队列
if(root==null) return result;
ArrayList<Integer> li=new ArrayList<Integer>();
TreeNode t=null;
TreeNode pre=null;
tempQ.add(root);
TreeNode rightMost=root;
while(tempQ.peek()!=null){//判断队列是否为空
t=tempQ.poll();
li.add(t.val);
if(t==rightMost){//如果t为rightmost
result.add(li);//表明一层遍历结束,将li加入到结果result链表中
li=new ArrayList<Integer>();//重新new li
if(t.left!=null||t.right!=null){//如果当前结点的左右孩子有一个不为空
rightMost=(t.right!=null)?t.right:t.left;//判断右孩子是否不为空,如果不为空,则定义其为rightmost,否则定义左孩子
if(t.left!=null) {tempQ.add(t.left);}//按照先放左孩子,再放右孩子的原则,放入队列中
if(t.right!=null) {tempQ.add(t.right);}
continue;//跳出,继续循环
}else{//如果左右孩子都为空
if(pre!=null) rightMost=pre;//判断pre是否为空,不为空时将pre作为rightmost
}
}else{//当前不为rightmost时:
if(t.left!=null) tempQ.add(t.left);
if(t.right!=null) tempQ.add(t.right);//按照先放左再放右,将孩子放入队列
if(t.right!=null) {pre=t.right;continue;}//如果右孩子不为空,将右孩子设置为pre
if(t.left!=null) {pre=t.left;continue;}
}
}
return result;
}
************************************************