Kotlin String Problems with Solutions: Must-Know Examples for AndroidProgrammer

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.

What are the most common Kotlin string problems asked in interviews?

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.

Why practice Kotlin string problems?

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.

Are the solutions optimized for coding interviews?

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.

Can I run these Kotlin string solutions directly?

Yes, all solutions are written in Kotlin and can be run directly in IntelliJ IDEA, Android Studio, or any Kotlin-supported environment.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top