剑指offer习题JAVA实现(二)

1.输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

public class Solution {
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
       if(root2==null) return false;
       if(root1==null&&root2!=null) return false;
       boolean flag=false;
       
        if(root1.val==root2.val){
       		flag=DoesTreeHaveTree2(root1, root2);
       	}
       	if(!flag){
       		flag=HasSubtree(root1.left, root2);
       			if(!flag){
       				flag=HasSubtree(root1.right, root2);
       				}
        	}
        	return flag;
        }
    public boolean DoesTreeHaveTree2(TreeNode root1,TreeNode root2){
    	if(root2==null){
    		return true;
    	}
    	if(root1==null&&root2!=null){
    		return false;
    	}
    	if(root1.val==root2.val){
    		return DoesTreeHaveTree2(root1.left, root2.left)&&DoesTreeHaveTree2(root1.right, root2.right);	
    	}else{
    		return false;
    	}  	              
    }
}
2. 操作给定的二叉树,将其变换为源二叉树的镜像。(就是左右节点互换)

public class Solution {
    public void Mirror(TreeNode root) {
        if(root==null)
        	return ;
        TreeNode tem=root.left;
        root.left=root.right;
        root.right=tem;
        if(root.left!=null){
        	Mirror(root.left);
        }
        if(root.right!=null){
        	Mirror(root.right);
        }
        
    }
}
3. 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

public class Solution {
    public ArrayList<Integer> printMatrix(int [][] matrix) {
     	 int M = matrix.length;
        int N = matrix[0].length;
        ArrayList<Integer> list = new ArrayList<Integer>();
        // 初始值为0,表示非访问
        int[][] temp = new int[M][N];
        int i = 0;//相当于设置两个位移量
        int j = 0;
        while (!isFinsh(temp)) {//判断条件是当数组中的所有元素都被访问
            while (j < N && temp[i][j] == 0) {
                list.add(matrix[i][j]);
                temp[i][j] = 1;
                j++;
            }
            j--;
            i++;
            while (i < M && temp[i][j] == 0) {
                list.add(matrix[i][j]);
                temp[i][j] = 1;
                i++;
            }
            j--;
            i--;
            while (j >= 0 && temp[i][j] == 0) {
                list.add(matrix[i][j]);
                temp[i][j] = 1;
                j--;
            }
            i--;
            j++;
            while (i >= 0 && temp[i][j] == 0) {
                list.add(matrix[i][j]);
                temp[i][j] = 1;
                i--;
            }
            i++;
            j++;
 
        }
 
        return list;
    }
    /*
       数组全部遍历完成则返回true,还有没访问的返回false
    */
    public boolean isFinsh(int matrix[][]){
         int M = matrix.length;
        int N = matrix[0].length;
        for( int k=0;k<M;k++){
            for( int l=0;l<N;l++){
                if(matrix[k][l] ==0) return false;
            }
          }
          return true;
    }
}
4. 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
public class Solution {
    Stack <Integer>stack=new Stack<Integer>();
    Stack <Integer>help=new Stack<Integer>();
    public void push(int node) {
        stack.push(node);
        if(help.isEmpty()){
        	help.push(node);
        }else if(!help.isEmpty()&&((Integer)help.peek()>node)){
        	help.push(node);
        }
        
    }
    public void pop() {
       int n=(Integer) stack.pop();
       if(n==(Integer)help.peek()){
    	   help.pop();
       }
    }
    public int top() {
        return (Integer) stack.peek();
    }
    public int min() {
        return (Integer) help.peek();
    }
}
5. 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

public class Solution {
    public boolean IsPopOrder(int [] pushA,int [] popA) {
            if(pushA.length==0||popA.length==0){
    	  return false;
     	}
     int index=0;
     Stack <Integer>stack=new Stack<Integer>();
     for (int i = 0; i < popA.length; i++) {
           stack.push(pushA[i]);
           while(index < popA.length && stack.peek() == popA[index]){ //模拟的是一边入栈,一边弹出
               stack.pop();
               index++;
           } 
       }
       return stack.empty()==true;
    }
}
6. 从上往下打印出二叉树的每个节点,同层节点从左至右打印。

public class Solution {
    public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) {
      Deque<TreeNode> deque=new LinkedList<TreeNode>();
      ArrayList <Integer>list=new ArrayList<Integer>();
      if(root==null){
    	   return list;
      }deque.add(root);
      while(!deque.isEmpty()){
    	  TreeNode t=deque.pop();
    	  list.add(t.val);
    	  if(t.left!=null){
    		   deque.add(t.left);
    	   }
    	   if(t.right!=null){
    		   deque.add(t.right);
    	   }
       } return list;
    }   
}
7. 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。(BST的后序序列的合法序列是,对于一个序列S,最后一个元素是x (也就是根),如果去掉最后一个元素的序列为T,那么T满足:T可以分成两段,前一段(左子树)小于x,后一段(右子树)大于x,且这两段(子树)都是合法的后序序列。 

public class Solution {
    public boolean VerifySquenceOfBST(int [] sequence) {
     if(sequence==null||sequence.length==0)
    	   return false;
    	int length=sequence.length;
        int root=sequence[length-1];
        int i=0;
        for(;i<length-1;++i){
        	if(sequence[i]>root)
        		break;
        }
        int j=i;
        int dd=i;
        for(;j<length-1;++j){
        	if(sequence[j]<root){
        		return false;
        	}
        }
        boolean left=true;
        boolean right=true;
        if(i>0){
        	left=VerifySquenceOfBST(Arrays.copyOfRange(sequence, 0, i));
        }
        if(i<length-1){
        	right=VerifySquenceOfBST(Arrays.copyOfRange(sequence, i, length-1));	
        }
         
        return left&&right;
    }
}
8. 输入一颗二叉树和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

public class Solution {
    public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) {
	ArrayList<ArrayList<Integer>> arr=new ArrayList<ArrayList<Integer>>();
	ArrayList <Integer>list=new ArrayList<Integer>();
		if(root==null){
		return arr;
		}
		int sum=0;
		pa(root,target,arr,list,sum);
		return arr;
	}
	public void pa(TreeNode root,int target,ArrayList<ArrayList<Integer>> arr,ArrayList<Integer>list,int sum){
		if(root==null){
			return;
		}
		sum+=root.val;
		if(root.left==null&&root.right==null){
			if(sum==target){
				list.add(root.val);
				arr.add(new ArrayList<Integer> (list));
				list.remove(list.size()-1);
			}
			return;
		}
		list.add(root.val);
		pa(root.left,target,arr,list,sum);
		pa(root.right,target,arr,list,sum);
		list.remove(list.size()-1);
	}
}
9. 输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

public class Solution {
    public RandomListNode Clone(RandomListNode pHead)
    {      
       RandomListNode p=pHead;
        RandomListNode t=pHead;
        while(p!=null){
            RandomListNode q=new RandomListNode(p.label);
            q.next=p.next;
            p.next=q;
            p=q.next;
        }
        while(t!=null){
            RandomListNode q=t.next;
            if(t.random!=null)
            q.random=t.random.next;
            t=q.next;      
        }
        RandomListNode s=new RandomListNode(0);
        RandomListNode s1=s;
       while(pHead!=null){
           RandomListNode  q=pHead.next;
             pHead.next=q.next;
             q.next=s.next;
             s.next=q;
             s=s.next;
             pHead=pHead.next;         
       }
        return s1.next;        
   }
}
10. 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
public class Solution {
    public TreeNode Convert(TreeNode pRootOfTree) {
      if(pRootOfTree==null){
    	   return null;
       }
       if(pRootOfTree.left==null&&pRootOfTree.right==null) return pRootOfTree;
       TreeNode left=Convert(pRootOfTree.left);
       TreeNode p=left;
       while(p!=null&&p.right!=null){
    	   p=p.right;
       }
       if(left!=null){
    	   pRootOfTree.left=p;
    	   p.right=pRootOfTree;
       }
       TreeNode right=Convert(pRootOfTree.right);
       if(right!=null){
    	   right.left=pRootOfTree;
    	   pRootOfTree.right=right;
       }
       return left!=null?left:pRootOfTree;
    }
}

第二部分主要是二叉树的基本操作,包括二叉树的反转,几种遍历方式(前序,中序,后序,层序),要理解二叉树的指针指向。

(补充)笔试面试常识:

二叉树是一种非常重要的数据结构,它同时具有数组和链表各自的特点:它可以像数组一样快速查找,也可以像链表一样快速添加。但是他也有自己的缺点:删除操作复杂。

二叉排序树:是每个结点最多有两个子树的有序树,在使用二叉树的时候,数据并不是随便插入到节点中的,一个节点的左子节点的关键值必须小于此节点,右子节点的关键值必须大于或者是等于此节点,所以又称二叉查找树、二叉排序树、二叉搜索树。

完全二叉树:若设二叉树的高度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第h层有叶子结点,并且叶子结点都是从左到右依次排布,这就是完全二叉树。

满二叉树——除了叶结点外每一个结点都有左右子叶且叶子结点都处在最底层的二叉树。

二叉树特点:

(1)树执行查找、删除、插入的时间复杂度都是O(logN)

(2)遍历二叉树的方法包括前序、中序、后序

(3)非平衡树指的是根的左右两边的子节点的数量不一致

(4) 在非空二叉树中,第i层的结点总数不超过 , i>=1;

(5)深度为h的二叉树最多有个结点(h>=1),最少有h个结点;

(6)对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则N0=N2+1;









 



猜你喜欢

转载自blog.csdn.net/qq_31278903/article/details/71307946