diff --git a/Sources/Geometry/OverlappingRectangles.swift b/Sources/Geometry/OverlappingRectangles.swift new file mode 100644 index 0000000..6e3b6d6 --- /dev/null +++ b/Sources/Geometry/OverlappingRectangles.swift @@ -0,0 +1,137 @@ +// +// OverlappingRectangles.swift +// +// +// Created by Mohshinsha Shahmadar on 2024-12-10. +// + +import Foundation +/** + ### Problem Statement: + Write a function that takes two rectangles as inputs and determines if they overlap. Each rectangle is represented by its bottom-left corner (x1, y1) and top-right corner (x2, y2). The function should return `true` if the rectangles overlap and `false` otherwise. + + ### Input: + - Each rectangle is represented by a tuple of four integers: `(x1, y1, x2, y2)`, where: + - `(x1, y1)` represents the coordinates of the bottom-left corner. + - `(x2, y2)` represents the coordinates of the top-right corner. + + ### Output: + - Return `true` if the two rectangles overlap, `false` otherwise. + + ### Constraints: + - You may assume that the edges of the rectangles are aligned with the X and Y axes (i.e., they are not rotated). + - Rectangles that share an edge or a corner are **not** considered to be overlapping. + + ### Test Cases: + + 1. **Test Case 1: Partially Overlapping** + ```swift + Input: rect1 = (0, 0, 4, 4), rect2 = (2, 2, 6, 6) + Output: true + ``` + + 2. **Test Case 2: Non-Overlapping** + ```swift + Input: rect1 = (0, 0, 2, 2), rect2 = (3, 3, 5, 5) + Output: false + ``` + + 3. **Test Case 3: One Rectangle Inside Another** + ```swift + Input: rect1 = (0, 0, 6, 6), rect2 = (2, 2, 4, 4) + Output: true + ``` + + 4. **Test Case 4: Touching at Edge (Non-Overlapping)** + ```swift + Input: rect1 = (0, 0, 4, 4), rect2 = (4, 0, 6, 3) + Output: true + ``` + + 5. **Test Case 5: Touching at Corner (Non-Overlapping)** + ```swift + Input: rect1 = (0, 0, 3, 3), rect2 = (3, 3, 6, 6) + Output: true + ``` + */ +func checkIfRectanglesIntersectingEachOther(with input: [[Int]]) -> Bool { + let rectangles: [Rectangle] = input.map(Rectangle.init) + guard !rectangles.isEmpty else { return false } + + var resultRectangle = rectangles[0] + + for i in 1.. Rectangle.OverlappingType { + switch renderedType { + case .horizotalLine, .verticalLine: return .touchingEdge + case .rectangle: return .intersecting + case .point: return .touchingPoint + case .invalid: return .farFromEachOther + } +} + +fileprivate struct Rectangle { + enum OverlappingType: String { + case overlapping + case intersecting + case touchingEdge + case touchingPoint + case farFromEachOther + } + + enum RenderedType { + case horizotalLine + case verticalLine + case rectangle + case point + case invalid + } + + init(bottomLeft: (x: Int, y: Int), topRight: (x: Int, y: Int)) { + self.bottomLeft = bottomLeft + self.topRight = topRight + } + + let bottomLeft: (x: Int, y: Int) + let topRight: (x: Int, y: Int) + + init(_ elements: [Int]) { + guard elements.count == 4 else { fatalError("Invaldi Rect Data Provided") } + bottomLeft = (x: elements[0], y: elements[1]) + topRight = (x: elements[2], y: elements[3]) + } + + var renderingType: RenderedType { + guard bottomLeft.x <= topRight.x && bottomLeft.y <= topRight.y else { return .invalid } + if bottomLeft.x == topRight.x && bottomLeft.y < topRight.y { + return .verticalLine + } else if bottomLeft.x < topRight.x && bottomLeft.y == topRight.y { + return .horizotalLine + } else if bottomLeft.x == topRight.x && bottomLeft.y == topRight.y { + return .point + } else if bottomLeft.x < topRight.x && bottomLeft.y < topRight.y { + return .rectangle + } else { + return .invalid + } + } + + func intersect(with rect2: Rectangle) -> Rectangle { + let rect1 = self + return Rectangle( + bottomLeft: ( + x: max(rect1.bottomLeft.x, rect2.bottomLeft.x), + y: max(rect1.bottomLeft.y, rect2.bottomLeft.y) + ), + topRight: ( + x: min(rect1.topRight.x, rect2.topRight.x), + y: min(rect1.topRight.y, rect2.topRight.y) + ) + ) + } +} diff --git a/Sources/Graph-DFS/ShortestDistanceFromAllBuildings.swift b/Sources/Graph-DFS/ShortestDistanceFromAllBuildings.swift new file mode 100644 index 0000000..f29af4e --- /dev/null +++ b/Sources/Graph-DFS/ShortestDistanceFromAllBuildings.swift @@ -0,0 +1,124 @@ +// +// ShortestDistanceFromAllBuildings.swift +// +// +// Created by Mohshinsha Shahmadar on 2024-10-19. +// + +import Foundation + +/** + You are given an m x n grid of values 0, 1, or 2, where: + + Each 0 marks an empty land that you can pass through. + Each 1 marks a building that you cannot pass through. + Each 2 marks an obstacle that you cannot pass through. + You want to build a house on an empty land that reaches all buildings in the shortest total travel distance. You can only move up, down, left, and right. + + Return the shortest travel distance for such a house. If it is not possible to build such a house according to the above rules, return -1. + + The total travel distance is the sum of the distances between the house and the buildings. + + The distance is calculated using Manhattan Distance, where: `distance(p1,p2)=∣p2.x−p1.x∣+∣p2.y−p1.y∣` + + For the given grid + 1 0 2 0 1 + 0 0 0 0 0 + 0 0 1 0 0 + Output: 7 + + */ +func findShortestDistanceFromAllBuildings(grid: [[Int]]) -> Int { + struct Pair { + let row: Int + let col: Int + let distance: Int + var key: String { + "\(row)#\(col)" + } + + var left: Pair { .init(row: row - 1, col: col, distance: distance + 1) } + var right: Pair { .init(row: row + 1, col: col, distance: distance + 1) } + var top: Pair { .init(row: row, col: col - 1, distance: distance + 1) } + var bottom: Pair { .init(row: row, col: col + 1, distance: distance + 1) } + } + + guard !grid.isEmpty, !grid[0].isEmpty else { return -1 } + + let rows = grid.count + let cols = grid[0].count + + let land = 0 + let building = 1 + var numberOfBuildings = 0 + + for i in 0.. Bool { + return pair.col >= 0 && + pair.col < cols && + pair.row >= 0 && + pair.row < rows + } + + func performDFS(row: Int, col: Int) { + var queue = [Pair]() + let startPair = Pair(row: row, col: col, distance: 0) + var visited = Set() + queue.append(startPair) + visited.insert(startPair.key) + + var queueHead = 0 + + while queueHead < queue.endIndex { + let headPair = queue[queueHead] + distanceToBuildings[headPair.row][headPair.col].append(headPair.distance) + + for pair in [ + headPair.left, + headPair.right, + headPair.top, + headPair.bottom + ] where !visited.contains(pair.key) && isValid(pair: pair) && grid[pair.row][pair.col] == land { + queue.append(pair) + visited.insert(pair.key) + } + + queueHead += 1 + } + } + + + for i in 0.. Int { + struct Point: Hashable { + let x: Int + let y: Int + } + + let points: [Point] = points.map { Point(x: $0[0], y: $0[1]) } + + var xPointsMap = [Int: Set]() + + for point in points { + var existingSet: Set = xPointsMap[point.x] ?? .init() + existingSet.insert(point.y) + xPointsMap[point.x] = existingSet + } + + var result = Int.max + for point1 in points { + for point2 in points { + if point1.x == point2.x || point1.y == point2.y { + continue + } + + if xPointsMap[point1.x]?.contains(point2.y) == true, + xPointsMap[point2.x]?.contains(point1.y) == true { + let area = abs(point2.x - point1.x) * abs(point2.y - point1.y) + result = min(result, area) + } + } + } + return result == .max ? 0 : result +} diff --git a/Tests/SwiftyAlgorithmsTests/Geometry/OverlappingRectangleTests.swift b/Tests/SwiftyAlgorithmsTests/Geometry/OverlappingRectangleTests.swift new file mode 100644 index 0000000..f2082bb --- /dev/null +++ b/Tests/SwiftyAlgorithmsTests/Geometry/OverlappingRectangleTests.swift @@ -0,0 +1,31 @@ +// +// OverlappingRectangleTests.swift +// +// +// Created by Mohshinsha Shahmadar on 2024-10-20. +// + +import Foundation +import XCTest +@testable import SwiftyAlgorithms + +final class OverlappingRectangleTests: XCTestCase { + + func testIntersectingRectangles() { + let testCases: [AlgorithmTestCase] = [ + .init([[0, 0, 4, 4], [2, 2, 6, 6]], true, "Partially Overlapping"), + .init([[0, 0, 2, 2], [3, 3, 5, 5]], false, "Non-Overlapping"), + .init([[0, 0, 6, 6], [2, 2, 4, 4]], true, "One Rectangle Inside Another"), + .init([[0, 0, 4, 4], [4, 0, 6, 3]], false, "Touching at Edge (Non-Overlapping)"), + .init([[0, 0, 3, 3], [3, 3, 6, 6]], false, "Touching at Corner (Non-Overlapping)"), + .init([[0, 0, 2, 2], [3, 3, 4, 4]], false, "Inverted Rectangle") + ] + + testAlgorithm( + name: "IntersectingRectangle", + with: testCases + ) { input in + checkIfRectanglesIntersectingEachOther(with: input) + } + } +} diff --git a/Tests/SwiftyAlgorithmsTests/Graph-DFS/ShortestDistanceFromAllBuildingsTests.swift b/Tests/SwiftyAlgorithmsTests/Graph-DFS/ShortestDistanceFromAllBuildingsTests.swift new file mode 100644 index 0000000..bdaea09 --- /dev/null +++ b/Tests/SwiftyAlgorithmsTests/Graph-DFS/ShortestDistanceFromAllBuildingsTests.swift @@ -0,0 +1,29 @@ +// +// ShortestDistanceFromAllBuildingsTests.swift +// +// +// Created by Mohshinsha Shahmadar on 2024-10-19. +// + +import Foundation +import XCTest +@testable import SwiftyAlgorithms + +final class ShortestDistanceFromAllBuildingsTests: XCTestCase { + + func testShortestDistanceFromAllBuildings() { + let testCases: [AlgorithmTestCase] = [ + .init([ + [1,0,2,0,1], + [0,0,0,0,0], + [0,0,1,0,0]], 7) + ] + + testAlgorithm( + name: "ShortestDistanceFromAllBuildingsTests", + with: testCases + ) { input in + findShortestDistanceFromAllBuildings(grid: input) + } + } +}