leetcode-两数之和IV-输入BST

谁说我不能喝 提交于 2020-03-01 19:12:14

 题目来自LeetCode,链接:two-sum-iv。具体描述为:
给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。

 示例1:

输入: 
    5
   / \
  3   6
 / \   \
2   4   7

Target = 9

输出: True

 示例2:

输入: 
    5
   / \
  3   6
 / \   \
2   4   7

Target = 28

输出: False

 这跟前面的两数之和以及两数之和II-输入有序数组很相似,不过输入的是BST。

 同样可以用两数之和的方法去做(直接用一个set保存target-当前数),需要遍历一次BST,每遍历一个节点就判断是否出现在set之中了,是的话返回True,否则将target-当前值加入set。

 或者可以模仿有序数组的方法,先中序遍历BST得到升序数组,然后直接用双指针方法也可以解决此问题。

 实际提交发现前面两种方法时间上并不是很有优势,所以想了想,其实在用前面第二种方法的时候,可以不用得到一个升序数组再用双指针的,完全可以在遍历过程中就用双指针的。为了实现这一点,可以参考栈形式的中序遍历:

  • 当前节点初始化为root,将其所有左节点(包括左节点的左节点,一直到叶子节点为止)和所有右节点分别入栈到左节点栈和右节点栈,可以得到left为最左节点,对应最小值,right为最右节点,对应最大值
  • 计算left和right对应节点值之和,与target对比
    • 相等,直接返回True
    • 小于,需要增大left,判断left的右节点是否存在
      • 存在,则将left的右节点的所有左节点入栈,left=此右节点的最左节点(也可以说是栈顶节点,不过为了简便可以在代码中省去出栈操作)
      • 不存在,直接left=栈顶出栈节点,也就是当前left的父节点
    • 大于,需要减少right,判断right的左节点是否存在
      • 存在,则将right的左节点的所有右左节点入栈,right=此左节点的最右节点
      • 不存在,直接right=栈顶出栈节点,也就是当前right的父节点

 本质上,上面的算法就是升序数组方法在BST中的实现,换了个数据结构罢了。

 另外,需要注意到的是以上所有方法的时间和空间复杂度均为O(N)O(N)

 JAVA版代码如下:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private TreeNode pushLeft(TreeNode leftNode, Stack<TreeNode> leftNodeStack) {
        while (leftNode.left != null) {
            leftNodeStack.push(leftNode);
            leftNode = leftNode.left;
        }
        return leftNode;
    }

    private TreeNode pushRight(TreeNode rightNode, Stack<TreeNode> rightNodeStack) {
        while (rightNode.right != null) {
            rightNodeStack.push(rightNode);
            rightNode = rightNode.right;
        }
        return rightNode;
    }
    public boolean findTarget(TreeNode root, int k) {
        Stack<TreeNode> leftNodeStack = new Stack<>();
        Stack<TreeNode> rightNodeStack = new Stack<>();
        TreeNode leftNode = pushLeft(root, leftNodeStack);
        TreeNode rightNode = pushRight(root, rightNodeStack);
        int sum2num = 0;
        while (leftNode != rightNode) {
            sum2num = leftNode.val + rightNode.val;
            if (sum2num == k) {
                return true;
            }
            else if (sum2num <  k) {
                if (leftNode.right != null) {
                    leftNode = pushLeft(leftNode.right, leftNodeStack);
                }
                else {
                    leftNode = leftNodeStack.pop();
                }
            }
            else {
                if (rightNode.left != null) {
                    rightNode = pushRight(rightNode.left, rightNodeStack);
                }
                else {
                    rightNode = rightNodeStack.pop();
                }
            }
        }
        return false;
    }
}

 提交结果如下:


 Python版代码如下:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def pushLeft(self, leftNode, leftNodeStack):
        while leftNode.left is not None:                    #将所有左节点入栈
            leftNodeStack.append(leftNode)
            leftNode = leftNode.left
        return leftNode
    
    def pushRight(self, rightNode, rightNodeStack):
        while rightNode.right is not None:                  #将所有右节点入栈
            rightNodeStack.append(rightNode)
            rightNode = rightNode.right
        return rightNode
    
    def findTarget(self, root: TreeNode, k: int) -> bool:
        leftNodeStack, rightNodeStack = [], []
        leftNode = self.pushLeft(root, leftNodeStack)
        rightNode = self.pushRight(root, rightNodeStack)
        while leftNode is not rightNode:
            sum2num = leftNode.val + rightNode.val
            if sum2num == k:                                #找到符合条件的两个节点
                return True
            elif sum2num <  k:                              #两数之和小于target,需要增大左节点
                if leftNode.right is not None:              #当前节点右节点不为空的情况将其左节点全部入栈
                    leftNode = self.pushLeft(leftNode.right, leftNodeStack)
                else:                                       #当前节点右节点为空的情况弹出当前节点的父节点
                    leftNode = leftNodeStack.pop()
            else:                                           #两数之和大于target,需要减小右节点
                if rightNode.left is not None:              #当前节点左节点不为空的情况将其右节点全部入栈
                    rightNode = self.pushRight(rightNode.left, rightNodeStack)
                else:                                       #当前节点左节点为空的情况弹出当前节点的父节点
                    rightNode = rightNodeStack.pop()
        return False

 提交结果如下:


标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!