面试中遇到的手撕代码(二)

8.栈的最大值问题

问题的描述和思路可以参考这里

Java实现代码如下:

import java.util.Stack;

/**
 * 栈的最大值问题 Title: Description: Company:
 * 
 * @author 郑伟
 * @date 2018年4月12日下午8:57:29
 */
public class SpecialStack {

    Stack<Integer> stack = new Stack<>();
    Stack<Integer> maxStack = new Stack<>();

    public void push(Integer num) {
        if (stack.isEmpty()) {
            maxStack.push(num);
            stack.push(num - maxStack.peek());
        } else {
            stack.push(num - maxStack.peek());
            if (num > maxStack.peek()) {
                maxStack.pop();
                maxStack.push(num);
            }
        }
    }

    public int pop() {
        if (!stack.isEmpty()) {
            if (stack.peek() >= 0 && !maxStack.isEmpty()) {
                int result = maxStack.pop();
                maxStack.push(result - stack.pop());
                return result;
            } else if (stack.peek() < 0 && !maxStack.isEmpty()) {
                return (maxStack.peek() + stack.pop());
            } else {
                return -1;
            }
        } else {
            return -1;
        }
    }

    public int max() {
        if (stack.isEmpty()) {
            return 0;
        }
        if (maxStack.isEmpty())
            return -1;
        return maxStack.peek();
    }

    public static void main(String[] args) {
        int arr[] = { 5, 4, 1, 2, 3, 10, 9, 8, 6, 7, 15 };
        SpecialStack specialStack = new SpecialStack();
        for (int i = 0; i < arr.length; i++) {
            specialStack.push(arr[i]);
            System.out.print("入栈:" + arr[i]);
            System.out.println("最大值:" + specialStack.max());
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.print("出栈:" + specialStack.pop());
            System.out.println("最大值:" + specialStack.max());
        }
    }

}

9.非递归实现二叉树的遍历

前序遍历:
对于树中的任意一个节点cur:
(1)访问cur,并将节点入栈;
(2)判断节点cur的左孩子是否为空。若不为空,则将cur的左孩子cur.left置为当前的结点cur;
(3)若为空,则取栈顶节点并进行出栈操作(根据出栈节点去找该节点的右孩子),并将栈顶结点的右孩子cur.right置为当前的结点cur,循环至1);

中序遍历:
对于树中的任意节点cur:
(1)若cur的左孩子不为空,将p压栈,并将cur的左子树置为当前节点cur,然后对当前节点重复操作。
(2)若cur的左孩子为空,将栈顶元素出栈并进行访问,把当前节点置为cur的右孩子。
(3)直到栈为空且cur为空

后序遍历:
对于树中的任意节点cur
(1) 如果该节点没有左孩子和右孩子可以直接访问该节点;
如果其左孩子和右孩子被访问过了,可以直接访问该节点;
(2)如果不是情况(1),那么就先将右孩子压栈,再将左孩子压栈,这样出栈顺序就是先出左孩子再出右孩子。

import java.util.Stack;

/**
 * 非递归的树的遍历 Title: Description: Company:
 * 
 * @author 郑伟
 * @date 2018年4月13日下午3:37:12
 */
public class Print_Tree {

    // 先序遍历非递归
    // 如果发现右儿子没有了,那么出栈,指向cur,如果cur右儿子有那么久打印右儿子,把右儿子入栈,如果没有右儿子,那么久继续出栈,出栈的节点设为cur
    public static void preOrder(TreeNode pNode) {
        Stack<TreeNode> stack = new Stack<>();
        while (pNode != null || !stack.isEmpty()) {
            while (pNode != null) {
                // 先打印当前节点
                System.out.print(pNode.val+" ");// 若节点不为空先访问再压栈
                stack.push(pNode);// 当前节点入栈
                pNode = pNode.left;// 将当前节点置为p的左孩子,若不为空继续访问并压栈
            }
            // 当p为空时,说明根节点和左孩子打印遍历完毕了,接下来出栈遍历右孩子
            if (!stack.isEmpty()) {// 左子树不存在,那么就是讲栈顶弹出,作为当前 节点
                pNode = stack.pop();
                // 讲当前节点设置为右边的节点
                pNode = pNode.right;
            }
        }
    }

    // 中序遍历非递归
    // 就只如果节点有左子树就不停的入栈,直到左边没有左子树,然后出栈,打印当前值,然后cur指向右节点。
    public static void InOrder(TreeNode pNode) {
        Stack<TreeNode> stack = new Stack<TreeNode>();
        while (pNode != null || !stack.isEmpty()) {
            // 不停的把左子树入栈
            while (pNode != null) {
                stack.push(pNode);
                pNode = pNode.left;
            }
            // 当左子树没有的时候,也就是如到底部了
            if (stack != null) {
                pNode = stack.pop();// 弹出一个节点
                System.out.print(pNode.val+" ");
                pNode = pNode.right;// 开始答应右边的节点
            }
        }
    }

    // 后续遍历
    // 先右子树压栈,再左子树压栈
    public static void PostOrder(TreeNode pNode) {
        if (pNode == null)
            return;
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode preNode = null;
        TreeNode curNode;
        stack.push(pNode);// 根节点先入栈
        while (!stack.isEmpty()) {
            curNode = stack.peek();
            // 如果当前节点的左右子节点都为null,那么就直接答应当前节点;
            // 当前一个节点不为空并且是当前节点的左孩子或者右孩子,当是左孩子时说明当前节点右孩子为空,
            // 当是右孩子时,说明左右孩子都访问过了,且都不为空
            if (curNode.left == null
                    && curNode.right == null
                    || (preNode != null && (preNode == curNode.left || preNode == curNode.right))) {
                System.out.print(curNode.val+" ");// 访问当前节点
                preNode = curNode;
                // curNode指向栈顶,由于打印过了,就直接出栈
                stack.pop();
            } else {
                // 当前节点为栈顶元素 如果当前节点不是叶子节点,在当前节点之前访问的那个节点不是当前节点的孩子,则进行压栈
                // 先压栈右节点再压栈左节点 这样出栈时是先左后右
                if (curNode.right != null)
                    stack.push(curNode.right);
                if (curNode.left != null)
                    stack.push(curNode.left);
            }
        }
    }

    public TreeNode buildTree(int[] nums, int i) {
        if (i >= nums.length)
            return null;
        TreeNode root = new TreeNode(nums[i]);
        root.left = buildTree(nums, i * 2 + 1);
        root.right = buildTree(nums, i * 2 + 2);
        return root;
    }

    public static void main(String[] args) {
        Print_Tree pTree = new Print_Tree();
        int[] nums = {1,2,3,4,5,6};
        TreeNode buildTree = pTree.buildTree(nums, 0);
        System.out.println("前序遍历");
        Print_Tree.preOrder(buildTree);
        System.out.println();
        System.out.println("中遍历");
        Print_Tree.InOrder(buildTree);
        System.out.println();
        System.out.println("后序遍历");
        Print_Tree.PostOrder(buildTree);
    }

}

/**
*前序遍历
*1 2 4 5 3 6 
*中遍历
*4 2 5 1 6 3 
*后序遍历
*4 5 2 6 3 1 
*/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章