给定一个二叉树 根节点 root ,树的每个节点的值要么是 0,要么是 1。请剪除该二叉树中所有节点的值为 0 的子树。
节点 node 的子树为 node 本身,以及所有 node 的后代。
class Solution {
public TreeNode pruneTree(TreeNode root) {
return afterOrder(root);
}
public TreeNode afterOrder(TreeNode node) {
if (node == null) {
return null;
}
node.left = afterOrder(node.left);
node.right = afterOrder(node.right);
if (node.val == 0 && node.left == null && node.right == null) {
node = null;
}
return node;
}
}
剑指 Offer II 049. 从根节点到叶节点的路径数字之和
给定一个二叉树的根节点 root ,树中每个节点都存放有一个 0 到 9 之间的数字。
每条从根节点到叶节点的路径都代表一个数字:
例如,从根节点到叶节点的路径 1 -> 2 -> 3 表示数字 123 。
计算从根节点到叶节点生成的 所有数字之和 。
叶节点 是指没有子节点的节点。
class Solution {
public int sumNumbers(TreeNode root) {
return dfs(root, 0);
}
public int dfs(TreeNode node, int sum) {
if (node == null) {
return 0;
}
sum = sum * 10 + node.val;
if (node.left == null && node.right == null) {
return sum;
}
return dfs(node.left, sum) + dfs(node.right, sum);
}
}
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
class Solution {
public int pathSum(TreeNode root, int targetSum) {
if (root == null) {
return 0;
}
return dfs(root, targetSum) + pathSum(root.left, targetSum) + pathSum(root.right, targetSum);
}
public int dfs(TreeNode node, int targetSum) {
if (node == null) {
return 0;
}
int ret = 0;
if (targetSum - node.val == 0) {
ret++;
}
ret += dfs(node.left, targetSum - node.val);
ret += dfs(node.right, targetSum - node.val);
return ret;
}
}
给你一棵二叉搜索树,请 按中序遍历 将其重新排列为一棵递增顺序搜索树,使树中最左边的节点成为树的根节点,并且每个节点没有左子节点,只有一个右子节点。
class Solution {
TreeNode temp;
public TreeNode increasingBST(TreeNode root) {
TreeNode t = new TreeNode(-1);
temp = t;
inOrder(root);
return t.right;
}
public void inOrder(TreeNode node) {
if (node == null) {
return;
}
inOrder(node.left);
temp.right = node;
node.left = null;
temp = node;
inOrder(node.right);
}
}
给定一棵二叉搜索树和其中的一个节点 p ,找到该节点在树中的中序后继。如果节点没有中序后继,请返回 null 。
节点 p 的后继是值比 p.val 大的节点中键值最小的节点,即按中序遍历的顺序节点 p 的下一个节点。
class Solution {
public TreeNode inorderSuccessor(TreeNode root, TreeNode p) {
TreeNode t = root, ret = null;
while (t != null) {
if (t.val <= p.val) {
t = t.right;
} else {
ret = t;
t = t.left;
}
}
return ret;
}
}
给定一个二叉搜索树,请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。
提醒一下,二叉搜索树满足下列约束条件:
节点的左子树仅包含键 小于 节点键的节点。
节点的右子树仅包含键 大于 节点键的节点。
左右子树也必须是二叉搜索树。
class Solution {
int sum = 0;
public TreeNode convertBST(TreeNode root) {
dfs(root);
return root;
}
public void dfs(TreeNode node) {
if (node == null) {
return;
}
dfs(node.right);
sum = sum + node.val;
node.val = sum;
dfs(node.left);
}
}
实现一个二叉搜索树迭代器类BSTIterator ,表示一个按中序遍历二叉搜索树(BST)的迭代器:
BSTIterator(TreeNode root) 初始化 BSTIterator 类的一个对象。BST 的根节点 root 会作为构造函数的一部分给出。指针应初始化为一个不存在于 BST 中的数字,且该数字小于 BST 中的任何元素。
boolean hasNext() 如果向指针右侧遍历存在数字,则返回 true ;否则返回 false 。
int next()将指针向右移动,然后返回指针处的数字。
注意,指针初始化为一个不存在于 BST 中的数字,所以对 next() 的首次调用将返回 BST 中的最小元素。
可以假设 next() 调用总是有效的,也就是说,当调用 next() 时,BST 的中序遍历中至少存在一个下一个数字。
class BSTIterator {
int idx;
List<Integer> list;
public BSTIterator(TreeNode root) {
idx = 0;
list = new ArrayList<>();
inorder(root);
}
public void inorder(TreeNode node) {
if (node == null) {
return;
}
inorder(node.left);
list.add(node.val);
inorder(node.right);
}
public int next() {
int ret = list.get(idx);
idx++;
return ret;
}
public boolean hasNext() {
return idx < list.size();
}
}
给定一个二叉搜索树的 根节点 root
和一个整数 k
, 请判断该二叉搜索树中是否存在两个节点它们的值之和等于 k
。假设二叉搜索树中节点的值均唯一。
class Solution {
public boolean findTarget(TreeNode root, int k) {
Set<Integer> set = new HashSet<>();
TreeNode current = root;
Stack<TreeNode> stack = new Stack<>();
while (current != null || !stack.isEmpty()) {
while(current != null) {
stack.push(current);
current = current.left;
}
TreeNode t = stack.pop();
if (set.contains(k - t.val)) {
return true;
}
set.add(t.val);
current = t.right;
}
return false;
}
}
剑指 Offer II 057. 值和下标之差都在给定的范围内
给你一个整数数组 nums 和两个整数 k 和 t 。请你判断是否存在 两个不同下标 i 和 j,使得 abs(nums[i] - nums[j]) <= t ,同时又满足 abs(i - j) <= k 。
如果存在则返回 true,不存在返回 false。
class Solution {
public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
TreeSet<Long> set = new TreeSet<>();
for (int i = 0; i < nums.length; i++) {
Long ceiling = set.ceiling((long)nums[i] - (long)t);
if (ceiling != null && ceiling <= (long)nums[i] + (long)t) {
return true;
}
set.add((long)nums[i]);
if (i >= k) {
set.remove((long)nums[i - k]);
}
}
return false;
}
}
请实现一个 MyCalendar 类来存放你的日程安排。如果要添加的时间内没有其他安排,则可以存储这个新的日程安排。
MyCalendar 有一个 book(int start, int end)方法。它意味着在 start 到 end 时间内增加一个日程安排,注意,这里的时间是半开区间,即 [start, end), 实数 x 的范围为, start <= x < end。
当两个日程安排有一些时间上的交叉时(例如两个日程安排都在同一时间内),就会产生重复预订。
每次调用 MyCalendar.book方法时,如果可以将日程安排成功添加到日历中而不会导致重复预订,返回 true。否则,返回 false 并且不要将该日程安排添加到日历中。
请按照以下步骤调用 MyCalendar 类: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)
class MyCalendar {
TreeMap<Integer, Integer> map;
public MyCalendar() {
map = new TreeMap<>();
}
public boolean book(int start, int end) {
Map.Entry<Integer, Integer> event = map.ceilingEntry(start);
if (event != null && event.getKey() < end) {
return false;
}
event = map.floorEntry(start);
if (event != null && event.getValue() > start) {
return false;
}
map.put(start, end);
return true;
}
}