刷题之旅2020.12.05

leetcode刷题 专栏收录该内容
3 篇文章 0 订阅

2020.12.05

1.前中后序 递归/非递归 实现

一、使用栈模拟递归实现过程

先序/中序

public List preinOrder2(TreeNode root){
    if(root==null)
        return;
    Stack<TreeNode> s=new Stack<>();
    List list = new LinkedList();
    while(root!=null || !s.isEmpty()){
        //不断往左子树方向走,每走一次就将当前节点保存到栈中
		//这是模拟递归的调用
        if(root != null){
            list.add(root.val);	//这里访问顺序是先序
            s.push(root);
            root = root.left;
        //当前节点为空,说明左边走到头了,从栈中弹出节点并保存
		//然后转向右边节点,继续上面整个过程
        }else{
            root = s.pop();
            list.add(root.val);	//这里访问顺序是中序
            root = root.right;
        }
    }
}

后序(模拟递归实现)

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

        Deque<TreeNode> stack = new LinkedList<TreeNode>();
        TreeNode prev = null;
        while (root != null || !stack.isEmpty()) {
            while (root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.pop();
            if (root.right == null || root.right == prev) {
                res.add(root.val);
                prev = root;
                root = null;
            } else {
                stack.push(root);
                root = root.right;
            }
        }
        return res;
    }
}

后序(利用前序实现「根-左-右」—> 「右-左-根」—> 「左-右-根」)

public List postorder(TreeNode root){
    TreeNode node = new TreeNode();
    Stack stack = new Stack();
    List list = new LinkedList();
    while(!stack.isEmpty() || root!=null){
        if(root != null){
            //头插法
            List.addFirst(root.val);
            stack.push(root);
            //优先访问右子树
            root = root.right;
        }else {
            root = stack.pop();
            root = root.left;
        }
    }
    return list;
}

颜色标记法模板

其核心思想如下:

  • 使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
  • 如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
  • 如果遇到的节点为灰色,则将节点的值输出
class Solution {
    class ColorNode {
        TreeNode node;
        String color;
        
        public ColorNode(TreeNode node,String color){
            this.node = node;
            this.color = color;
        }
    }
    public List<Integer> inorderTraversal(TreeNode root) {
        if(root == null) return new ArrayList<Integer>();
            
        List<Integer> list = new ArrayList<>();
        Stack<ColorNode> stack = new Stack<>();
        stack.push(new ColorNode(root,"white"));
        
        while(!stack.empty()){
            ColorNode cn = stack.pop();
            
            if(cn.color.equals("white")){
                // 入栈顺序 对应于访问结果顺序(这里为中序,对应 右 根 左)
                if(cn.node.right != null) stack.push(new ColorNode(cn.node.right,"white")); 
                stack.push(new ColorNode(cn.node,"gray"));
                if(cn.node.left != null)stack.push(new ColorNode(cn.node.left,"white"));
            }else{
                list.add(cn.node.val);
            }
        }
        
        return list;
    }
}
另一种奇技淫巧,直接判断栈元素是否为TreeNode
public List<Integer> inorderTraversal(TreeNode root) {
        Stack<Object> stack = new Stack<>();
        List<Integer> list = new ArrayList<>();
        if (root == null)
            return list;
        stack.push(root);
        while (!stack.isEmpty()) {
            Object pop = stack.pop();
            if (pop instanceof TreeNode) {
                // 入栈顺序 对应于访问结果顺序(这里为中序,对应 右 根 左)
                TreeNode treeNode = (TreeNode) pop;
                if (treeNode.right != null) {
                    stack.push(treeNode.right);
                }
                stack.push(new Integer(treeNode.val));
                if (treeNode.left != null) {
                    stack.push(treeNode.left);
                }
            } else {
				list.add((Integer)pop);
            }
        }
        return list;
    }

链表

1.两两交换链表中节点 (leetcode24)

思路:可以使用迭代或者递归实现

迭代实现:

新建哑结点nHead,令nHead.next = head,令 temp 表示当前到达的节点,初始时 temp = nHead。每次需要交换 temp 后面的两个节点即可,如果 temp 的后面没有节点或者只有一个节点,则没有更多的节点需要交换,因此结束交换。否则,获得 temp 后面的两个节点 node1 和 node2,通过更新节点的指针关系实现两两交换节点。

    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null)
            return head;
        ListNode nHead = new ListNode(-1);
        nHead.next = head;
        ListNode temp = nHead;
        while (temp.next != null && temp.next.next != null) {
            ListNode nNext = temp.next.next;
            temp.next.next = nNext.next;
            nNext.next = temp.next;
            temp.next = nNext;
            temp = nNext.next;
        }
        return nHead.next;     
    }

递归实现:

终止条件为head == null || head.next == null;

递归思路就是假设head.next.next后面已经完成两两交换,并返回,即temp = swapPairs(head.next.next);

则单次递归执行逻辑为:ListNode newHead = head.next; head.next = temp;newHead.next = head;

class Solution {
    public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode newHead = head.next;
        head.next = swapPairs(newHead.next);
        newHead.next = head;
        return newHead;
    }
}

2.反转链表||(leetcode92)

输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL

反转从位置m到n的链表。思想:在第m节点的前一个位置(这里指向1)设为pre节点,利用cur指针(这里指向2)依次将cur节点的后置节点插入到pre后面,执行逻辑为:ListNode nxt = cur.next;cur.next = nxt.next;nxt.next = pre.next;pre.next = nxt;

public ListNode reverseBetween(ListNode head, int m, int n) {
        if (head == null) return null;
       
        ListNode pre = new ListNode(-1);
        ListNode nHead = pre;
        pre.next = head;
        for (int i=1; i<m; i++) {
            pre = pre.next;
        }
        ListNode cur = pre.next;
        for (int i=m; i<n; i++) {
            ListNode nxt = cur.next;
            cur.next = nxt.next;
            nxt.next = pre.next;
            pre.next = nxt;
        }
        return nHead.next;
    }

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页

打赏

Coderwangz

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值