LeetCode題解——樹(四)

BST

將有序數組轉換爲二叉搜索樹

將一個按照升序排列的有序數組,轉換爲一棵高度平衡二叉搜索樹。

本題中,一個高度平衡二叉樹是指一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過 1。

示例:

給定有序數組: [-10,-3,0,5,9],

一個可能的答案是:[0,-3,9,-10,null,5],它可以表示下面這個高度平衡二叉搜索樹:

      0
     / \
   -3   9
   /   /
 -10  5

遞歸

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode sortedArrayToBST(int[] nums) {
        return toBeBST(nums, 0, nums.length - 1);
    }
    private TreeNode toBeBST(int[] nums, int left, int right) {
        if (left > right) {
            return null;
        }
        int mid = (left + right) / 2;
        TreeNode root = new TreeNode(nums[mid]);
        root.left = toBeBST(nums, left, mid - 1);
        root.right = toBeBST(nums, mid + 1, right);
        return root;
    }

}

有序鏈表轉換二叉搜索樹

給定一個單鏈表,其中的元素按升序排序,將其轉換爲高度平衡的二叉搜索樹。

本題中,一個高度平衡二叉樹是指一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過 1。

示例:

給定的有序鏈表: [-10, -3, 0, 5, 9],

一個可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面這個高度平衡二叉搜索樹:

      0
     / \
   -3   9
   /   /
 -10  5

遞歸

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode sortedListToBST(ListNode head) {
        if (head == null) {
            return null;
        }
        if (head.next == null) {
            return new TreeNode(head.val);
        }
        ListNode preMid = preMid(head);
        ListNode mid = preMid.next;
        preMid.next = null;
        TreeNode root = new TreeNode(mid.val);
        root.left = sortedListToBST(head);
        root.right = sortedListToBST(mid.next);
        return root;
    }
    private ListNode preMid(ListNode head) {
        ListNode slow = head, fast = head.next;
        ListNode pre = head;
        while(fast != null && fast.next != null) {
            pre = slow;
            slow = slow.next;
            fast = fast.next.next;
        }
        return pre;
    }
}

中序遍歷

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private ListNode head;
    private int findSize(ListNode node) {
        ListNode ptr = node;
        int count = 0;
        while (ptr != null) {
            ptr = ptr.next;
            count++;
        }
        return count;
    }
    private TreeNode toBeBST(int left, int right) {
        if (left > right) {
            return null;
        }
        int mid = (left + right) / 2;
        TreeNode leftNode = toBeBST(left, mid - 1);
        TreeNode node = new TreeNode(this.head.val);
        node.left = leftNode;
        this.head = this.head.next;
        node.right = toBeBST(mid + 1, right);
        return node;
    }
    public TreeNode sortedListToBST(ListNode head) {
        if (head == null) {
            return null;
        }
        if (head.next == null) {
            return new TreeNode(head.val);
        }
        int size = findSize(head);
        this.head = head;
        return toBeBST(0, size - 1);
    }
}

兩數之和 IV - 輸入 BST

給定一個二叉搜索樹和一個目標結果,如果 BST 中存在兩個元素且它們的和等於給定的目標結果,則返回 true。

案例 1:

輸入: 
    5
   / \
  3   6
 / \   \
2   4   7

Target = 9

輸出: True
 

案例 2:

輸入: 
    5
   / \
  3   6
 / \   \
2   4   7

Target = 28

輸出: False

中序遍歷

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean findTarget(TreeNode root, int k) {
        List<Integer> nums = new ArrayList<>();
        inOrder(root, nums);
        int i = 0, j = nums.size() - 1;
        while(i < j) {
            int sum = nums.get(i) + nums.get(j);
            if (sum == k) {
                return true;
            } else if (sum < k) {
                i++;
            } else {
                j--;
            }
        }
        return false;
    }
    private void inOrder(TreeNode node, List<Integer> nums) {
        if (node == null) {
            return;
        }
        inOrder(node.left, nums);
        nums.add(node.val);
        inOrder(node.right, nums);
    }
}

二叉搜索樹的最小絕對差

給你一棵所有節點爲非負值的二叉搜索樹,請你計算樹中任意兩節點的差的絕對值的最小值。

示例:

輸入:

   1
    \
     3
    /
   2

輸出:
1

解釋:
最小絕對差爲 1,其中 2 和 1 的差的絕對值爲 1(或者 2 和 3)。
 

提示:

樹中至少有 2 個節點。
本題與 783 https://leetcode-cn.com/problems/minimum-distance-between-bst-nodes/ 相同

中序遍歷

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int getMinimumDifference(TreeNode root) {
        List<Integer> nums = new ArrayList<>();
        int min = Integer.MAX_VALUE;
        inOrder(root, nums);
        int size = nums.size();
        int j = 1;
        for (int i = 0; i < size - 1 && j <= size - 1; ) {
            int tmp = Math.abs(nums.get(i) - nums.get(j));
            if (tmp < min) {
                min = tmp;
            }
            i++;
            j++;
        }
        return min;
    }
    private void inOrder(TreeNode node, List<Integer> nums) {
        if (node == null) {
            return;
        }
        inOrder(node.left, nums);
        nums.add(node.val);
        inOrder(node.right, nums);
    }
}

中序遍歷優化

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private TreeNode preNode = null;
    private int min = Integer.MAX_VALUE;
    public int getMinimumDifference(TreeNode root) {
        inOrder(root);
        return min;
    }
    private void inOrder(TreeNode node) {
        if (node == null) {
            return;
        }
        inOrder(node.left);
        if (preNode != null) {
            min = Math.min(min, Math.abs(preNode.val - node.val));
        }
        preNode = node;
        inOrder(node.right);
    }
}

二叉搜索樹中的衆數

給定一個有相同值的二叉搜索樹(BST),找出 BST 中的所有衆數(出現頻率最高的元素)。

假定 BST 有如下定義:

結點左子樹中所含結點的值小於等於當前結點的值
結點右子樹中所含結點的值大於等於當前結點的值
左子樹和右子樹都是二叉搜索樹
例如:
給定 BST [1,null,2,2],

   1
    \
     2
    /
   2
返回[2].

提示:如果衆數超過1個,不需考慮輸出順序

進階:你可以不使用額外的空間嗎?(假設由遞歸產生的隱式調用棧的開銷不被計算在內)

中序遍歷

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private TreeNode preNode = null;
    private int curCount = 1;
    private int maxCount = 1;
    public int[] findMode(TreeNode root) {
        List<Integer> nums = new ArrayList<>();
        inOrder(root, nums);
        int i = 0;
        int[] res = new int[nums.size()];
        for (int num : nums) {
            res[i++] = num;
        }
        return res;
    }
    private void inOrder(TreeNode node, List<Integer> nums) {
        if (node == null) {
            return;
        }
        inOrder(node.left, nums);
        if (preNode != null) {
            if (preNode.val == node.val) {
                curCount++;
            } else {
                curCount = 1;
            }
        }
        if (curCount > maxCount) {
            maxCount = curCount;
            nums.clear();
            nums.add(node.val);
        } else if (curCount == maxCount) {
            nums.add(node.val);
        }
        preNode = node;
        inOrder(node.right, nums);
    }
}

Morris中序遍歷

詳解見https://leetcode-cn.com/problems/find-mode-in-binary-search-tree/solution/lian-di-gui-du-bu-yong-de-chang-shu-kong-jian-fu-z/

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] findMode(TreeNode root) {
        TreeNode cur = root, pre = null;
        ArrayList<Integer> nums = new ArrayList<>();
        int curCount = 1, maxCount = 1;
        while (cur != null) {
            if (cur.left == null) { // 左子樹爲空,直接比較
                if (pre != null && pre.val == cur.val) {
                    curCount++;
                } else {
                    curCount = 1;
                }
                if (curCount > maxCount) {
                    maxCount = curCount;
                    nums.clear();
                    nums.add(cur.val); 
                } else if (curCount == maxCount) {
                    nums.add(cur.val); 
                }
                pre = cur;
                cur = cur.right;
            } else { // 進入左子樹
                TreeNode preTemp = cur.left;
                while (preTemp.right != null && preTemp.right != cur) {
                    preTemp = preTemp.right;
                }
                if (preTemp.right == cur) {
                    if (pre != null && pre.val == cur.val) {
                        curCount++;
                    } else {
                        curCount = 1;
                    }
                    if (curCount > maxCount) {
                        maxCount = curCount;
                        nums.clear();
                        nums.add(cur.val); 
                    } else if (curCount == maxCount) {
                        nums.add(cur.val);
                    }
                    preTemp.right = null;
                    pre = cur;
                    cur = cur.right;
                } else {
                    preTemp.right = cur;
                    cur = cur.left;
                }
            }
        }
        int[] res = new int[nums.size()];
        int index = 0;
        for (int num : nums) {
            res[index++] = num;
        }
        return res;
    }
}

字典樹

實現 Trie (前綴樹)

實現一個 Trie (前綴樹),包含 insert, search, 和 startsWith 這三個操作。

示例:

Trie trie = new Trie();

trie.insert("apple");
trie.search("apple");   // 返回 true
trie.search("app");     // 返回 false
trie.startsWith("app"); // 返回 true
trie.insert("app");   
trie.search("app");     // 返回 true
說明:

你可以假設所有的輸入都是由小寫字母 a-z 構成的。
保證所有輸入均爲非空字符串。

解法

class Trie {

    /** Initialize your data structure here. */
    public Trie() {
        
    }
    
    private class Node {
        Node[] children = new Node[26];
        boolean isLeaf;
    }
    
    private Node root = new Node();
    
    /** Inserts a word into the trie. */
    public void insert(String word) {
        insert(word, root);
    }
    
    private void insert(String word, Node node) {
        if (node == null) {
            return;
        }
        if (word.length() == 0) {
            node.isLeaf = true;
            return;
        }
        int index = indexForChar(word.charAt(0));
        if (node.children[index] == null) {
            node.children[index] = new Node();
        }
        insert(word.substring(1), node.children[index]);
    }
    
    private int indexForChar(char c) {
        return c - 'a';
    }
        
    /** Returns if the word is in the trie. */
    public boolean search(String word) {
        return search(word, root);
    }
    
    private boolean search(String word, Node node) {
        if (node == null) {
            return false;
        }
        if (word.length() == 0) {
            return node.isLeaf;
        }
        int index = indexForChar(word.charAt(0));
        return search(word.substring(1), node.children[index]);
    }
    
    /** Returns if there is any word in the trie that starts with the given prefix. */
    public boolean startsWith(String prefix) {
        return startsWith(prefix, root);
    }
    
    private boolean startsWith(String prefix, Node node) {
        if (node == null) {
            return false;
        }
        if (prefix.length() == 0) {
            return true;
        }
        int index = indexForChar(prefix.charAt(0));
        return startsWith(prefix.substring(1), node.children[index]);
    }
}

/**
 * Your Trie object will be instantiated and called as such:
 * Trie obj = new Trie();
 * obj.insert(word);
 * boolean param_2 = obj.search(word);
 * boolean param_3 = obj.startsWith(prefix);
 */

鍵值映射

實現一個 MapSum 類裏的兩個方法,insert 和 sum。

對於方法 insert,你將得到一對(字符串,整數)的鍵值對。字符串表示鍵,整數表示值。如果鍵已經存在,那麼原來的鍵值對將被替代成新的鍵值對。

對於方法 sum,你將得到一個表示前綴的字符串,你需要返回所有以該前綴開頭的鍵的值的總和。

示例 1:

輸入: insert("apple", 3), 輸出: Null
輸入: sum("ap"), 輸出: 3
輸入: insert("app", 2), 輸出: Null
輸入: sum("ap"), 輸出: 5

解法

class MapSum {
    
    private class Node {
        Node[] children = new Node[26];
        int value;
    }
    
    private Node root = new Node();

    /** Initialize your data structure here. */
    public MapSum() {
    
    }
    
    public void insert(String key, int val) {
        insert(key, root, val);
    }
    
    private void insert(String key, Node node, int val) {
        if (key == null) {
            return;
        }
        if (key.length() == 0) {
            node.value = val;
            return;
        }
        int index = indexForChar(key.charAt(0));
        if (node.children[index] == null) {
            node.children[index] = new Node();
        }
        insert(key.substring(1), node.children[index], val);
    }
    
    private int indexForChar(char c) {
        return c - 'a';
    }
    
    public int sum(String prefix) {
        return sum(prefix, root);
    }
    
    private int sum(String prefix, Node node) {
        if (node == null) {
            return 0;
        }
        if (prefix.length() != 0) {
            int index = indexForChar(prefix.charAt(0));
            return sum(prefix.substring(1), node.children[index]);
        }
        int sum = node.value;
        for (Node child : node.children) {
            sum += sum(prefix, child);
        }
        return sum;
    }
}

/**
 * Your MapSum object will be instantiated and called as such:
 * MapSum obj = new MapSum();
 * obj.insert(key,val);
 * int param_2 = obj.sum(prefix);
 */

推薦閱讀


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章