Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

38 overlapping rectangles #39

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
137 changes: 137 additions & 0 deletions Sources/Geometry/OverlappingRectangles.swift
Original file line number Diff line number Diff line change
@@ -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..<rectangles.count {
resultRectangle = resultRectangle.intersect(with: rectangles[i])
}
return resultRectangle.renderingType == .rectangle
}

fileprivate func findOverlappingType(for renderedType: Rectangle.RenderedType) -> 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)
)
)
}
}
124 changes: 124 additions & 0 deletions Sources/Graph-DFS/ShortestDistanceFromAllBuildings.swift
Original file line number Diff line number Diff line change
@@ -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..<grid.count {
for j in 0..<grid[i].count where grid[i][j] == 1 {
numberOfBuildings += 1
}
}

let initialMappings = [Int]()
// Distance from Land to ALL Buildings
var distanceToBuildings = Array(
repeating: Array(repeating: initialMappings, count: cols),
count: grid.count
)

func isValid(pair: Pair) -> 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<String>()
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..<grid.count {
for j in 0..<grid[i].count where grid[i][j] == building {
performDFS(row: i, col: j)
}
}

var result: Int = Int.max

for i in 0..<grid.count {
for j in 0..<grid[i].count where grid[i][j] == land {
let distanceArray = distanceToBuildings[i][j]
if distanceArray.count != numberOfBuildings {
return -1
} else {
let distanceSum = distanceArray.reduce(0) { $0 + $1 }
result = min(result, distanceSum)
}
}
}

return result == Int.max ? -1 : result
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// ClimbStairsTests.swift
//
//
// Created by Mohshinsha Shahmadar on 2024-09-09.
//

import Foundation
import XCTest
@testable import SwiftyAlgorithms

final class ClimbStairsTests: XCTestCase {
func testClimbStairs() {

let testCases: [AlgorithmTestCase] = [
.init(0, 0),
.init(1, 1),
.init(2, 2),
.init(3, 3),
.init(4, 5),
.init(5, 8),
.init(6, 13),
.init(7, 21),
.init(8, 34),
.init(9, 55),
// 1,2,3,5,8,13,21,34,55
]

testAlgorithm(
name: "Ways to ClimbStairs to reach `n`",
with: testCases
) { input in
findNumberOfWaysToClimbStairs(toReach: input)
}
}
}
79 changes: 79 additions & 0 deletions Tests/SwiftyAlgorithmsTests/Geometry/MinAreaRectangleTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//
// MinAreaRectangle.swift
//
//
// Created by Mohshinsha Shahmadar on 2024-10-20.
//

import Foundation
import XCTest
@testable import SwiftyAlgorithms

final class MinAreaRectangleTests: XCTestCase {

func testIntersectingRectangles() {
let testCases: [AlgorithmTestCase] = [
.init([[1, 1],[1, 3],[3, 1], [3, 3], [4,1], [4,3]], 2),
]

testAlgorithm(
name: "MinAreaRectangleTests",
with: testCases) { input in
minAreaFreeRect(input)
}
}
}

/**
You are given an array of points in the X-Y plane points where points[i] = [xi, yi].
Return the minimum area of any rectangle formed from these points, with sides not necessarily parallel to the X and Y axes. If there is not any such rectangle, return 0.

Answers within 10-5 of the actual answer will be accepted.

Example 1:
Input: points = [[1,2],[2,1],[1,0],[0,1]]
Output: 2
Explanation: The minimum area rectangle occurs at [1,2],[2,1],[1,0],[0,1], with an area of 2.

Example 2:
Input: points = [[0,1],[2,1],[1,1],[1,0],[2,0]]
Output: 1
Explanation: The minimum area rectangle occurs at [1,0],[1,1],[2,1],[2,0], with an area of 1.

Example 3:
Input: points = [[0,3],[1,2],[3,1],[1,3],[2,1]]
Output: 0
Explanation: There is no possible rectangle to form from these points.
*/
func minAreaFreeRect(_ points: [[Int]]) -> 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<Int>]()

for point in points {
var existingSet: Set<Int> = 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
}
Loading
Loading