【LeetCode】《剑指Offer》第Ⅳ篇⊰⊰⊰ 32 - 38题

【LeetCode】《剑指Offer》第Ⅳ篇⊰⊰⊰ 32 - 38题

32-Ⅰ. 从上到下打印二叉树(medium)

剑指 Offer 32 - I. 从上到下打印二叉树

题目】从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

示例

给定二叉树: [3,9,20,null,null,15,7],

返回[3,9,20,15,7]

解题思路

层次遍历

class Solution {
    
    
    public int[] levelOrder(TreeNode root) {
    
    
        if (root == null) return new int[]{
    
    };
       
        List<Integer> list = new ArrayList<>();
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root); 
        while (!queue.isEmpty()) {
    
    
            TreeNode node = queue.poll();
            list.add(node.val);
            if(node.left != null) queue.offer(node.left);
            if(node.right != null) queue.offer(node.right);
        }

        int []res = new int[list.size()];
        for (int i = 0; i < list.size(); i++) res[i] = list.get(i);
        return res;
    }
}

32-Ⅱ. 从上到下打印二叉树 II(easy)

剑指 Offer 32 - II. 从上到下打印二叉树 II

题目】从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

示例

给定二叉树: [3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:
[
  [3],
  [9,20],
  [15,7]
]

解题思路

层次遍历

class Solution {
    
    
    public List<List<Integer>> levelOrder(TreeNode root) {
    
    
        if (root == null) {
    
    
            return new ArrayList<>();
        }
        List<List<Integer>> list = new ArrayList<>();
        Queue<TreeNode> queue = new ArrayDeque<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
    
    
            List<Integer> l = new ArrayList<>();
            int len = queue.size();
            while (len > 0) {
    
    
                TreeNode p = queue.poll();
                l.add(p.val);
                if (p.left != null) {
    
    
                    queue.offer(p.left);
                }
                if (p.right != null) {
    
    
                    queue.offer(p.right);
                }
                len--;
            }
            list.add(l);
        }
        return list;
    }
}

32-Ⅲ. 从上到下打印二叉树 III(medium)

剑指 Offer 32 - III. 从上到下打印二叉树 III

题目】请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

解题思路

递归或者层次遍历

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

    public void iter(TreeNode root, int deep){
    
    
        if (root == null) return;
        if (list.size() == deep) list.add(new ArrayList<>());
        if (deep % 2 == 0) {
    
    
            list.get(deep).add(root.val);
        } else {
    
    
            list.get(deep).add(0, root.val);
        }
        iter(root.left, deep + 1);
        iter(root.right, deep + 1);
    }
}

33. 二叉搜索树的后序遍历序列(medium)

剑指 Offer 33. 二叉搜索树的后序遍历序列

题目】输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

提示:数组长度 <= 1000

示例

     5
    / \
   2   6
  / \
 1   3
输入: [1,6,3,2,5]
输出: false
-------------------
输入: [1,3,2,6,5]
输出: true

解题思路

单调栈

class Solution {
    
    
    public boolean verifyPostorder(int[] postorder) {
    
    
        Stack<Integer> stack = new Stack<>();
        int parent = Integer.MAX_VALUE;
        //逆向遍历,就是翻转的先序遍历
        for (int i = postorder.length - 1; i >= 0; i--) {
    
    
            int cur = postorder[i];
            while (!stack.isEmpty() && cur < stack.peek()) {
    
    
                parent = stack.pop();
            }
            if (cur > parent) {
    
    
                return false;
            }
            stack.add(cur);
        }
        return true;
    }
}

34. 二叉树中和为某一值的路径(medium)

剑指 Offer 34. 二叉树中和为某一值的路径

题目】输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

示例

给定如下二叉树,以及目标和 sum = 22
              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1
返回:
[
   [5,4,11,2],
   [5,8,4,5]
]

解题思路

递归

class Solution {
    
    
    List<List<Integer>> res;
    List<Integer> list;
    
    public List<List<Integer>> pathSum(TreeNode root, int sum) {
    
    
        res = new ArrayList();
        list = new ArrayList<Integer>();
        iter(root, sum);
        return res;
    }

    private void iter(TreeNode root, int sum) {
    
    
        if (root == null) return;
        sum -= root.val;
        list.add(root.val);
        if (root.left == null && root.right == null && sum == 0) {
    
    
            res.add(new ArrayList<Integer>(list));
        }
        iter(root.left, sum);
        iter(root.right, sum);
        list.remove(list.size() - 1);
    }
}

35. 复杂链表的复制(medium)

剑指 Offer 35. 复杂链表的复制

题目】请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null

提示:

  • -10000 <= Node.val <= 10000
  • Node.random 为空(null)或指向链表中的节点。
  • 节点数目不超过 1000 。

示例

在这里插入图片描述

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

在这里插入图片描述

输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

解题思路

方法一:HashMap

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    
    
    public Node copyRandomList(Node head) {
    
    
        Map<Node, Node> map = new HashMap<>();
        for (Node p = head; p != null; p = p.next) {
    
    
            map.put(p, new Node(p.val));
        }
        for (Node p = head; p != null; p = p.next) {
    
    
            map.get(p).next = map.get(p.next);
            map.get(p).random = map.get(p.random);
        }
        return map.get(head);
    }
}

方法二:原地算法

class Solution {
    
    
    public Node copyRandomList(Node head) {
    
    
        if (head == null) return head;
        Node cur = head;
        //复制
        while (cur != null) {
    
    
            Node p = new Node(cur.val);
            p.next = cur.next;
            cur.next = p;
            cur = p.next;
        }
        //连接
        cur = head;
        while (cur != null) {
    
    
            Node p = cur.next;
            if (cur.random != null) {
    
    
                p.random = cur.random.next;
            }
            cur = cur.next.next;
        }
        //拆分
        Node res = head.next, t = res;
        cur = head;
        while (cur != null) {
    
    
            cur.next = cur.next.next;
            cur = cur.next;
            if (cur != null) {
    
    
                t.next = cur.next;
                t = t.next;
            }
        }
        return res;
    }
}

36. 二叉搜索树与双向链表(medium)

剑指 Offer 36. 二叉搜索树与双向链表

题目】输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。

为了让您更好地理解问题,以下面的二叉搜索树为例:

在这里插入图片描述

我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。

下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。

在这里插入图片描述

特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。

解题思路

中序遍历

class Solution {
    
    
    Node head, pre;
    public Node treeToDoublyList(Node root) {
    
    
        if (root == null) return null;
        helper(root);
        head.left = pre;
        pre.right = head;
        return head;
    }

    private void helper(Node cur) {
    
    
        if (cur == null) return;
        helper(cur.left);
        if (head == null) head = cur;
        if (pre == null) {
    
    
            pre = cur;
        } else {
    
    
            cur.left = pre;
            pre.right = cur;
            pre = cur;
        }
        helper(cur.right);
    }
}

37. 序列化二叉树(hard)

剑指 Offer 37. 序列化二叉树

题目】请实现两个函数,分别用来序列化和反序列化二叉树。

示例

你可以将以下二叉树:

    1
   / \
  2   3
     / \
    4   5

序列化为 "[1,2,3,null,null,4,5]"

解题思路

层序遍历,

例如上面那棵树,序列化后为"1,2,n,n,3,4,5,n,n,n,n"

public class Codec {
    
    

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
    
    
        if (root == null) {
    
    
            return "";
        }
        StringBuffer sb = new StringBuffer("");
        ArrayDeque<TreeNode> queue = new ArrayDeque<>();
        queue.offer(root);
        sb.append(root.val);
        
        while (!queue.isEmpty()) {
    
    
            TreeNode node = queue.poll();
            sb.append(',');
            if (node.left == null) {
    
    
                sb.append('n');
            } else {
    
    
                queue.offer(node.left);
                sb.append(node.left.val);
            }
            sb.append(',');
            if (node.right == null) {
    
    
                sb.append('n');
            } else {
    
    
                queue.offer(node.right);
                sb.append(node.right.val);
            }
        }
        return sb.toString();
    }
    
    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
    
    
        if (data.equals("")) {
    
    
            return null;
        }
        String[] spot = data.split(",");
        ArrayDeque<TreeNode> queue = new ArrayDeque();
        TreeNode root = new TreeNode(Integer.valueOf(spot[0]));
        queue.offer(root);
        int k = 1;
        
        while (!queue.isEmpty()) {
    
    
            TreeNode node = queue.poll();
            if (!spot[k].equals("n")) {
    
    
                TreeNode lnode = new TreeNode(Integer.valueOf(spot[k]));
                node.left = lnode;
                queue.offer(lnode);
            } else {
    
    
                node.left = null;
            }
            k++;
            if (!spot[k].equals("n")) {
    
    
                TreeNode rnode = new TreeNode(Integer.valueOf(spot[k]));
                node.right = rnode;
                queue.offer(rnode);
            } else {
    
    
                node.right = null;
            }
            k++;
        }
        return root;       
    }
}

38. 字符串的排列(medium)

剑指 Offer 38. 字符串的排列

题目】输入一个字符串,打印出该字符串中字符的所有排列。

你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。

限制:

1 <= s 的长度 <= 8

示例

输入:s = "abc"
输出:["abc","acb","bac","bca","cab","cba"]

解题思路

回溯法

关于求全排列的方法可以参考往期总结【LeetCode】﹝回溯法ி﹞ 全排列、子集、组合问题

class Solution {
    
    
    List<String> list;
    public String[] permutation(String s) {
    
    
        list = new ArrayList<>();
        backtrack(s.toCharArray(), 0);
        String[] res = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
    
    
            res[i] = list.get(i);
        }
        return res;
    }

    private void backtrack(char[] chars, int begin) {
    
    
        if (begin == chars.length - 1) {
    
    
            list.add(new String(chars));
            return;
        }
        Set<Character> set = new HashSet<>();
        for (int i = begin; i < chars.length; i++) {
    
    
            if (set.contains(chars[i])) continue;
            set.add(chars[i]);
            swap(chars, begin, i);
            backtrack(chars, begin + 1);
            swap(chars, begin, i);
        }
    }

    private void swap(char[] chars, int i, int j) {
    
    
        char c = chars[i];
        chars[i] = chars[j];
        chars[j] = c;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_44368437/article/details/114249554
今日推荐