Skip to content

Commit

Permalink
Implemented 'Closest Nodes Queries in a Binary Search Tree' challenge
Browse files Browse the repository at this point in the history
  • Loading branch information
wibosco committed Feb 24, 2024
1 parent c1c7c8f commit 0568edd
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ struct BinarySearch {
//If `values[mid]` matches `target` then we have found our target and can return; if `values[mid]` does not match `target`
//then we half the search space by moving either `left` to the right (if `values[mid]` was smaller than `target`) or moving
//`right` to the left (if `values[mid]` was larger than `target`). We can reduce the search space like this because `values`
//sorted so we know that if `values[mid]` was smaller than `target` then any index less than `mid` will contain an even
//is sorted so we know that if `values[mid]` was smaller than `target` then any index less than `mid` will contain an even
//smaller value than `values[mid]` so searching those other indexes would be pointless (the opposite is true for reducing
//the search space to the right of `mid`).
//
Expand Down
8 changes: 8 additions & 0 deletions LeetCode/LeetCode.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,8 @@
4335FB112B88F04500416BB6 /* ValidateBinaryTreeNodesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4335FB102B88F04500416BB6 /* ValidateBinaryTreeNodesTests.swift */; };
4335FB132B8944D500416BB6 /* CheckIfNAndItsDoubleExist.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4335FB122B8944D500416BB6 /* CheckIfNAndItsDoubleExist.swift */; };
4335FB152B89455100416BB6 /* CheckIfNAndItsDoubleExistTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4335FB142B89455100416BB6 /* CheckIfNAndItsDoubleExistTests.swift */; };
4335FB172B894E9D00416BB6 /* ClosestNodesQueriesInABinarySearchTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4335FB162B894E9D00416BB6 /* ClosestNodesQueriesInABinarySearchTree.swift */; };
4335FB192B894ED700416BB6 /* ClosestNodesQueriesInABinarySearchTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4335FB182B894ED700416BB6 /* ClosestNodesQueriesInABinarySearchTreeTests.swift */; };
4336E5542B236C520060A25D /* MakeCostsOfPathsEqualInABinaryTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4336E5532B236C520060A25D /* MakeCostsOfPathsEqualInABinaryTree.swift */; };
4336E5562B236C810060A25D /* MakeCostsOfPathsEqualInABinaryTreeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4336E5552B236C810060A25D /* MakeCostsOfPathsEqualInABinaryTreeTests.swift */; };
4336E5582B23CCA50060A25D /* EvenOddTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4336E5572B23CCA50060A25D /* EvenOddTree.swift */; };
Expand Down Expand Up @@ -1547,6 +1549,8 @@
4335FB102B88F04500416BB6 /* ValidateBinaryTreeNodesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidateBinaryTreeNodesTests.swift; sourceTree = "<group>"; };
4335FB122B8944D500416BB6 /* CheckIfNAndItsDoubleExist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckIfNAndItsDoubleExist.swift; sourceTree = "<group>"; };
4335FB142B89455100416BB6 /* CheckIfNAndItsDoubleExistTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckIfNAndItsDoubleExistTests.swift; sourceTree = "<group>"; };
4335FB162B894E9D00416BB6 /* ClosestNodesQueriesInABinarySearchTree.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClosestNodesQueriesInABinarySearchTree.swift; sourceTree = "<group>"; };
4335FB182B894ED700416BB6 /* ClosestNodesQueriesInABinarySearchTreeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClosestNodesQueriesInABinarySearchTreeTests.swift; sourceTree = "<group>"; };
4336E5532B236C520060A25D /* MakeCostsOfPathsEqualInABinaryTree.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeCostsOfPathsEqualInABinaryTree.swift; sourceTree = "<group>"; };
4336E5552B236C810060A25D /* MakeCostsOfPathsEqualInABinaryTreeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MakeCostsOfPathsEqualInABinaryTreeTests.swift; sourceTree = "<group>"; };
4336E5572B23CCA50060A25D /* EvenOddTree.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EvenOddTree.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1972,6 +1976,7 @@
3D5C90B827A7F7620035C399 /* CloneGraph.swift */,
3D5C90E227A7F7620035C399 /* ClosestBinarySearchTreeValue.swift */,
43643B1C2B0E3E7800B9D711 /* ClosestLeafInABinaryTree.swift */,
4335FB162B894E9D00416BB6 /* ClosestNodesQueriesInABinarySearchTree.swift */,
433E55BF29DF145E00974B73 /* CoinChange .swift */,
3D46242C27E359F800A888C1 /* Combinations.swift */,
3D30553427C631AE00294BC7 /* CombinationSum.swift */,
Expand Down Expand Up @@ -2428,6 +2433,7 @@
3D5C922D27A7F76B0035C399 /* CloneGraphTests.swift */,
3D5C928827A7F76C0035C399 /* ClosestBinarySearchTreeValueTests.swift */,
43643B1E2B0E3EAD00B9D711 /* ClosestLeafInABinaryTreeTests.swift */,
4335FB182B894ED700416BB6 /* ClosestNodesQueriesInABinarySearchTreeTests.swift */,
433E55C129DF14D600974B73 /* CoinChangeTests.swift */,
3D46242E27E35A4100A888C1 /* CombinationsTests.swift */,
3D193ABC27C78D9600E49F08 /* CombinationSumIIITests.swift */,
Expand Down Expand Up @@ -2944,6 +2950,7 @@
4347A1C429E2158300501CEE /* ContainsDuplicate.swift in Sources */,
43EE0BDA2A55A5CD003D23E0 /* PartitionLabels.swift in Sources */,
43F240692A67067200FB5964 /* BoatsToSavePeople.swift in Sources */,
4335FB172B894E9D00416BB6 /* ClosestNodesQueriesInABinarySearchTree.swift in Sources */,
43C8CB4F2A5426F200FAA411 /* HandOfStraights.swift in Sources */,
43EF3C212AFB7FB60085445E /* DetermineIfACellIsReachableAtAGivenTime.swift in Sources */,
431F3D582A634CAB00500C0E /* NumberOfZeroFilledSubarrays.swift in Sources */,
Expand Down Expand Up @@ -3434,6 +3441,7 @@
3D5C932027A7F76C0035C399 /* SortListTests.swift in Sources */,
3D1D0C85280645C7006DA350 /* GameOfLifeTests.swift in Sources */,
3D5C92B827A7F76C0035C399 /* UniqueBinarySearchTreesTests.swift in Sources */,
4335FB192B894ED700416BB6 /* ClosestNodesQueriesInABinarySearchTreeTests.swift in Sources */,
3D5C92D427A7F76C0035C399 /* NumberOfProvincesTests.swift in Sources */,
431E35732AF15A1F0019BB1F /* NumberOfClosedIslandsTests.swift in Sources */,
433953052B041833009F067C /* SumOfNodesWithEvenValuedGrandparentTests.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ struct CheckIfNAndItsDoubleExist {
func checkIfExist(_ arr: [Int]) -> Bool {
var seen = Set<Int>()

for (index, value) in arr.enumerated() {
for value in arr {
//have we seen double this value already
if seen.contains((value * 2)) {
return true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//
// ClosestNodesQueriesInABinarySearchTree.swift
// LeetCode
//
// Created by William Boles on 23/02/2024.
//

import Foundation

//https://leetcode.com/problems/closest-nodes-queries-in-a-binary-search-tree/
struct ClosestNodesQueriesInABinarySearchTree {

//Time: O(
//Space: O(
//binary tree
//binary search tree
//binary search
//in-order
//DFS
//recursive
//inout
//array
//
//Solution Description:
//As this is binary search tree, we know that an in-order traversal will produce a sorted array. With a sorted array we can
//then perform two binary searches to find both the upper and lower bounds of each query item.
func closestNodes(_ root: TreeNode?, _ queries: [Int]) -> [[Int]] {
guard let root = root else {
return [[Int]]()
}

var values = [Int]()
inorder(root, &values)

var result = [[Int]]()

for query in queries {
let min = findMax(values, query)
let max = findMin(values, query)

result.append([min, max])
}

return result
}

private func inorder(_ root: TreeNode?, _ order: inout [Int]) {
guard let root = root else {
return
}

inorder(root.left, &order)
order.append(root.val)
inorder(root.right, &order)
}

private func findMax(_ values: [Int], _ target: Int) -> Int {
var left = 0
var right = values.count - 1

var result = -1

while left <= right {
let mid = left + (right - left) / 2 //to avoid overflow

if values[mid] <= target { //find the upper bounds that is less than or equal to target
result = values[mid] //we know that values[mid] is a valid result so store it and check again
left = mid + 1
} else {
right = mid - 1
}
}

return result
}

private func findMin(_ values: [Int], _ target: Int) -> Int {
var left = 0
var right = values.count - 1

var result = -1

while left <= right {
let mid = left + (right - left) / 2 //to avoid overflow

if values[mid] >= target { //find the lower bounds that is greater than or equal to target
result = values[mid] //we know that values[mid] is a valid result so store it anad check again
right = mid - 1
} else {
left = mid + 1
}
}

return result
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
//
// ClosestNodesQueriesInABinarySearchTreeTests.swift
// LeetCodeTests
//
// Created by William Boles on 23/02/2024.
//

import XCTest

@testable import LeetCode

final class ClosestNodesQueriesInABinarySearchTreeTests: XCTestCase {

//MARK: - Tests

func test_A() {
let data = [6,2,13,1,4,9,15,nil,nil,nil,nil,nil,nil,14]
let queries = [2,5,16]

let root = TreeNode.deserialize(data)

let result = ClosestNodesQueriesInABinarySearchTree().closestNodes(root, queries)

XCTAssertEqual(result, [[2,2],[4,6],[15,-1]])
}

func test_B() {
let data = [4,nil,9]
let queries = [3]

let root = TreeNode.deserialize(data)

let result = ClosestNodesQueriesInABinarySearchTree().closestNodes(root, queries)

XCTAssertEqual(result, [[-1,4]])
}

func test_C() {
let data = [16,8,18,1,12,nil,20,nil,2,9,nil,nil,nil,nil,7]
let queries = [8,14,285508,6]

let root = TreeNode.deserialize(data)

let result = ClosestNodesQueriesInABinarySearchTree().closestNodes(root, queries)

XCTAssertEqual(result, [[8,8],[12,16],[20,-1],[2,7]])
}

func test_D() {
let data = [16,14,nil,4,15,1]
let queries = [10,6,2,9]

let root = TreeNode.deserialize(data)

let result = ClosestNodesQueriesInABinarySearchTree().closestNodes(root, queries)

XCTAssertEqual(result, [[4,14],[4,14],[1,4],[4,14]])
}

func test_E() {
let data = [9,6,14,nil,nil,13,20,12]
let queries = [19,10,9,17,19,6,10,19,13,6]

let root = TreeNode.deserialize(data)

let result = ClosestNodesQueriesInABinarySearchTree().closestNodes(root, queries)

XCTAssertEqual(result, [[14,20],[9,12],[9,9],[14,20],[14,20],[6,6],[9,12],[14,20],[13,13],[6,6]])
}
}

0 comments on commit 0568edd

Please sign in to comment.