参考☞:CS-Notes
递归
一棵树要么是空树,要么有两个指针,每个指针指向一棵树。树是一种递归结构,很多树的问题可以使用递归来处理。
1. 树的高度
Leetcode (opens new window)/ 力扣
class Solution {
public int maxDepth(TreeNode root) {
// 结束条件
if (root == null) {
return 0;
}
// 本级递归要做的事
// 左子树高度
int leftDepth = maxDepth(root.left);
// 右子树高度
int rightDepth = maxDepth(root.right);
// 返回值
// 左右子树最高的就是树的高度
return Math.max(leftDepth, rightDepth) + 1;
}
}
2. 平衡树
Leetcode (opens new window)/ 力扣
class Solution {
// 标志位,如果为 true 就说明是平衡二叉树,否则反之
private boolean flag = true;
public boolean isBalanced(TreeNode root) {
maxDepth(root);
return flag;
}
/**
* 递归计算树的高度
*/
public int maxDepth(TreeNode root) {
// 结束条件
if (root == null) {
return 0;
}
// 本级递归要做的事
// 得到左右子树高度
int leftDepth = maxDepth(root.left);
int rightDepth = maxDepth(root.right);
// 如果左右两个子树的高度差大于 1
// 将标志位置为 false
if (Math.abs(leftDepth - rightDepth) > 1) {
flag = false;
}
// 返回值
// 返回左右子树的最大高度
return Math.max(leftDepth, rightDepth) + 1;
}
}
3. 两节点的最长路径
Leetcode (opens new window)/ 力扣
class Solution {
// 直径长度
private int max = 0;
public int diameterOfBinaryTree(TreeNode root) {
depth(root);
return max;
}
public int depth(TreeNode root) {
// 结束条件
if (root == null) {
return 0;
}
// 本级递归要做的事
int leftDepth = depth(root.left);
int rightDepth = depth(root.right);
// 一棵二叉树的直径长度是任意两个结点路径长度中的最大值
max = Math.max(max, leftDepth + rightDepth);
// 返回值
return Math.max(leftDepth, rightDepth) + 1;
}
}
4. 翻转树
Leetcode (opens new window)/ 力扣
/**
* 递归实现
* 思想:翻转左子树和右子树就完事了
*/
class Solution {
public TreeNode invertTree(TreeNode root) {
// 结束条件
if (root == null) {
return root;
}
// 本级递归要做的事
// 因为 root.left 的值会改变
// 所以需要提前记录下来
TreeNode node = root.left;
root.left = invertTree(root.right);
root.right = invertTree(node);
// 返回值
return root;
}
}
5. 归并两棵树
Leetcode (opens new window)/ 力扣
/**
* 递归实现
*/
class Solution {
public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
// 结束条件
if (root1 == null && root2 == null) {
return null;
}
if (root1 == null) {
return root2;
}
if (root2 == null) {
return root1;
}
// 本级递归要做的事
TreeNode root = new TreeNode(root1.val + root2.val);
root.left = mergeTrees(root1.left, root2.left);
root.right = mergeTrees(root1.right, root2.right);
// 返回值
return root;
}
}
6. 判断路径和是否等于一个数
Leetcode (opens new window)/ 力扣
/**
* 递归实现
* 思想:从根节点开始找,从左右子树分别开始递归
*/
class Solution {
public boolean hasPathSum(TreeNode root, int targetSum) {
// 结束条件
if (root == null) {
return false;
}
// 本级递归要做的事
if (root.left == null && root.right == null && root.val == targetSum) {
return true;
}
// 返回值
return hasPathSum(root.left, targetSum - root.val) ||
hasPathSum(root.right, targetSum - root.val);
}
}
7. 统计路径和等于一个数的路径数量
Leetcode (opens new window)/ 力扣
class Solution {
public int pathSum(TreeNode root, int targetSum) {
if (root == null) {
return 0;
}
// 三种情况相加
int result = pathSumStartWithRoot(root, targetSum) +
pathSum(root.left, targetSum) +
pathSum(root.right, targetSum);
return result;
}
public int pathSumStartWithRoot(TreeNode root, int targetSum) {
if (root == null) {
return 0;
}
int result = 0;
if (root.val == targetSum) {
result++;
}
result += pathSumStartWithRoot(root.left, targetSum - root.val) +
pathSumStartWithRoot(root.right, targetSum - root.val);
return result;
}
}
8. 子树
Leetcode (opens new window)/ 力扣
class Solution {
public boolean isSubtree(TreeNode root, TreeNode subRoot) {
if (root == null) {
return false;
}
return isSameTree(root, subRoot) ||
isSubtree(root.left, subRoot) ||
isSubtree(root.right, subRoot);
}
public boolean isSameTree(TreeNode s, TreeNode t) {
if (s == null && t == null) {
return true;
}
if (s == null || t == null) {
return false;
}
if (s.val != t.val) {
return false;
}
return isSameTree(s.left, t.left) && isSameTree(s.right, t.right);
}
}
9. 树的对称
Leetcode (opens new window)/ 力扣
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) {
return true;
}
return isSymmetric(root.left, root.right);
}
/**
* 方法重载
* 递归解决
*/
public boolean isSymmetric(TreeNode t1, TreeNode t2) {
// 结束条件
// 只有两个节点同时为空时,才返回 true,说明每个值都相同
if (t1 == null && t2 == null) {
return true;
}
if (t1 == null || t2 == null) {
return false;
}
// 本级递归要做的事
if (t1.val != t2.val) {
return false;
}
// 返回值
return isSymmetric(t1.left, t2.right) &&
isSymmetric(t1.right, t2.left);
}
}
10. 最小路径
Leetcode (opens new window)/ 力扣
class Solution {
public int minDepth(TreeNode root) {
// 结束条件
if (root == null) {
return 0;
}
// 本级递归要做的事
int leftDepth = minDepth(root.left);
int rightDepth = minDepth(root.right);
// 返回值
if (leftDepth == 0 || rightDepth == 0) {
return leftDepth + rightDepth + 1;
}
return Math.min(leftDepth, rightDepth) + 1;
}
}
11. 统计左叶子节点的和
Leetcode (opens new window)/ 力扣
class Solution {
/**
* 左节点定义:如果左节点不为空,且左节点没有左右孩子,那么这个节点就是左叶子。
* 判断当前节点是不是左叶子是无法判断的,必须要通过节点的父节点来判断其左孩子是不是左叶子。
*
*/
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) {
return 0;
}
int result = 0;
if (root.left != null && root.left.left == null && root.left.right == null) {
result += root.left.val;
}
return sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right) + result;
}
}
12. 相同节点值的最大路径长度
Leetcode (opens new window)/ 力扣
class Solution {
// 返回结果
private int result;
public int longestUnivaluePath(TreeNode root) {
result = 0;
arrowLength(root);
return result;
}
public int arrowLength(TreeNode root) {
if (root == null) {
return 0;
}
int left = arrowLength(root.left);
int right = arrowLength(root.right);
int arrowLeft = 0, arrowRight = 0;
if (root.left != null && root.left.val == root.val) {
arrowLeft += left + 1;
}
if (root.right != null && root.right.val == root.val) {
arrowRight += right + 1;
}
result = Math.max(result, arrowLeft + arrowRight);
return Math.max(arrowLeft, arrowRight);
}
}
13. 间隔遍历
Leetcode (opens new window)/ 力扣
(1)原始代码,使用递归
class Solution {
public int rob(TreeNode root) {
if (root == null) {
return 0;
}
// 两个组合(求最大值):
// (1)爷爷节点和四个孙子节点的和
// (2)两个儿子节点的和
// 爷爷节点的值
int money = root.val;
// 将四个孙子节点的值和爷爷节点的值相加
if (root.left != null) {
money += rob(root.left.left) + rob(root.left.right);
}
if (root.right != null) {
money += rob(root.right.left) + rob(root.right.right);
}
// 比较两个组合的最大值,然后返回
return Math.max(money, rob(root.left) + rob(root.right));
}
}
(2)进行优化,将以某个节点为根的最大值用 map 保存起来,避免重复计算,提升效率
class Solution {
public int rob(TreeNode root) {
Map<TreeNode, Integer> map = new HashMap<>();
return robInternal(root, map);
}
public int robInternal(TreeNode root, Map<TreeNode, Integer> map) {
if (root == null) {
return 0;
}
// 如果有就直接取出来,避免重复计算
if (map.containsKey(root)) {
return map.get(root);
}
int money = root.val;
if (root.left != null) {
money += robInternal(root.left.left, map) + robInternal(root.left.right, map);
}
if (root.right != null) {
money += robInternal(root.right.left, map) + robInternal(root.right.right, map);
}
int result = Math.max(money, robInternal(root.left, map) + robInternal(root.right, map));
// 将结果存入 map 中
map.put(root, result);
return result;
}
}
(3)再次优化
class Solution {
// 动态规划
public int rob(TreeNode root) {
int[] result = robInternal(root);
return Math.max(result[0], result[1]);
}
public int[] robInternal(TreeNode root) {
if (root == null) {
return new int[2];
}
int[] result = new int[2];
int[] left = robInternal(root.left);
int[] right = robInternal(root.right);
result[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
result[1] = root.val + left[0] + right[0];
return result;
}
}
14. 找出二叉树中第二小的节点
Leetcode (opens new window)/ 力扣
class Solution {
private int result = -1;
public int findSecondMinimumValue(TreeNode root) {
// 因为 root.val = min(root.left.val, root.right.val)
// 所以最小值必是 root 节点的值,即最小值会不断往上传递
dfs(root, root.val);
return result;
}
public void dfs(TreeNode root, int val) {
if (root == null) {
return ;
}
if (root.val != val) {
if (result == -1) {
result = root.val;
} else {
result = Math.min(result, root.val);
}
return ;
}
dfs(root.left, val);
dfs(root.right, val);
}
}
层次遍历
1. 二叉树的层序遍历
Leetcode (opens new window)/ 力扣
class Solution {
// BFS
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) {
return new ArrayList<List<Integer>>();
}
List<List<Integer>> result = new ArrayList<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
List<Integer> level = new ArrayList<>();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
level.add(node.val);
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
result.add(level);
}
return result;
}
}
2. 一棵树每层节点的平均数
Leetcode (opens new window)/ 力扣
class Solution {
// DFS
public List<Double> averageOfLevels(TreeNode root) {
// 记录每层的总和
List<Double> sums = new ArrayList<>();
// 记录每层的节点数量
List<Integer> counts = new ArrayList<>();
dfs(root, 0, counts, sums);
List<Double> averages = new ArrayList<>();
for (int i = 0; i < sums.size(); i++) {
averages.add(i, sums.get(i) / counts.get(i));
}
return averages;
}
public void dfs(TreeNode root, int level, List<Integer> counts, List<Double> sums) {
if (root == null) {
return ;
}
// 需要考虑第一次添加和
// 第 N 次添加两种情况
if (level < sums.size()) {
sums.set(level, sums.get(level) + root.val);
counts.set(level, counts.get(level) + 1);
} else {
sums.add(root.val * 1.0);
counts.add(1);
}
dfs(root.left, level + 1, counts, sums);
dfs(root.right, level + 1, counts, sums);
}
}
3. 得到左下角的节点
Leetcode (opens new window)/ 力扣
class Solution {
public int findBottomLeftValue(TreeNode root) {
if (root == null) {
return 0;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
root = queue.poll();
if (root.right != null) {
queue.add(root.right);
}
if (root.left != null) {
queue.add(root.left);
}
}
return root.val;
}
}
前中后序遍历
1
/ \
2 3
/ \ \
4 5 6
- 层次遍历顺序:[1, 2, 3, 4, 5, 6]
- 前序遍历顺序:[1, 2, 4, 5, 3, 6]
- 中序遍历顺序:[4, 2, 5, 1, 3, 6]
- 后序遍历顺序:[4, 5, 2, 6, 3, 1]
层次遍历使用 BFS
实现,利用的就是 BFS
一层一层遍历的特性;而前序、中序、后序遍历利用了 DFS
实现。
前序、中序、后序遍只是在对节点访问的顺序有一点不同,其它都相同。
(1)前序
void dfs(TreeNode root) {
visit(root);
dfs(root.left);
dfs(root.right);
}
(2)中序
void dfs(TreeNode root) {
dfs(root.left);
visit(root);
dfs(root.right);
}
(3)后序
void dfs(TreeNode root) {
dfs(root.left);
dfs(root.right);
visit(root);
}
(4)层次遍历
/**
* 思想:就是把每个节点加入队列,每个节点出队列的时候把它的子节点都加入队列。
* 队列:先进先出
*/
void bfs(TreeNode root) {
Queue<TreeNode> queue = new ArrayDeque<>();
queue.add(root);
while (!queue.isEmpty()) {
// Java 的 pop 写作 poll()
TreeNode node = queue.poll();
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
}
1. 实现二叉树的前序遍历
Leetcode (opens new window)/ 力扣
(1)递归实现
class Solution {
// 递归实现
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
preOrder(root, result);
return result;
}
public void preOrder(TreeNode root, List<Integer> result) {
if (root == null) {
return ;
}
result.add(root.val);
preOrder(root.left, result);
preOrder(root.right, result);
}
}
(2)非递归实现
class Solution {
// 非递归实现,栈
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if (root != null) {
stack.push(root);
}
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
if (node == null) {
continue;
}
result.add(node.val);
// 栈:先进后出
stack.push(node.right);
stack.push(node.left);
}
return result;
}
}
2. 实现二叉树的后序遍历
Leetcode (opens new window)/ 力扣
class Solution {
// 非递归实现
public List<Integer> postorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
if (root != null) {
stack.push(root);
}
List<Integer> result = new ArrayList<>();
while (!stack.isEmpty()) {
TreeNode node = stack.pop();
if (node == null) {
continue;
}
result.add(node.val);
stack.add(node.left);
stack.add(node.right);
}
Collections.reverse(result);
return result;
}
}
3. 实现二叉树的中序遍历
(1)递归实现
class Solution {
// 递归实现
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
dfs(root, result);
return result;
}
public void dfs(TreeNode root, List<Integer> result) {
if (root == null) {
return ;
}
dfs(root.left, result);
result.add(root.val);
dfs(root.right, result);
}
}
BST
二叉查找树(BST):根节点大于等于左子树所有节点,小于等于右子树所有节点。
二叉查找树中序遍历有序。
1. 修剪二叉查找树
Leetcode (opens new window)/ 力扣
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) {
return null;
}
// 1 如果 root.val 小于 low 的话
// 就修剪 root 和 root 的左节点,因为 root.val 是大于左子树的所有节点的
// 因为这是 BST(二叉查找树)
if (root.val < low) {
root = root.right;
root = trimBST(root, low, high);
// 与 1 同理
} else if (root.val > high) {
root = root.left;
root = trimBST(root, low, high);
} else {
// 说明 root 满足区间条件
// 检查左右节点是否满足条件
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
}
return root;
}
}
简洁写法:
class Solution {
public TreeNode trimBST(TreeNode root, int low, int high) {
if (root == null) {
return null;
}
if (root.val < low) {
return trimBST(root.right, low, high);
}
if (root.val > high) {
return trimBST(root.left, low, high);
}
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);
return root;
}
}
2. 寻找二叉查找树的第 k 个元素
Leetcode (opens new window)/ 力扣
中序遍历解法:
class Solution {
private int count = 0;
private int val = 0;
public int kthSmallest(TreeNode root, int k) {
inOrder(root, k);
return val;
}
public void inOrder(TreeNode root, int k) {
if (root == null) {
return ;
}
inOrder(root.left, k);
count++;
if (count == k) {
val = root.val;
}
inOrder(root.right, k);
}
}
3. 把二叉搜索树转换为累加树
Leetcode (opens new window)/ 力扣
class Solution {
private int num = 0;
public TreeNode convertBST(TreeNode root) {
if (root != null) {
// 先遍历右子树
convertBST(root.right);
// 遍历顶点
root.val = root.val + num;
num = root.val;
// 遍历左子树
convertBST(root.left);
return root;
}
return null;
}
}
4. 二叉查找树的最近公共祖先
Leetcode (opens new window)/ 力扣
class Solution {
/**
* 二叉搜索树特性:
* 左子树比根节点小,右子树比根节点大
* 三种情况:
* (1)p,q 都小于 root,去左子树中找最近公共祖先
* (2)p,q 都大于 root,去右子树中找最近公共祖先
* (3)p,q 分布在左右子树,说明 root 就是最近公共祖先
*
* 递归思想,把树就看成 左-中-右 3 个节点
*/
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (p.val < root.val && q.val < root.val) {
return lowestCommonAncestor(root.left, p, q);
}
if (p.val > root.val && q.val > root.val) {
return lowestCommonAncestor(root.right, p, q);
}
return root;
}
}
5. 二叉树的最近公共祖先
Leetcode (opens new window)/ 力扣
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null) {
return null;
}
// 如果 p, q 有一个等于 root,说明 root 就是最近公共祖先
if (p.val == root.val || q.val == root.val) {
return root;
}
// 看 p, q 是否都在左子树中,去左子树中找最近公共祖先
if (find(root.left, p.val) && find(root.left, q.val)) {
return lowestCommonAncestor(root.left, p, q);
}
// 看 p, q 是否都在右子树中,去右子树中找最近公共祖先
if (find(root.right, p.val) && find(root.right, q.val)) {
return lowestCommonAncestor(root.right, p, q);
}
// 如果都不满足条件,说明 p, q 分别在左右子树,root 就是最近公共祖先
return root;
}
// 前序遍历
private boolean find(TreeNode root, int val) {
if (root == null) {
return false;
}
if (root.val == val) {
return true;
}
return find(root.left, val) || find(root.right, val);
}
}
简洁写法:
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if (root == null || p.val == root.val || q.val == root.val) {
return root;
}
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
if (left == null) {
return right;
}
if (right == null) {
return left;
}
return root;
}
}
6. 从有序数组中构造二叉查找树
Leetcode (opens new window)/ 力扣
// 中序遍历,以数组的中间元素作为根节点
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
return dfs(nums, 0, nums.length - 1);
}
public TreeNode dfs(int[] nums, int low, int high) {
if (low > high) {
return null;
}
// 不用 (low + high) /2 避免溢出
int mid = low + ((high - low) >> 1);
TreeNode root = new TreeNode(nums[mid]);
root.left = dfs(nums, low, mid - 1);
root.right = dfs(nums, mid + 1, high);
return root;
}
}
7. 根据有序链表构造平衡的二叉查找树
Leetcode (opens new window)/ 力扣
class Solution {
public TreeNode sortedListToBST(ListNode head) {
if (head == null) {
return null;
} else if (head.next == null) {
return new TreeNode(head.val);
}
ListNode pre = head;
ListNode p = pre.next;
ListNode q = p.next;
// 找到链表的中点 p
while(q != null && q.next != null){
pre = pre.next;
p = pre.next;
q = q.next.next;
}
// 将中点左边的链表分开
pre.next = null;
TreeNode root = new TreeNode(p.val);
root.left = sortedListToBST(head);
root.right = sortedListToBST(p.next);
return root;
}
}
8、两数之和 IV - 输入 BST
Leetcode (opens new window)/ 力扣
class Solution {
public boolean findTarget(TreeNode root, int k) {
if (root == null) {
return false;
}
List<Integer> list = new ArrayList<>();
inOrder(root, list);
// 首索引
int low = 0;
// 尾索引
int high = list.size() - 1;
// list 中的元素是有序的
while (low < high) {
if (list.get(low) + list.get(high) == k) {
return true;
// 说明不够大,low 得前移一位(有序)
} else if (list.get(low) + list.get(high) < k) {
low++;
// 说明超过范围了,high 得后移一位(有序)
} else {
high--;
}
}
return false;
}
// 因为中序遍历的元素是有序的,维护一个 List 集合
public void inOrder(TreeNode root, List<Integer> list) {
if (root == null) {
return ;
}
inOrder(root.left, list);
list.add(root.val);
inOrder(root.right, list);
}
}
9. 在二叉查找树中查找两个节点之差的最小绝对值
Leetcode (opens new window)/ 力扣
class Solution {
private Integer pre;
private Integer result;
public int getMinimumDifference(TreeNode root) {
result = Integer.MAX_VALUE;
pre = -1;
dfs(root);
return result;
}
// 中序遍历,相邻节点为最小值
public void dfs(TreeNode root) {
if (root == null) {
return ;
}
dfs(root.left);
if (pre == -1) {
pre = root.val;
} else {
result = Math.min(result, root.val - pre);
pre = root.val;
}
dfs(root.right);
}
}
10. 寻找二叉查找树中出现次数最多的值
Leetcode (opens new window)/ 力扣
class Solution {
// 当前值的个数
private int curCount = 1;
// 最多值的个数
private int maxCount = 1;
private TreeNode pre = null;
public int[] findMode(TreeNode root) {
List<Integer> result = new ArrayList<>();
dfs(root, result);
// 将集合转换成数组
int[] res = new int[result.size()];
for (int i = 0; i < result.size(); i++) {
res[i] = result.get(i);
}
return res;
}
// 深度优先遍历
public void dfs(TreeNode root, List<Integer> result) {
if (root == null) {
return ;
}
dfs(root.left, result);
if (pre != null) {
// 如果相等就累加当前值的个数
if (pre.val == root.val) {
curCount++;
// 不相等说明值已经不同,将累加值重置为 1
} else {
curCount = 1;
}
}
// 如果当前值的个数大于原先值的个数,说明这个才是众数
// 清空集合,将当前值加入到集合中,同时改变 maxCount
if (curCount > maxCount) {
maxCount = curCount;
result.clear();
result.add(root.val);
// 相等的话说明这两个都是众数
} else if (curCount == maxCount) {
result.add(root.val);
}
pre = root;
dfs(root.right, result);
}
}
Trie
Trie
,又称前缀树或字典树,用于判断字符串是否存在或者是否具有某种字符串前缀。
1. 实现一个 Trie
Leetcode (opens new window)/ 力扣
class Trie {
// 根节点
private Node root;
private class Node {
// 孩子节点,因为有 26 个字母,所以初始化 26 个空间
Node[] childs = new Node[26];
// 默认值为 false
boolean isLeaf;
}
public Trie() {
root = new Node();
}
// 插入方法
public void insert(String word) {
Node p = root;
for (int i = 0; i < word.length(); i++) {
int u = word.charAt(i) - 'a';
// 如果为空
if (p.childs[u] == null) {
// 就初始化空间
p.childs[u] = new Node();
}
p = p.childs[u];
}
p.isLeaf = true;
}
// 查找方法
public boolean search(String word) {
Node p = root;
for (int i = 0; i < word.length(); i++) {
int u = word.charAt(i) - 'a';
// 如果空间为 null,说明没有值,返回 false
if (p.childs[u] == null) {
return false;
}
p = p.childs[u];
}
// 如果都跑完了,还需要判断是否是最后一个节点
return p.isLeaf;
}
// 是否是已经插入的字符串的前缀之一
public boolean startsWith(String prefix) {
Node p = root;
for (int i = 0; i < prefix.length(); i++) {
int u = prefix.charAt(i) - 'a';
// 如果为空,说明没有值,直接返回 false
if (p.childs[u] == null) {
return false;
}
p = p.childs[u];
}
return true;
}
}
2. 实现一个 Trie,用来求前缀和
Leetcode (opens new window)/ 力扣
class MapSum {
// 根节点
private Node root;
private class Node {
// 子节点
Node[] childs = new Node[26];
// 值
int val;
}
// 初始化s
public MapSum() {
root = new Node();
}
// 插入方法
public void insert(String key, int val) {
Node p = root;
for (int i = 0; i < key.length(); i++) {
int u = key.charAt(i) - 'a';
if (p.childs[u] == null) {
p.childs[u] = new Node();
}
p = p.childs[u];
}
p.val = val;
}
// 求前缀和方法
public int sum(String prefix) {
Node p = root;
for (int i = 0; i < prefix.length(); i++) {
int u = prefix.charAt(i) - 'a';
// 没有这个键
if (p.childs[u] == null) {
return 0;
}
p = p.childs[u];
}
return dfs(p);
}
public int dfs(Node root) {
if (root == null) {
return 0;
}
int result = 0;
for (int i = 0; i < 26; i++) {
if (root.childs[i] != null) {
result += dfs(root.childs[i]);
}
}
return result + root.val;
}
}