day16-20/232/9/30/144/94/145-栈/栈实现队列/树的前中后序遍历-过后复习Morris算法

71 阅读4分钟

第一题-有效的括号

题目

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。
  2. 左括号必须以正确的顺序闭合。
  3. 每个右括号都有一个对应的相同类型的左括号

思路

用栈啊,一定存在一对括号直接是左右匹配的,所以,遍历字符串,遇到右括号,检查栈顶元素是否是相应的左括号,只要不匹配,就返回false,匹配的话,弹出栈顶元素,继续匹配下一项

代码

class Solution {
    public boolean isValid(String s) {
        Deque<Character> stack = new ArrayDeque<Character>();
        for(int i = 0; i < s.length(); i++) {
            if(s.charAt(i) == ')') {
                if(!stack.isEmpty() && stack.peek() == '(') {
                    stack.pop();
                }else {
                    return false;
                };
            }else if(!stack.isEmpty() && s.charAt(i) == '}') {
                if(stack.peek() == '{') {
                    stack.pop();
                }else {
                    return false;
                };
            }else if(!stack.isEmpty() && s.charAt(i) == ']') {
                if(stack.peek() == '[') {
                    stack.pop();
                }else {
                    return false;
                };
            }else {
                stack.push(s.charAt(i));
            };
        };
        return stack.isEmpty();
    }
}

第二题-用栈实现队列-后面加两道这个的附加题

题目

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 你 只能 使用标准的栈操作 —— 也就是只有 push to toppeek/pop from topsize, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可

代码

class MyQueue {
    Deque<Integer> inStack;
    Deque<Integer> outStack;
    public MyQueue() {
        inStack = new ArrayDeque<Integer>();
        outStack = new ArrayDeque<Integer>();
    }
    
    public void push(int x) {
        inStack.push(x);
    }
    
    public int pop() {
        if(outStack.isEmpty()) {
            inToOut();
        }
        return outStack.pop();
    }
    
    public int peek() {
        if(outStack.isEmpty()) {
            inToOut();
        }
        return outStack.peek();
    }
    
    public boolean empty() {
        if(outStack.isEmpty()) {
            inToOut();
        }
        return outStack.isEmpty();
    }

    private void inToOut() {
        while(!inStack.isEmpty()) {
            outStack.push(inStack.pop());
        };
    }
}

第二题附加题01-用两个栈实现队列

题目

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

思路

感谢一直以来的坚持刷题,做这道题的时候,还有做第二题的印象,所以直接就写了

代码

class CQueue {
    Deque<Integer> inStack;
    Deque<Integer> outStack;

    public CQueue() {
        inStack = new ArrayDeque<Integer>();
        outStack = new ArrayDeque<Integer>();
    }
    
    public void appendTail(int value) {
        inStack.push(value);
    }
    
    public int deleteHead() {
        if(outStack.isEmpty()) {
            inToOut();
        }
        return outStack.isEmpty() ? -1 : outStack.pop();
    }

    public void inToOut() {
        while(!inStack.isEmpty()) {
            outStack.push(inStack.pop());
        }
    }
}

第二题附加题02- 包含min函数的栈

题目

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)

思路

最开始思路错了,原本想设置一个全局的min,然后直接返回,但是忘记了当队列删除掉最小元素,这时的min就不在队列中了,所以参考了题解,使用栈进行存储最小元素,这个栈在我这边看来,就是单调栈

代码

class MinStack {
    int minNum;
    Deque<Integer> stcakTemp;
    Deque<Integer> minStack;
    /** initialize your data structure here. */
    public MinStack() {
        stcakTemp = new ArrayDeque<Integer>();
        minStack = new ArrayDeque<Integer>();
        minNum = 2147483647;
    }
    
    public void push(int x) {
        stcakTemp.push(x);
        if(minStack.isEmpty() || minStack.peek() >= x) {
            minStack.push(x);
        }
    }
    
    public void pop() {
        if(stcakTemp.pop().equals(minStack.peek())) {
            minStack.pop();
        }
    }
    
    public int top() {
        return stcakTemp.peek();
    }
    
    public int min() {
        return minStack.peek();
    }
}

第三题-树的先序遍历-根-左-右

题目

给你二叉树的根节点 root ,返回它节点值的 前序 **遍历

思路

1、递归-递归简单哎,先扔进去根结点,然后递归左子树,再递归右子树

2、morris算法-看的官方题解-(好难,好烧脑,差点放弃,多走两遍就好了)

代码

1、递归

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        preFun(root, list);
        return list;
    }

    public static void preFun(TreeNode root, List list) {
        if(root != null) {
            list.add(root.val);
            preFun(root.left, list);
            preFun(root.right, list);
        }else {
            return;
        }
    }
}

2、morris

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if (root == null) {
            return res;
        }

        TreeNode p1 = root, p2 = null;

        while (p1 != null) {
            p2 = p1.left;
            if(p2 != null) {
                while(p2.right != null && p2.right != p1) {
                    p2 = p2.right;
                }
                if(p2.right == null) {
                    res.add(p1.val);
                    p2.right = p1;
                    p1 = p1.left;
                    continue;
                }else {
                    p2.right = null;
                }
            }else {
                res.add(p1.val);
            }
            p1 = p1.right;
        }
        return res;
    }
}

第四题-树的中序遍历-左-根-右

题目

给定一个二叉树的根节点 root ,返回 它的 中序 遍历

思路

和第三题一样的

代码

1、递归

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        preFun(root, list);
        return list;
    }

    public static void preFun(TreeNode root, List list) {
        if(root != null) {
            preFun(root.left, list);
            list.add(root.val);
            preFun(root.right, list);
        }else {
            return;
        }
    }
}

2、morris

class Solution {
    public List<Integer> inorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        TreeNode p1 = root;
        while(p1 != null) {
            TreeNode p2 = p1.left;
            if(p2 != null) {
                while(p2.right != null && p2.right != p1) {
                    p2 = p2.right;
                };
                if(p2.right == null) {
                    p2.right = p1;
                    p1 = p1.left;
                    continue;
                }else {
                    p2.right = null;
                };
            }
            list.add(p1.val);
            p1 = p1.right;
        }
        return list;
    }
}

第五题-树的后序遍历

题目

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历

思路

思路同上,但是morris后序遍历我不会,也看不懂,先贴个代码,后续来看

代码

1、递归

class Solution {
    public List<Integer> preorderTraversal(TreeNode root) {
        List<Integer> list = new ArrayList<Integer>();
        preFun(root, list);
        return list;
    }

    public static void preFun(TreeNode root, List list) {
        if(root != null) {
            preFun(root.left, list);
            preFun(root.right, list);
            list.add(root.val);
        }else {
            return;
        }
    }
}

2、morris

class Solution {
    public List<Integer> postorderTraversal(TreeNode root) {
        List<Integer> res = new ArrayList<Integer>();
        if (root == null) {
            return res;
        }

        TreeNode p1 = root, p2 = null;
        while (p1 != null) {
            p2 = p1.left;
            if(p2 != null) {
                while(p2.right != null && p2.right != p1) {
                    p2 = p2.right;
                }
                if(p2.right == null) {
                    p2.right = p1;
                    p1 = p1.left;
                    continue;
                }else {
                    p2.right = null;
                    printEdge(p1.left, res);
                }
            }
            p1 = p1.right;
        }
        printEdge(root, res);
        return res;
    }
    public static void printEdge(TreeNode node, List list){
       TreeNode tail =reverseEdge(node);
       TreeNode cur = tail;
       while (cur != null ){
           list.add(cur.val);
           cur =cur.right;
       }
       reverseEdge(tail);
   }
   public static TreeNode reverseEdge(TreeNode node){
       TreeNode pre = null;
       TreeNode next = null;
       while (node != null){
           next = node.right;
           node.right = pre;
           pre = node;
           node = next;
       }
       return pre;
   }
}