Skip to content

Commit 4cb61c2

Browse files
author
Michael Ho
committed
First update in 2019
1 parent de4a214 commit 4cb61c2

File tree

30 files changed

+1144
-130
lines changed

30 files changed

+1144
-130
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// Heap
2+
// Maxheaps: Elements with a higher value represent higher priority.
3+
// Minheaps: Elements with a lower value represent higher priority.
4+
5+
import Foundation
6+
7+
struct Heap<Element> {
8+
var elements : [Element]
9+
let priorityFunction : (Element, Element) -> Bool
10+
11+
init(elements: [Element] = [], priorityFunction: @escaping (Element, Element) -> Bool) {
12+
self.elements = elements
13+
self.priorityFunction = priorityFunction
14+
buildHeap()
15+
}
16+
17+
mutating func buildHeap() {
18+
for index in (0 ..< count/2).reversed() {
19+
siftDown(elementAtIndex: index)
20+
}
21+
}
22+
23+
var isEmpty : Bool { return elements.isEmpty }
24+
var count : Int { return elements.count }
25+
26+
func peek() -> Element? {
27+
return elements.first
28+
}
29+
30+
mutating func enqueue(_ element: Element) {
31+
elements.append(element)
32+
siftUp(elementAtIndex: count - 1)
33+
}
34+
35+
mutating func siftUp(elementAtIndex index: Int) {
36+
let parent = parentIndex(of: index)
37+
guard !isRoot(index),
38+
isHigherPriority(at: index, than: parent)
39+
else { return }
40+
swapElement(at: index, with: parent)
41+
siftUp(elementAtIndex: parent)
42+
}
43+
44+
mutating func dequeue() -> Element? {
45+
guard !isEmpty
46+
else { return nil }
47+
swapElement(at: 0, with: count - 1)
48+
let element = elements.removeLast()
49+
if !isEmpty {
50+
siftDown(elementAtIndex: 0)
51+
}
52+
return element
53+
}
54+
55+
mutating func siftDown(elementAtIndex index: Int) {
56+
let childIndex = highestPriorityIndex(for: index)
57+
if index == childIndex {
58+
return
59+
}
60+
swapElement(at: index, with: childIndex)
61+
siftDown(elementAtIndex: childIndex)
62+
}
63+
64+
// Helper functions
65+
func isRoot(_ index: Int) -> Bool {
66+
return index == 0
67+
}
68+
69+
func leftChildIndex(of index: Int) -> Int {
70+
return (2 * index) + 1
71+
}
72+
73+
func rightChildIndex(of index: Int) -> Int {
74+
return (2 * index) + 2
75+
}
76+
77+
func parentIndex(of index: Int) -> Int {
78+
return (index - 1) / 2
79+
}
80+
81+
func isHigherPriority(at firstIndex: Int, than secondIndex: Int) -> Bool {
82+
return priorityFunction(elements[firstIndex], elements[secondIndex])
83+
}
84+
85+
func highestPriorityIndex(of parentIndex: Int, and childIndex: Int) -> Int {
86+
guard childIndex < count && isHigherPriority(at: childIndex, than: parentIndex)
87+
else { return parentIndex }
88+
return childIndex
89+
}
90+
91+
func highestPriorityIndex(for parent: Int) -> Int {
92+
return highestPriorityIndex(of: highestPriorityIndex(of: parent, and: leftChildIndex(of: parent)), and: rightChildIndex(of: parent))
93+
}
94+
95+
mutating func swapElement(at firstIndex: Int, with secondIndex: Int) {
96+
guard firstIndex != secondIndex
97+
else { return }
98+
swap(&elements[firstIndex], &elements[secondIndex])
99+
}
100+
}
101+
102+
// A bonus extra for you: two extra functions, if the Element type is Equatable
103+
extension Heap where Element : Equatable {
104+
105+
// This function allows you to remove an element from the heap, in a similar way to how you would dequeue the root element.
106+
mutating func remove(_ element: Element) {
107+
guard let index = elements.index(of: element)
108+
else { return }
109+
swapElement(at: index, with: count - 1)
110+
elements.remove(at: count - 1)
111+
siftDown(elementAtIndex: index)
112+
}
113+
114+
// This function allows you to 'boost' an element, by sifting the element up the heap. You might do this if the element is already in the heap, but its priority has increased since it was enqueued.
115+
mutating func boost(_ element: Element) {
116+
guard let index = elements.index(of: element)
117+
else { return }
118+
siftUp(elementAtIndex: index)
119+
}
120+
}
121+
122+
var heap = Heap<Int>(elements: [3, 2, 8, 5, 0], priorityFunction: >)
123+
heap.enqueue(6)
124+
heap.enqueue(1)
125+
heap.enqueue(4)
126+
heap.enqueue(7)
127+
heap.dequeue()
128+
print(heap.elements)
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/**
2+
Trie implementation
3+
4+
LeetCode: https://leetcode.com/problems/implement-trie-prefix-tree
5+
*/
6+
7+
class Trie {
8+
var root: Node
9+
10+
// Initialize your data structure here.
11+
init() {
12+
self.root = Node()
13+
}
14+
15+
// Inserts a word into the trie.
16+
func insert(_ word: String) {
17+
var currentNode = self.root
18+
for ch in word {
19+
if currentNode.children[ch] == nil {
20+
currentNode.children[ch] = Node(ch)
21+
}
22+
currentNode = currentNode.children[ch]!
23+
}
24+
// Only go through to the last node represents a word
25+
currentNode.isWord = true
26+
}
27+
28+
// Returns if the word is in the trie.
29+
func search(_ word: String) -> Bool {
30+
var currentNode = self.root
31+
for ch in word {
32+
if currentNode.children[ch] != nil {
33+
currentNode = currentNode.children[ch]!
34+
} else {
35+
return false
36+
}
37+
}
38+
return currentNode.isWord
39+
}
40+
41+
// Returns if there is any word in the trie that starts with the given prefix.
42+
func startsWith(_ prefix: String) -> Bool {
43+
var currentNode = self.root
44+
for ch in prefix {
45+
if currentNode.children[ch] != nil {
46+
currentNode = currentNode.children[ch]!
47+
} else {
48+
return false
49+
}
50+
}
51+
return true
52+
}
53+
}
54+
55+
public class Node {
56+
var val: Character
57+
var children: [Character : Node]
58+
var isWord: Bool
59+
60+
init() {
61+
self.val = "*"
62+
self.children = [:]
63+
self.isWord = false
64+
}
65+
66+
init(_ val: Character) {
67+
self.val = val
68+
self.children = [:]
69+
self.isWord = false
70+
}
71+
}
72+
73+
// Test cases
74+
let trie = Trie()
75+
trie.insert("apple")
76+
trie.search("apple") // returns true
77+
trie.search("app") // returns false
78+
trie.startsWith("app") // returns true
79+
trie.insert("app")
80+
trie.search("app")
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<playground version='5.0' target-platform='macos' executeOnSourceChanges='false'>
3+
<timeline fileName='timeline.xctimeline'/>
4+
</playground>
Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// LeetCode: https://leetcode.com/problems/merge-two-sorted-lists/description/
22

3+
import XCTest
4+
35
public class ListNode {
46
public var val: Int
57
public var next: ListNode?
@@ -8,48 +10,49 @@ public class ListNode {
810
self.next = nil
911
}
1012
}
13+
1114
class Solution {
1215
func mergeTwoLists(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? {
13-
if nil != l1, nil == l2 {
14-
return l1
15-
} else if nil == l1, nil != l2 {
16+
guard l1 != nil || l2 != nil else {
17+
return nil
18+
}
19+
if l1 == nil {
1620
return l2
21+
} else if l2 == nil {
22+
return l1
1723
}
1824

19-
guard let l1 = l1, let l2 = l2 else {
20-
return nil
21-
}
22-
var head: ListNode?
23-
var output: ListNode?
24-
var list1: ListNode? = l1
25-
var list2: ListNode? = l2
26-
if (list1?.val)! < (list2?.val)! {
27-
head = l1
28-
list1 = list1?.next
25+
var l1 = l1
26+
var l2 = l2
27+
var value: Int!
28+
if (l1?.val)! < (l2?.val)! {
29+
value = (l1?.val)!
30+
l1 = l1?.next
2931
} else {
30-
head = l2
31-
list2 = list2?.next
32+
value = (l2?.val)!
33+
l2 = l2?.next
3234
}
33-
output = head
35+
var head = ListNode(value)
36+
var node: ListNode? = head
3437

35-
while nil != list1 || nil != list2 {
36-
guard nil != list1 else {
37-
head?.next = list2
38-
return output
39-
}
40-
guard nil != list2 else {
41-
head?.next = list1
42-
return output
38+
while l1 != nil || l2 != nil {
39+
if l1 == nil {
40+
node?.next = l2
41+
break
42+
} else if l2 == nil {
43+
node?.next = l1
44+
break
4345
}
44-
if (list1?.val)! < (list2?.val)! {
45-
head?.next = list1
46-
list1 = list1?.next
46+
47+
if (l1?.val)! < (l2?.val)! {
48+
node?.next = ListNode((l1?.val)!)
49+
l1 = l1?.next
4750
} else {
48-
head?.next = list2
49-
list2 = list2?.next
51+
node?.next = ListNode((l2?.val)!)
52+
l2 = l2?.next
5053
}
51-
head = head?.next
54+
node = node?.next
5255
}
53-
return output
56+
return head
5457
}
5558
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// LeetCode: https://leetcode.com/problems/contains-duplicate-ii/description/
2+
3+
import XCTest
4+
5+
class Solution {
6+
func containsNearbyDuplicate(_ nums: [Int], _ k: Int) -> Bool {
7+
var dict: [Int:Int] = [:]
8+
for (idx, num) in nums.enumerated() {
9+
if dict[num] != nil, idx - dict[num]! <= k {
10+
return true
11+
}
12+
dict[num] = idx
13+
}
14+
return false
15+
}
16+
}
17+
18+
class Tests: XCTestCase {
19+
let s = Solution()
20+
21+
func testSample1() {
22+
let input = ([1,2,3,1,2,3], 2)
23+
XCTAssertFalse(s.containsNearbyDuplicate(input.0, input.1))
24+
}
25+
26+
func testSample2() {
27+
let input = ([1,0,1,1], 1)
28+
XCTAssertTrue(s.containsNearbyDuplicate(input.0, input.1))
29+
}
30+
}
31+
32+
Tests.defaultTestSuite.run()
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<playground version='5.0' target-platform='macos' executeOnSourceChanges='false'>
3+
<timeline fileName='timeline.xctimeline'/>
4+
</playground>

0 commit comments

Comments
 (0)