Coding Interview Questions
Reverse a string without using reversed().
Example
Two-pointer swap on a CharArray: O(n) time, O(n) space for the array.
fun reverse(s: String): String {
val chars = s.toCharArray()
var i = 0
var j = chars.lastIndex
while (i < j) {
val tmp = chars[i]; chars[i] = chars[j]; chars[j] = tmp
i++; j--
}
return String(chars)
}
fun main() {
println(reverse("Kotlin"))
println(reverse("Careeroza"))
println(reverse(""))
}Output
niltoK azoreeraC
Check whether a string is a palindrome (ignore case and non-letters).
Example
fun isPalindrome(s: String): Boolean {
val clean = s.lowercase().filter { it.isLetterOrDigit() }
return clean == clean.reversed()
}
fun main() {
listOf("Madam", "A man, a plan, a canal: Panama", "Kotlin").forEach {
println("\"$it\" -> ${isPalindrome(it)}")
}
}Output
"Madam" -> true "A man, a plan, a canal: Panama" -> true "Kotlin" -> false
Print the first N Fibonacci numbers.
Example
Iterative (O(n), no recursion overflow) and a lazy generateSequence version.
fun fib(n: Int): List<Long> {
val result = mutableListOf<Long>()
var a = 0L
var b = 1L
repeat(n) {
result.add(a)
val next = a + b
a = b; b = next
}
return result
}
fun main() {
println(fib(10))
val seq = generateSequence(0L to 1L) { (a, b) -> b to a + b }.map { it.first }
println(seq.take(10).toList())
}Output
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34] [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Count the frequency of each character in a string.
Example
groupingBy { }.eachCount() returns a LinkedHashMap, so the order of first appearance is kept.
fun main() {
val text = "programming"
val freq = text.groupingBy { it }.eachCount()
println(freq)
val firstNonRepeating = text.firstOrNull { freq[it] == 1 }
println("First non-repeating: $firstNonRepeating")
val mostCommon = freq.maxByOrNull { it.value }
println("Most common: ${mostCommon?.key} (${mostCommon?.value} times)")
}Output
{p=1, r=2, o=1, g=2, a=1, m=2, i=1, n=1}
First non-repeating: p
Most common: r (2 times)Check whether two strings are anagrams.
Example
Sort-based is O(n log n); counting with an IntArray(26) is O(n).
fun isAnagram(a: String, b: String): Boolean {
if (a.length != b.length) return false
val count = IntArray(26)
for (c in a.lowercase()) count[c - 'a']++
for (c in b.lowercase()) count[c - 'a']--
return count.all { it == 0 }
}
fun main() {
println(isAnagram("listen", "silent"))
println(isAnagram("Triangle", "Integral"))
println(isAnagram("apple", "paper"))
println("listen".toList().sorted() == "silent".toList().sorted())
}Output
true true false true
Find duplicate elements in a list.
Example
fun main() {
val nums = listOf(4, 2, 7, 2, 9, 4, 4, 1)
val seen = mutableSetOf<Int>()
val dups = linkedSetOf<Int>()
for (n in nums) if (!seen.add(n)) dups.add(n)
println("Duplicates: $dups")
val counts = nums.groupingBy { it }.eachCount().filter { it.value > 1 }
println("With counts: $counts")
println("Without duplicates: ${nums.distinct()}")
}Output
Duplicates: [2, 4]
With counts: {4=3, 2=2}
Without duplicates: [4, 2, 7, 9, 1]Find the second largest number in a list in one pass.
Example
Track the largest and second largest; handle duplicates and lists with fewer than two distinct values.
fun secondLargest(nums: List<Int>): Int? {
var first: Int? = null
var second: Int? = null
for (n in nums) {
if (first == null || n > first) {
second = first
first = n
} else if (n != first && (second == null || n > second)) {
second = n
}
}
return second
}
fun main() {
println(secondLargest(listOf(12, 35, 1, 10, 34, 1)))
println(secondLargest(listOf(5, 5, 5)))
println(secondLargest(listOf(10, 10, 9)))
println(listOf(12, 35, 1, 10, 34).distinct().sortedDescending().getOrNull(1))
}Output
34 null 9 34
Two Sum: return the indices of two numbers that add up to a target.
Example
A HashMap from value to index gives O(n) time instead of the O(n²) nested loop.
fun twoSum(nums: IntArray, target: Int): Pair<Int, Int>? {
val indexOf = HashMap<Int, Int>()
for ((i, n) in nums.withIndex()) {
indexOf[target - n]?.let { return it to i }
indexOf[n] = i
}
return null
}
fun main() {
println(twoSum(intArrayOf(2, 7, 11, 15), 9))
println(twoSum(intArrayOf(3, 2, 4), 6))
println(twoSum(intArrayOf(1, 2), 10))
}Output
(0, 1) (1, 2) null
Check whether brackets in a string are balanced.
Example
Push opening brackets on a stack (ArrayDeque), pop and compare on closing ones.
fun isBalanced(s: String): Boolean {
val pairs = mapOf(')' to '(', ']' to '[', '}' to '{')
val stack = ArrayDeque<Char>()
for (c in s) {
when (c) {
'(', '[', '{' -> stack.addLast(c)
')', ']', '}' -> if (stack.removeLastOrNull() != pairs[c]) return false
}
}
return stack.isEmpty()
}
fun main() {
listOf("{[()]}", "([)]", "((", "fun main() { println(arr[0]) }").forEach {
println("$it -> ${isBalanced(it)}")
}
}Output
{[()]} -> true
([)] -> false
(( -> false
fun main() { println(arr[0]) } -> trueImplement an LRU cache.
Example
A LinkedHashMap with accessOrder = true moves an entry to the end on every access; overriding removeEldestEntry evicts the least recently used entry. Android has a ready-made android.util.LruCache used for image caches.
class LruCache<K, V>(private val capacity: Int) :
LinkedHashMap<K, V>(capacity, 0.75f, true) {
override fun removeEldestEntry(eldest: MutableMap.MutableEntry<K, V>?): Boolean =
size > capacity
}
fun main() {
val cache = LruCache<String, String>(3)
cache["home"] = "home.png"
cache["cart"] = "cart.png"
cache["profile"] = "profile.png"
cache["home"] // access: home becomes most recent
cache["orders"] = "orders.png" // evicts cart (least recently used)
println(cache.keys)
}Output
[profile, home, orders]
Fetch data from several APIs in parallel and combine the results.
Example
A classic Android coding question. async per call plus awaitAll() inside coroutineScope: if one call fails, the others are cancelled.
import kotlinx.coroutines.*
data class Profile(val name: String)
suspend fun fetchProfile(): Profile { delay(200); return Profile("Asha") }
suspend fun fetchOrders(): List<String> { delay(300); return listOf("#101", "#102") }
suspend fun fetchPrice(sku: String): Int { delay(100); return sku.length * 100 }
suspend fun loadDashboard(): String = coroutineScope {
val profile = async { fetchProfile() }
val orders = async { fetchOrders() }
val prices = listOf("pen", "laptop", "bag").map { sku -> async { fetchPrice(sku) } }.awaitAll()
"${profile.await().name} has ${orders.await().size} orders; cart total = ${prices.sum()}"
}
fun main(): Unit = runBlocking {
println(loadDashboard())
}Output
Asha has 2 orders; cart total = 1200