Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions algorithms/arrays/two_sum/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,74 @@ Output: [1,2]
Explanation: The sum of -1 and 0 is -1. Therefore index1 = 1, index2 = 2. We return [1, 2].
```

---

# Two Sum IV - Input Is a BST

Given the root of a binary search tree and an integer k, determine whether there are two elements in the BST whose sum
equals k. Return TRUE if such elements exist or FALSE otherwise.

## Constraints

- The number of nodes in the tree is in the range [1, 10^3].
- 10^3 <= Node.data <= 10^3
- root is guaranteed to be a valid binary search tree.
- 10^4 <= k <= 10^4

## Examples

![Example 1](./images/examples/two_sum_4_input_is_bst_example_1.png)
![Example 2](./images/examples/two_sum_4_input_is_bst_example_2.png)
![Example 3](./images/examples/two_sum_4_input_is_bst_example_3.png)

## Solution

The core intuition behind solving this problem is to use a set to track values encountered during a breadth-first search
of the binary search tree (BST). We calculate each node’s complement (i.e., the difference between k and the node’s value)
and check if this complement already exists in the set. If it does, it means there is another node in the BST whose value,
when added to the current node’s value, equals k, and we return TRUE. Otherwise, we add the current node’s value to the set.
If no two nodes with the required sum are found by the end of the traversal, we return FALSE.

Using the intuition above, the solution can be implemented as follows:

1. If the BST is empty, return FALSE.
2. Define a set, seen, to store the visited node values.
3. Define a queue, q, to perform the level-order traversal of the BST.
- Enqueue root to q to start the traversal from the root node.
4. While the queue is not empty, repeat the following steps:
- Dequeue a node from the front of the queue.
- Check if the complement of the current node’s value exists in the seen set. If yes, return TRUE.
- Add the current node’s value to the seen set.
- Enqueue its left and right children.
5. If no two nodes with the required sum are found, return FALSE.

Let’s look at the following illustration to get a better understanding of the solution:

![Solution 1](./images/solutions/two_sum_4_input_is_bst_solution_1.png)
![Solution 2](./images/solutions/two_sum_4_input_is_bst_solution_2.png)
![Solution 3](./images/solutions/two_sum_4_input_is_bst_solution_3.png)
![Solution 4](./images/solutions/two_sum_4_input_is_bst_solution_4.png)
![Solution 5](./images/solutions/two_sum_4_input_is_bst_solution_5.png)
![Solution 6](./images/solutions/two_sum_4_input_is_bst_solution_6.png)
![Solution 7](./images/solutions/two_sum_4_input_is_bst_solution_7.png)
![Solution 8](./images/solutions/two_sum_4_input_is_bst_solution_8.png)
![Solution 9](./images/solutions/two_sum_4_input_is_bst_solution_9.png)
![Solution 10](./images/solutions/two_sum_4_input_is_bst_solution_10.png)
![Solution 11](./images/solutions/two_sum_4_input_is_bst_solution_11.png)
![Solution 12](./images/solutions/two_sum_4_input_is_bst_solution_12.png)
![Solution 13](./images/solutions/two_sum_4_input_is_bst_solution_13.png)
![Solution 14](./images/solutions/two_sum_4_input_is_bst_solution_14.png)

### Time Complexity

The algorithm’s time complexity is O(n), where n is the number of nodes in the binary search tree.

### Space Complexity

The algorithm’s space complexity is O(n), as the size of the set can grow up to at most n.

---

## Related Topics

- Array
Expand Down
45 changes: 44 additions & 1 deletion algorithms/arrays/two_sum/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from typing import List
from typing import List, Deque, Set
from collections import deque
from datastructures.trees.binary.node import BinaryTreeNode


def two_sum(numbers: List[int], target: int) -> List[int]:
Expand Down Expand Up @@ -59,3 +61,44 @@ def two_sum_with_pointers(numbers: List[int], target: int) -> List[int]:
first_pointer += 1
else:
last_pointer -= 1
return []


def two_sum_find_target(root: BinaryTreeNode, k: int) -> bool:
"""
Checks if two nodes in the binary search tree add up to the given target number

Args:
root (BinaryTreeNode): root of the binary search tree
k (int): target number
Returns:
bool: True if there are two nodes in the binary search tree that add up to the target, False otherwise
"""
if not root:
return False

# store the seen values so far during the traversal
seen: Set[int] = set()

# Keep track of visited nodes, we start with the root node. We use a FIFO queue here
queue: Deque[BinaryTreeNode] = deque()
queue.append(root)

while queue:
# dequeue the first node, the front of the queue.
curr = queue.popleft()

if curr:
# check if the complement of this node's value exists in the values we have seen so far
if (k - curr.data) in seen:
return True

# if not, add the value
seen.add(curr.data)

# enqueue the left and right children of the current node
queue.append(curr.left)
queue.append(curr.right)

# if we reach here, we have not found two nodes that add up to the target
return False
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
83 changes: 41 additions & 42 deletions algorithms/arrays/two_sum/test_two_sum.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,55 @@
import unittest
from . import two_sum, two_sum_with_pointers
from typing import List
from parameterized import parameterized
from datastructures.trees.binary.node import BinaryTreeNode
from algorithms.arrays.two_sum import (
two_sum,
two_sum_with_pointers,
two_sum_find_target,
)

TWO_SUM_TEST_CASES = [
([2, 7, 11, 15], 9, [1, 2]),
([2, 3, 4], 6, [1, 3]),
([-1, 0], -1, [1, 2]),
]

TWO_SUM_TWO_POINTERS_TEST_CASES = [
([2, 7, 11, 15], 9, [0, 1]),
([2, 3, 4], 6, [0, 2]),
([-1, 0], -1, [0, 1]),
]

TWO_SUM_INPUT_BST_TEST_CASES = [
([7, 3, 13, 2, 5, None, 19], 18, True),
([8, 4, None, 0, None, -11], 4, True),
([1, None, 2, None, 3, None, 4], 5, True),
([900], 900, False),
([0, -200, 500, -300, -100, 400, 600], 500, True),
]


class TwoSumTestCase(unittest.TestCase):
def test_1(self):
"""numbers = [2,7,11,15], target = 9"""
numbers = [2, 7, 11, 15]
target = 9
expected = [1, 2]
@parameterized.expand(TWO_SUM_TEST_CASES)
def test_two_sum(self, numbers: List[int], target: int, expected: List[int]):
actual = two_sum(numbers, target)
self.assertEqual(expected, actual)

def test_2(self):
"""numbers = [2,3,4], target = 6"""
numbers = [2, 3, 4]
target = 6
expected = [1, 3]
actual = two_sum(numbers, target)
self.assertEqual(expected, actual)

def test_3(self):
"""numbers = [-1,0], target = -1"""
numbers = [-1, 0]
target = -1
expected = [1, 2]
actual = two_sum(numbers, target)
self.assertEqual(expected, actual)


class TwoSumWithPointersTestCase(unittest.TestCase):
def test_1(self):
"""numbers = [2,7,11,15], target = 9"""
numbers = [2, 7, 11, 15]
target = 9
expected = [0, 1]
@parameterized.expand(TWO_SUM_TWO_POINTERS_TEST_CASES)
def test_two_sum_with_two_pointers(
self, numbers: List[int], target: int, expected: List[int]
):
actual = two_sum_with_pointers(numbers, target)
self.assertEqual(expected, actual)

def test_2(self):
"""numbers = [2,3,4], target = 6"""
numbers = [2, 3, 4]
target = 6
expected = [0, 2]
actual = two_sum_with_pointers(numbers, target)
self.assertEqual(expected, actual)
@parameterized.expand(TWO_SUM_INPUT_BST_TEST_CASES)
def test_two_sum_input_bst(self, numbers: List[int], target: int, expected: bool):
root = BinaryTreeNode(numbers[0])
for data in numbers[1:]:
if data is not None:
root.insert_node(data)

def test_3(self):
"""numbers = [-1,0], target = -1"""
numbers = [-1, 0]
target = -1
expected = [0, 1]
actual = two_sum_with_pointers(numbers, target)
actual = two_sum_find_target(root, target)
self.assertEqual(expected, actual)


Expand Down
Loading