Kotlin String Problems with Solutions : 15 Essential Coding Interview Questions
Here are 15 essential Kotlin string problems with detailed solutions, outputs, and explanations. Perfect for interview prep and strengthening your Kotlin skills.
1. Isomorphic Strings
Copy
fun isIsomorphic(s: String, t: String): Boolean {
if (s.length != t.length) return false
val mapS = mutableMapOf()
val mapT = mutableMapOf()
for (i in s.indices) {
val c1 = s[i]
val c2 = t[i]
if (mapS.getOrPut(c1) { c2 } != c2 || mapT.getOrPut(c2) { c1 } != c1) return false
}
return true
}
fun main() {
println(isIsomorphic("egg", "add"))
println(isIsomorphic("foo", "bar"))
}
Output:
true
false
Explanation: “egg” → “add” maintains mapping (e→a, g→d). “foo” → “bar” breaks mapping since ‘o’ cannot map to both ‘a’ and ‘r’.
2. Word Pattern
Copy
fun wordPattern(pattern: String, s: String): Boolean {
val words = s.split(" ")
if (pattern.length != words.size) return false
val map = mutableMapOf()
val set = mutableSetOf()
for (i in pattern.indices) {
val c = pattern[i]
val w = words[i]
if (map.containsKey(c)) {
if (map[c] != w) return false
} else {
if (!set.add(w)) return false
map[c] = w
}
}
return true
}
fun main() {
println(wordPattern("abba", "dog cat cat dog"))
println(wordPattern("abba", "dog cat cat fish"))
}
Output:
true
false
Explanation: Pattern “abba” maps correctly to “dog cat cat dog”. In the second case, mapping breaks as last “a” maps to “dog” but pattern mismatches.
3. Valid Palindrome
Copy
fun isPalindrome(s: String): Boolean {
val str = s.filter { it.isLetterOrDigit() }.lowercase()
return str == str.reversed()
}
fun main() {
println(isPalindrome("A man, a plan, a canal: Panama"))
println(isPalindrome("race a car"))
}
Output:
true
false
Explanation: “A man, a plan, a canal: Panama” → palindrome after cleaning. “race a car” → not a palindrome.
4. Reverse Only Letters
Copy
fun reverseOnlyLetters(s: String): String {
val letters = s.filter { it.isLetter() }.toMutableList()
return s.map { if (it.isLetter()) letters.removeAt(letters.lastIndex) else it }.joinToString("")
}
fun main() {
println(reverseOnlyLetters("ab-cd"))
println(reverseOnlyLetters("a-bC-dEf-ghIj"))
}
Output:
dc-ba
j-Ih-gfE-dCba
Explanation: Non-letters remain fixed, only letters reverse.
5. Roman to Integer
Copy
fun romanToInt(s: String): Int {
val map = mapOf('I' to 1,'V' to 5,'X' to 10,'L' to 50,'C' to 100,'D' to 500,'M' to 1000)
var res = 0
var i = 0
while (i < s.length) {
if (i + 1 < s.length && map[s[i]]!! < map[s[i + 1]]!!) {
res += map[s[i + 1]]!! - map[s[i]]!!
i += 2
} else {
res += map[s[i]]!!
i++
}
}
return res
}
fun main() {
println(romanToInt("III"))
println(romanToInt("IX"))
println(romanToInt("LVIII"))
}
Output:
3
9
58
Explanation: Subtractive notation (like IV = 4, IX = 9) is handled with lookahead.
6. Valid Anagram
Copy
fun isAnagram(s: String, t: String): Boolean {
return s.toCharArray().sorted() == t.toCharArray().sorted()
}
fun main() {
println(isAnagram("anagram", "nagaram"))
println(isAnagram("rat", "car"))
}
Output:
true
false
Explanation: Both strings sorted must be identical for an anagram.
7. Find the Index of the First Occurrence (strStr)
Copy
fun strStr(haystack: String, needle: String): Int {
return haystack.indexOf(needle)
}
fun main() {
println(strStr("sadbutsad", "sad"))
println(strStr("leetcode", "leeto"))
}
Output:
0
-1
Explanation: Uses Kotlin’s built-in indexOf
.
8. Repeated Substring Pattern
Copy
fun repeatedSubstringPattern(s: String): Boolean {
val str = s + s
return str.substring(1, str.length - 1).contains(s)
}
fun main() {
println(repeatedSubstringPattern("abab"))
println(repeatedSubstringPattern("aba"))
}
Output:
true
false
Explanation: Trick: if s can be built by repeating substring, it will appear inside (s+s)[1..-1].
9. Valid Parentheses
Copy
fun isValid(s: String): Boolean {
val stack = ArrayDeque()
val map = mapOf(')' to '(', '}' to '{', ']' to '[')
for (c in s) {
if (c in map.values) stack.addLast(c)
else if (stack.isEmpty() || stack.removeLast() != map[c]) return false
}
return stack.isEmpty()
}
fun main() {
println(isValid("()"))
println(isValid("()[]{}"))
println(isValid("(]"))
}
Output:
true
true
false
Explanation: Uses stack to check balanced parentheses.
10. Valid Palindrome II
Copy
fun validPalindrome(s: String): Boolean {
fun isPal(sub: String): Boolean = sub == sub.reversed()
var l = 0; var r = s.lastIndex
while (l < r) {
if (s[l] != s[r]) {
return isPal(s.substring(l+1, r+1)) || isPal(s.substring(l, r))
}
l++; r--
}
return true
}
fun main() {
println(validPalindrome("aba"))
println(validPalindrome("abca"))
}
Output:
true
true
Explanation: At most one character can be deleted to form a palindrome.
11. Longest Common Prefix
Copy
fun longestCommonPrefix(strs: Array): String {
if (strs.isEmpty()) return ""
var prefix = strs[0]
for (i in 1 until strs.size) {
while (strs[i].indexOf(prefix) != 0) {
prefix = prefix.substring(0, prefix.length - 1)
if (prefix.isEmpty()) return ""
}
}
return prefix
}
fun main() {
println(longestCommonPrefix(arrayOf("flower","flow","flight")))
println(longestCommonPrefix(arrayOf("dog","racecar","car")))
}
Output:
fl
(empty string)
Explanation: Shrinks prefix until all strings start with it.
12. Backspace String Compare
Copy
fun backspaceCompare(s: String, t: String): Boolean {
fun build(str: String): String {
val stack = ArrayDeque()
for (c in str) {
if (c != '#') stack.addLast(c) else if (stack.isNotEmpty()) stack.removeLast()
}
return stack.joinToString("")
}
return build(s) == build(t)
}
fun main() {
println(backspaceCompare("ab#c", "ad#c"))
println(backspaceCompare("ab##", "c#d#"))
}
Output:
true
true
Explanation: Backspaces processed via stack.
13. Reorder Data in Log Files
Copy
fun reorderLogFiles(logs: Array): Array {
val letterLogs = mutableListOf()
val digitLogs = mutableListOf()
for (log in logs) {
val parts = log.split(" ", limit = 2)
if (parts[1][0].isDigit()) digitLogs.add(log) else letterLogs.add(log)
}
letterLogs.sortWith(compareBy({ it.substringAfter(" ") }, { it.substringBefore(" ") }))
return (letterLogs + digitLogs).toTypedArray()
}
fun main() {
val logs = arrayOf("dig1 8 1 5 1","let1 art can","dig2 3 6","let2 own kit dig","let3 art zero")
println(reorderLogFiles(logs).joinToString())
}
Output:
let1 art can, let3 art zero, let2 own kit dig, dig1 8 1 5 1, dig2 3 6
Explanation: Letter-logs come before digit-logs, sorted lexicographically by content.
14. Add Binary
Copy
fun addBinary(a: String, b: String): String {
var i = a.lastIndex
var j = b.lastIndex
var carry = 0
val sb = StringBuilder()
while (i >= 0 || j >= 0 || carry > 0) {
val sum = (if (i >= 0) a[i--] - '0' else 0) +
(if (j >= 0) b[j--] - '0' else 0) + carry
sb.append(sum % 2)
carry = sum / 2
}
return sb.reverse().toString()
}
fun main() {
println(addBinary("11","1"))
println(addBinary("1010","1011"))
}
Output:
100
10101
Explanation: Binary addition handled digit by digit with carry.
15. Word Pattern II (Bijective Mapping)
Copy
fun wordPatternMatch(pattern: String, s: String): Boolean {
fun backtrack(p: Int, strIdx: Int, map: MutableMap, used: MutableSet): Boolean {
if (p == pattern.length && strIdx == s.length) return true
if (p == pattern.length || strIdx == s.length) return false
val c = pattern[p]
if (c in map) {
val w = map[c]!!
return if (s.startsWith(w, strIdx)) backtrack(p+1, strIdx+w.length, map, used) else false
}
for (end in strIdx+1..s.length) {
val sub = s.substring(strIdx, end)
if (sub in used) continue
map[c] = sub; used.add(sub)
if (backtrack(p+1, end, map, used)) return true
map.remove(c); used.remove(sub)
}
return false
}
return backtrack(0,0, mutableMapOf(), mutableSetOf())
}
fun main() {
println(wordPatternMatch("abab", "redblueredblue"))
println(wordPatternMatch("aaaa", "asdasdasdasd"))
}
Output:
true
true
Explanation: Backtracking checks if pattern maps bijectively to substrings.
Some of the most common Kotlin string problems are Isomorphic Strings, Word Pattern, Valid Palindrome, Reverse Only Letters, Roman to Integer, Valid Anagram, strStr(), Repeated Substring Pattern, Valid Parentheses, Valid Palindrome II, Longest Common Prefix, Backspace String Compare, Reorder Data in Log Files, Implement strStr(), and Add Binary.
String problems are fundamental in coding interviews because they test algorithmic thinking, data structures knowledge, and problem-solving skills. Practicing Kotlin string problems prepares developers for real-world coding challenges.
Yes, the provided solutions are optimized for coding interviews. They use efficient approaches like HashMaps, two pointers, and string manipulation tricks while keeping code clean and interview-friendly.
Yes, all solutions are written in Kotlin and can be run directly in IntelliJ IDEA, Android Studio, or any Kotlin-supported environment.