文章目錄
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中序遍歷
/**
* 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);
*/