题目:
Given a Binary Search Tree and a target number, return true if there exist two elements in the BST such that their sum is equal to the given target.
Example 1:
Input: 5 / \ 3 6 / \ \ 2 4 7 Target = 9 Output: True
Example 2:
Input: 5 / \ 3 6 / \ \ 2 4 7 Target = 28 Output: False
这道题就是把2sum中的数组换成了BST的形式,刚开始也是脑子不灵光没想到怎么做,其实最直觉的方法就是因为BST的inorder traversal是升序排列的,所以可以进行一次遍历把这棵树转换成一个数组,然后对这个数组进行普通的(2023.1.2 edit:应该是sorted的)2sum就可以了。时间复杂度是遍历树的复杂度O(n),空间也是O(n)因为要把它们都存到一个数组里。
Runtime: 2 ms, faster than 93.75% of Java online submissions for Two Sum IV - Input is a BST.
Memory Usage: 41.7 MB, less than 71.43% of Java online submissions for Two Sum IV - Input is a BST.
/**
* 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 pStart = 0;
int pEnd = nums.size() - 1;
while (pStart < pEnd) {
int sum = nums.get(pStart) + nums.get(pEnd);
if (sum > k) {
pEnd--;
} else if (sum < k) {
pStart++;
} else {
return true;
}
}
return false;
}
private void inorder(TreeNode root, List<Integer> nums) {
if (root == null) {
return;
}
inorder(root.left, nums);
nums.add(root.val);
inorder(root.right, nums);
}
}
2022.12.24
想到了能转成array,却忘了array是sorted,可以直接2 pointers做。写2 pointers的时候在动high和low的时候也忘了,需要根据sum和k的大小来选择移动谁,需要复习复习。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
List<Integer> list = new ArrayList<>();
public boolean findTarget(TreeNode root, int k) {
inorder(root);
int low = 0;
int high = list.size() - 1;
while (low < high) {
int sum = list.get(low) + list.get(high);
if (sum == k) {
return true;
} else if (sum < k) {
low++;
} else {
high--;
}
}
return false;
}
private void inorder(TreeNode root) {
if (root == null) {
return;
}
inorder(root.left);
list.add(root.val);
inorder(root.right);
}
}
上面这种方法虽然是用上了BST的性质,但实际上对这个数组access了两次,其实是可以优化的,比如一遍遍历一边把它塞进hashset里(写到这里突然意识到之前忘了哪道题用hashmap其实并不需要存key-value pair,只需要快速查找,所以直接用hashset即可)。这样的话其实就用不上BST的性质了,普通任意一棵树都可以,所以这里也有两种做法,一种是DFS,一种是BFS。
DFS的做法就是在普通的DFS函数中,如果root == null返回false说明以这个root为根的子树找不到配对的,然后继续查set中是否有可以和它配对的,有的话就直接返回true了,然后把当前的数字加入set,接下来再对root的左右子树进行DFS递归调用这个函数,如果它的左右子树中任意有一个能配对就返回true,否则返回false。(最后return的这个地方刚开始没想清楚,后面要多复习这种return方法)时间复杂度O(n),空间复杂度O(n)。
Runtime: 2 ms, faster than 93.75% of Java online submissions for Two Sum IV - Input is a BST.
Memory Usage: 41.7 MB, less than 71.43% of Java online submissions for Two Sum IV - Input is a BST.
/**
* 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) {
Set<Integer> nums = new HashSet<>();
return find (root, k, nums);
}
private boolean find(TreeNode root, int k, Set<Integer> nums) {
if (root == null) {
return false;
}
if (nums.contains(k - root.val)) {
return true;
}
nums.add(root.val);
return find(root.left, k, nums) || find(root.right, k, nums);
}
}
2022.12.24
DFS其实也挺简单,刚开始想成了inorder traversal,其实好像这么写确实是类似于inorder,先判断root,再判断左,最后判断右,但其实又跟traversal order没啥太大关系,就是一普通的递归DFS罢了。代码就看上面的吧,都一样。
BFS在这道题里并没有比DFS复杂,按照BFS的常规套路建一个queue来放root,然后while queue不为空的时候每次取出队头的node,判断这个node在set中有没有可以配对的,有的话直接true,没有的话把它放进set并且把它的左右子节点放进queue。这里被坑了一下,就是每次取队头元素的时候要判断它是不是null,因为有可能有只有一个叶子节点的情况。
Runtime: 3 ms, faster than 40.78% of Java online submissions for Two Sum IV - Input is a BST.
Memory Usage: 41.6 MB, less than 73.21% of Java online submissions for Two Sum IV - Input is a BST.
/**
* 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) {
Set<Integer> nums = new HashSet<>();
if (root == null) {
return false;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
TreeNode node = queue.remove();
if (node != null) { // attention to null in the tree
if (nums.contains(k - node.val)) {
return true;
}
nums.add(node.val);
queue.add(node.left);
queue.add(node.right);
}
}
return false;
}
}
2022.12.24
这是看到这道题以后第一个想到的方法。时隔这么久再回头做树,印象最深刻的还是经典的用queue进行BFS啊。也是顺利地就写出了代码,很感动,但是代码没有之前写的那么简洁,把left和right分开写了。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public boolean findTarget(TreeNode root, int k) {
Set<Integer> set = new HashSet<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
set.add(root.val);
while (queue.size() != 0) {
TreeNode top = queue.remove();
if (top.left != null) {
if (set.contains(k - top.left.val)) {
return true;
}
queue.add(top.left);
set.add(top.left.val);
}
if (top.right != null) {
if (set.contains(k - top.right.val)) {
return true;
}
queue.add(top.right);
set.add(top.right.val);
}
}
return false;
}
}