1.题目
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
翻译:给定一个二分搜索树和一个目标数字,如果在树中有两个元素的值相加等于目标数字就返回true。
2.思路
思路1:最先想到的算法,先把二叉树转成一个有序数组,然后问题转化为“在有序数组中寻找相加等于target的两个数”。在数组中,可以用“双指针”思想来找,一个指针从头开始,一个指针从尾开始。相加大于target,右指针左移,相加小于target,左指针右移。前提,左指针右指针不能相遇。
思路2:直接在树上进行处理,与数组上不同的是,在树上从中间开始找,向外侧延伸。一个递归算法,如果两节点的和小于target,继续看第一个节点的right和第二个节点的和,以及第一个节点和第二个节点right的和;如果两节点的和大于target,看第一个节点的left和第二个节点的和,以及第一个节点和第二个节点left的和。
3.算法
算法1
private List<Integer> list;
public boolean findTarget(TreeNode root, int k) {
list = new ArrayList<Integer>();
travel(root);
int len= list.size();
if(len<=1) return false;
int[] res = new int[len];
for(int i =0;i<len;i++){
res[i]= list.get(i);
}
// Arrays.sort(res);
int i=0;
int j=len-1;
while(i<j){
if(res[i]+res[j]<k)i++;
else if(res[i]+res[j]>k)j--;
else if(res[i]+res[j]==k)return true;
}
return false;
}
private void travel(TreeNode treenode){
if(treenode == null)return ;
if(treenode.left!=null) travel(treenode.left);
list.add(treenode.val);
if(treenode.right!=null) travel(treenode.right);
}
算法2
public boolean findTarget(TreeNode root, int k) {
return addTwoNode(root,root,k);
}
private boolean addTwoNode(TreeNode left,TreeNode right,int k){
if(left==null||right==null)return false;
if((left.val+right.val==k)&&(left.val!=right.val))return true;
else if(left.val+right.val<=k)
return addTwoNode(left,right.right,k)||addTwoNode(left.right,right,k);
else if(left.val+right.val>k)
return addTwoNode(left.left,right,k)||addTwoNode(left,right.left,k);
return false;
}
4.总结
费了好大劲想出的第二个算法,结果比第一个算法还慢,笑哭。第一种方法比较稳妥,它可以处理(一堆数中有两个数相等的情况),第二种算法是属于钻了“没有两个值相等的数”的空子,不然在树中比较难判断一个节点有没有被重复利用。