1
+ /*
2
+ * Copyright 2021 Nazmul Idris. All rights reserved.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ package algorithms
19
+
20
+ import color_console_log.ColorConsoleContext.Companion.colorConsole
21
+ import color_console_log.Colors
22
+ import support.Main
23
+ import support.RuntimeStats
24
+ import support.printHeading
25
+
26
+ /* * Makes it easy to run just this file. */
27
+ fun main () {
28
+ BigO .main(args = emptyArray())
29
+ }
30
+
31
+ object BigO : Main {
32
+
33
+ override fun main (args : Array <String >) {
34
+
35
+ run {
36
+ " o(1)" .printHeading()
37
+ colorConsole {
38
+ val list = listOf (null , " abc" , " def" )
39
+ val text1 = " is first elem of list $list null? = "
40
+ val text2 = " ${isFirstElementNull(list)} "
41
+
42
+ printLine(spanSeparator = " " , prefixWithTimestamp = false ) {
43
+ span(Colors .Purple , text1)
44
+ span(Colors .Yellow , " ➡ " )
45
+ span(Colors .Blue , text2)
46
+ }
47
+ }
48
+ }
49
+
50
+ run {
51
+ " o(n)" .printHeading()
52
+ RuntimeStats ().also { rs ->
53
+ colorConsole {
54
+ val value = " efg"
55
+ val list = listOf (" abc" , " def" , " 123" , " xyz" )
56
+ val text1 = " is '$value ` in list $list = ${containsValue(list, value, rs)} "
57
+ val text2 = " $rs "
58
+
59
+ printLine(spanSeparator = " " , prefixWithTimestamp = false ) {
60
+ span(Colors .Purple , text1)
61
+ span(Colors .Yellow , " ➡ " )
62
+ span(Colors .Blue , text2)
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ run {
69
+ " o(n^2)" .printHeading()
70
+ colorConsole {
71
+ val list = listOf (" abc" , " def" , " 123" , " abc" , " 123" , " 567" )
72
+ val stats = containsDupes(list)
73
+ val text1 =
74
+ " list $list " + if (stats.dupes > 0 ) " contains dupes" else " does not contain dupes"
75
+ val text2 = " $stats "
76
+
77
+ printLine(spanSeparator = " " , prefixWithTimestamp = false ) {
78
+ span(Colors .Purple , text1)
79
+ span(Colors .Yellow , " ➡ " )
80
+ span(Colors .White , text2)
81
+ }
82
+ }
83
+ }
84
+
85
+ run {
86
+ " o(2^n)" .printHeading()
87
+ val value = 20
88
+ with (RuntimeStats ()) {
89
+ colorConsole {
90
+ printLine(spanSeparator = " " , prefixWithTimestamp = false ) {
91
+ val text1 = " fibonacci($value ) = ${fibonacci(value, this @with)} "
92
+ val text2 = this @with.toString()
93
+ span(Colors .Purple , text1)
94
+ span(Colors .Yellow , " ➡ " )
95
+ span(Colors .White , text2)
96
+ }
97
+ }
98
+ }
99
+ }
100
+
101
+ run {
102
+ " o(log n)" .printHeading()
103
+ colorConsole {
104
+ printLine(spanSeparator = " " , prefixWithTimestamp = false ) {
105
+ span(Colors .Purple , " binarySearch()" )
106
+ }
107
+ }
108
+ val item = " zany"
109
+ val list = listOf (
110
+ " nazmul" , " idris" , " maret" , " john" , " harry" , " tom" , " tony" , " pepper" , " andrew"
111
+ ).sorted()
112
+ with (RuntimeStats ()) {
113
+ colorConsole {
114
+ val result = binarySearch(item, list, this @with)
115
+ printLine(spanSeparator = " " , prefixWithTimestamp = false ) {
116
+ span(Colors .Purple , " found:" )
117
+ span(Colors .Yellow , " ➡ " )
118
+ span(Colors .Green , " $result " )
119
+ }
120
+ }
121
+ }
122
+ }
123
+ }
124
+
125
+ /* * O(log n) */
126
+ fun binarySearch (
127
+ item : String ,
128
+ sortedList : List <String >,
129
+ stats : RuntimeStats
130
+ ): Boolean {
131
+ colorConsole {
132
+ printLine(spanSeparator = " " , prefixWithTimestamp = false ) {
133
+ span(Colors .Blue , " \n binarySearch($item )" )
134
+ span(Colors .Yellow , " ➡ " )
135
+ span(Colors .Green , " $sortedList " )
136
+ }
137
+ }
138
+ stats.operations++
139
+
140
+ // Exit conditions (base cases)
141
+ if (sortedList.isEmpty()) {
142
+ return false
143
+ }
144
+
145
+ // Setup probe
146
+ val size = sortedList.size
147
+ val probeIndex = size / 2
148
+ val probeItem = sortedList[probeIndex]
149
+ stats.comparisons++
150
+ colorConsole {
151
+ printLine(spanSeparator = " " , prefixWithTimestamp = false ) {
152
+ span(Colors .Blue , " ✨ probe" )
153
+ span(Colors .Yellow , " ➡ " )
154
+ span(Colors .Green , " [index=$probeIndex , $probeItem ]" )
155
+ }
156
+ }
157
+
158
+ // Does the probe match? If not, split and recurse
159
+ when {
160
+ item == probeItem -> return true
161
+ item < probeItem -> return binarySearch(
162
+ item,
163
+ sortedList.subList(0 , probeIndex),
164
+ stats
165
+ )
166
+ else -> return binarySearch(
167
+ item,
168
+ sortedList.subList(
169
+ probeIndex + 1 ,
170
+ size
171
+ ),
172
+ stats
173
+ )
174
+ }
175
+ }
176
+
177
+ /* *
178
+ * O(n^2)
179
+ *
180
+ * For an input size of 6, 6x6 comparisons are made due to two inner loops iterating over the
181
+ * size of the input list.
182
+ * [More info in wiki](https://github.com/nazmulidris/algorithms-in-kotlin/wiki/Big-O-Notation).
183
+ */
184
+ fun containsDupes (list : List <String >) = RuntimeStats ().apply {
185
+ with (list) {
186
+ for (cursor1 in 0 until size) {
187
+ for (cursor2 in 0 until size) {
188
+ comparisons++
189
+ if (cursor1 != cursor2) {
190
+ if (get(cursor1) == get(cursor2)) {
191
+ dupes++
192
+ get(cursor1).let {
193
+ dupeMap[it] = dupeMap[it] ? : 0 + 1
194
+ }
195
+ }
196
+ }
197
+ }
198
+ }
199
+ }
200
+ }
201
+
202
+ /* * O(1) */
203
+ fun isFirstElementNull (list : List <String ?>) = list[0 ] == null
204
+
205
+ /* * O(n) */
206
+ fun containsValue (
207
+ list : List <String >,
208
+ value : String ,
209
+ stats : RuntimeStats
210
+ ): Boolean {
211
+ list.forEach { it ->
212
+ stats.comparisons++
213
+ if (it == value) {
214
+ return true
215
+ }
216
+ }
217
+ return false
218
+ }
219
+
220
+ /* * O(2^n) */
221
+ fun fibonacci (number : Int , stats : RuntimeStats ): Int {
222
+ stats.operations++
223
+ return if (number <= 1 ) number
224
+ else fibonacci(number - 1 , stats) + fibonacci(number - 2 , stats)
225
+ }
226
+ }
0 commit comments