Skip to content
Merged

Bfs #353

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
53 changes: 53 additions & 0 deletions BFS/RaceCar.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Question Link: https://leetcode.com/problems/race-car/
* Primary idea: BFS to go over A or R at a specific step. Only add R to the queue when necessary.
*
* Time Complexity: O(nlogn), Space Complexity: O(n)
*/

class RaceCar {
func racecar(_ target: Int) -> Int {
let startNode = Node(speed: 1, position: 0)
var queue = [startNode], len = 0, isVisited = Set<Node>()

while !queue.isEmpty {
let size = queue.count

for _ in 0..<size {
let node = queue.removeFirst()

if node.position == target {
return len
}

if isVisited.contains(node) {
continue
}

isVisited.insert(node)

let ANode = Node(speed: node.speed * 2, position: node.position + node.speed)
queue.append(ANode)

if shouldRevert(node, target) {
let RNode = Node(speed: node.speed > 0 ? -1 : 1, position: node.position)
queue.append(RNode)
}

}

len += 1
}

return len
}

private func shouldRevert(_ node: Node, _ target: Int) -> Bool {
return (node.position + node.speed > target && node.speed > 0) || (node.position + node.speed < target && node.speed < 0)
}

struct Node: Hashable {
let speed: Int
let position: Int
}
}
45 changes: 23 additions & 22 deletions BFS/ShortestPathGetFood.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,36 @@ class ShortestPathGetFood {
let start = findStart(grid)

isVisited[start.0][start.1] = true
var queue = [Point(i: start.0, j: start.1, len: 0)]
var queue = [(start.0, start.1)], count = 0

while !queue.isEmpty {
let point = queue.removeFirst()

if grid[point.i][point.j] == "#" {
return point.len
}
let size = queue.count

for dir in [(0, 1), (0, -1), (1, 0), (-1, 0)] {
let (x, y) = (point.i + dir.0, point.j + dir.1)
guard x >= 0 && x < m && y >= 0 && y < n && !isVisited[x][y] else {
continue
for _ in 0..<size {
let point = queue.removeFirst()

if grid[point.0][point.1] == "#" {
return count
}

if grid[x][y] == "X" {
continue

for dir in [(0, 1), (0, -1), (1, 0), (-1, 0)] {
let (x, y) = (point.0 + dir.0, point.1 + dir.1)

guard x >= 0 && x < m && y >= 0 && y < n && !isVisited[x][y] else {
continue
}

if grid[x][y] == "X" {
continue
}

isVisited[x][y] = true
queue.append((x, y))
}

isVisited[x][y] = true
queue.append(Point(i: x, j: y, len: point.len + 1))
}

count += 1
}

return -1
Expand All @@ -52,10 +59,4 @@ class ShortestPathGetFood {

return (-1, -1)
}

struct Point {
var i: Int
var j: Int
var len: Int
}
}
51 changes: 25 additions & 26 deletions BFS/ShortestPathGridObstaclesElimination.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,56 +8,55 @@
class ShortestPathGridObstaclesElimination {
func shortestPath(_ grid: [[Int]], _ k: Int) -> Int {
let m = grid.count, n = grid[0].count
var remainings = Array(repeating: Array(repeating: -1, count: n), count: m)
var remaining = Array(repeating: Array(repeating: -1, count: n), count: m)
var queue = [Point(i: 0, j: 0, remain: k)], count = 0

remainings[0][0] = k
var queue = [Point(i: 0, j: 0, remain: k)]
var count = 0

if k > m + n - 2 {
return m + n - 2;
if m + n - 2 < k {
return m + n - 2
}

while !queue.isEmpty {
let size = queue.count

let currentPoints = queue
queue.removeAll()

for point in currentPoints {
if point.i == m - 1 && point.j == n - 1 {
for _ in 0..<size {
let point = queue.removeFirst()

if point.i == m - 1, point.j == n - 1 {
return count
}

for dir in [(0, 1), (0, -1), (1, 0), (-1, 0)] {
let (x, y) = (point.i + dir.0, point.j + dir.1)

for dir in [[0, 1], [0, -1], [1, 0], [-1, 0]] {
let (x, y) = (point.i + dir[0], point.j + dir[1])

guard x >= 0 && x < m && y >= 0 && y < n else {
continue
}

if grid[x][y] == 1 && point.remain <= 0 {
if grid[x][y] == 1 && point.remain == 0 {
continue
}

let remain = grid[x][y] == 1 ? point.remain - 1 : point.remain
// only choose the path if remainings are greater
if remainings[x][y] >= remain {
let nextRemaining = grid[x][y] == 1 ? point.remain - 1 : point.remain

if remaining[x][y] >= nextRemaining {
continue
}
}

remainings[x][y] = remain
queue.append(Point(i: x, j: y, remain: remain))
remaining[x][y] = nextRemaining
queue.append(Point(i: x, j: y, remain: nextRemaining))

}
}

count += 1
}

return -1
}

struct Point {
var i: Int
var j: Int
var remain: Int
let i: Int
let j: Int
let remain: Int
}
}
24 changes: 15 additions & 9 deletions BFS/WordLadder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,26 @@

class WordLadder {
func ladderLength(_ beginWord: String, _ endWord: String, _ wordList: [String]) -> Int {
var wordSet = Set(wordList), wordStepQueue = [(beginWord, 1)]
var wordSet = Set(wordList), wordQueue = [beginWord], count = 1

while !wordStepQueue.isEmpty {
let (currentWord, currentStep) = wordStepQueue.removeFirst()
while !wordQueue.isEmpty {

if currentWord == endWord {
return currentStep
}
let size = wordQueue.count

for word in neighbors(for: currentWord, in: wordSet) {
for _ in 0..<size {
let currentWord = wordQueue.removeFirst()

if currentWord == endWord {
return count
}

wordStepQueue.append((word, currentStep + 1))
wordSet.remove(word)
for word in neighbors(for: currentWord, in: wordSet) {
wordQueue.append(word)
wordSet.remove(word)
}
}

count += 1
}

return 0
Expand Down