-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathCountAndSay.kt
78 lines (68 loc) · 2.25 KB
/
CountAndSay.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package questions
import _utils.UseCommentAsDocumentation
import utils.shouldBe
import java.math.BigInteger
/**
* The count-and-say sequence is a sequence of digit strings defined by the recursive formula:
* * `countAndSay(1)` = "1"
* * `countAndSay(n)` is the way you would "say" the digit string from `countAndSay(n-1)`,which is then converted into a different digit string.
*
* To determine how you "say" a digit string, split it into the minimal number of substrings such that each substring
* contains exactly one unique digit. Then for each substring, say the number of digits, then say the digit.
* Finally, concatenate every said digit.
*
* [Source](https://leetcode.com/problems/count-and-say/)
*/
@UseCommentAsDocumentation
private fun countAndSay(n: Int): String {
if (n == 1) { // base case
return "1"
}
return _countAndSay(n, 2, "1")
}
typealias CharToConsecutiveCount = Pair<Char, Int>
private fun _countAndSay(n: Int, current: Int, value: String): String {
if (current > n) {
return value
}
return _countAndSay(n, current + 1, say(count(value.toBigInteger())))
}
/**
* Count the number of occurrence of a character in a consecutive manner
*/
private fun count(n: BigInteger): List<CharToConsecutiveCount> {
val str = n.toString()
var prevInt = str[0]
var count = 1
val result = mutableListOf<Pair<Char, Int>>()
for (index in 1..str.length) {
if (index == str.length) {
result.add(Pair(prevInt, count))
break
}
if (prevInt == str[index]) {
count++
} else {
result.add(Pair(prevInt, count))
prevInt = str[index]
count = 1
}
}
return result
}
private fun say(charToCount: List<CharToConsecutiveCount>): String {
val result = StringBuilder()
charToCount.forEach {
result.append(it.second.toString()).append(it.first) // occurrence + character
}
return result.toString()
}
fun main() {
countAndSay(11) shouldBe "11131221133112132113212221"
countAndSay(10) shouldBe "13211311123113112211"
countAndSay(1) shouldBe "1"
countAndSay(2) shouldBe "11"
countAndSay(3) shouldBe "21"
countAndSay(4) shouldBe "1211"
countAndSay(5) shouldBe "111221"
}