Kotlin Array Problems Cheat Sheet 🚀
This guide covers the most important Kotlin array & algorithm problems for interviews and coding practice. Each problem includes:
1️⃣ Reverse an Array
fun reverseArray(arr: IntArray) {
var start = 0
var end = arr.size - 1
while (start < end) {
val temp = arr[start] // **store arr[start] temporarily**
arr[start] = arr[end] // **swap arr[start] with arr[end]**
arr[end] = temp // **place temp at arr[end]**
start++ // **move start forward**
end-- // **move end backward**
}
}
fun main() {
val arr = intArrayOf(1, 2, 3, 4, 5)
reverseArray(arr)
println(arr.joinToString())
}
Output:
Input: [1, 2, 3, 4, 5]
Reversed: [5, 4, 3, 2, 1]
Time: O(n), Space: O(1)
2. Find Max & Min in Array
Scan the array once, updating min and max variables.
fun findMinMax(arr: IntArray): Pair<Int, Int> {
var min = arr[0]
var max = arr[0]
for (num in arr) {
if (num < min) min = num // **update min if smaller found**
if (num > max) max = num // **update max if larger found**
}
return Pair(min, max)
}
fun main() {
val arr = intArrayOf(3, 1, 7, 0, 9, 5)
val (min, max) = findMinMax(arr)
println("Min: $min, Max: $max")
}
Output:
Input: [3,1,7,0,9,5] → Min: 0, Max: 9
Time: O(n), Space: O(1)
3. Cyclically Rotate by 1
Store last element then shift all elements right by 1.
fun rotateByOne(arr: IntArray) {
val last = arr[arr.size - 1] // **store last**
for (i in arr.size - 1 downTo 1) {
arr[i] = arr[i - 1] // **shift right**
}
arr[0] = last // **place last at first**
}
fun main() {
val arr = intArrayOf(1,2,3,4,5)
rotateByOne(arr)
println(arr.joinToString())
}
Output:
Input: [1,2,3,4,5] → Rotated: [5,1,2,3,4]
Time: O(n), Space: O(1)
4. Move Negatives to One Side (Order Not Preserved)
Two-pointer swap: positives swapped with right pointer until all negatives on left.
fun moveNegativesOneSide(arr: IntArray) {
var left = 0
var right = arr.size - 1
while (left <= right) {
if (arr[left] < 0) left++ // **already negative**
else {
val temp = arr[left]
arr[left] = arr[right] // **swap positive with right**
arr[right] = temp
right-- // **move right backward**
}
}
}
fun main() {
val arr = intArrayOf(-1, 2, -3, 4, -5)
moveNegativesOneSide(arr)
println(arr.joinToString())
}
Output:
Input: [-1,2,-3,4,-5] → Example result: [-1,-5,-3,4,2] (order not guaranteed)
Time: O(n), Space: O(1)
5. Move Negatives (Order Preserved / Stable)
Use another array to copy negatives first then non-negatives (stable partition).
fun stableMoveNegatives(arr: IntArray): IntArray {
val result = IntArray(arr.size)
var idx = 0
for (v in arr) if (v < 0) result[idx++] = v // **add negatives**
for (v in arr) if (v >= 0) result[idx++] = v // **add non-negatives**
return result
}
fun main() {
val arr = intArrayOf(-1, 2, -3, 4, -5)
println(stableMoveNegatives(arr).joinToString())
}
Output:
Input: [-1,2,-3,4,-5] → Result: [-1,-3,-5,2,4]
Time: O(n), Space: O(n) (for result)
6. Rearrange +/- Alternately (O(1) extra space)
Find out-of-place indices and right-rotate subarray to place opposite-signed element — in-place and stable.
fun rearrangeAlternate(arr: IntArray) {
var outOfPlace = -1
for (i in arr.indices) {
if (outOfPlace >= 0) {
if ((arr[i] >= 0 && arr[outOfPlace] < 0) || (arr[i] < 0 && arr[outOfPlace] >= 0)) {
val temp = arr[i]
var j = i
while (j > outOfPlace) {
arr[j] = arr[j - 1] // **shift right**
j--
}
arr[outOfPlace] = temp // **place element**
outOfPlace = if (i - outOfPlace >= 2) outOfPlace + 2 else -1
}
} else {
if ((arr[i] >= 0 && i % 2 == 1) || (arr[i] < 0 && i % 2 == 0)) outOfPlace = i // **mark**
}
}
}
fun main() {
val arr = intArrayOf(-1, 3, -5, 6, -2, 4, -7, 8)
rearrangeAlternate(arr)
println(arr.joinToString())
}
Output:
Input: [-1,3,-5,6,-2,4,-7,8] → Example output: [-1,3,-5,6,-2,4,-7,8] (alternating; extras at end if counts differ)
Time: O(n^2) in worst-case due to shifts, Space: O(1)
7. Three-Way Partition Around a Value (Dutch National Flag)
Use low/mid/high pointers to partition into < pivot, == pivot, > pivot in one pass.
fun threeWayPartition(arr: IntArray, pivot: Int) {
var low = 0; var mid = 0; var high = arr.size - 1
while (mid <= high) {
when {
arr[mid] < pivot -> {
val tmp = arr[low]; arr[low] = arr[mid]; arr[mid] = tmp
low++; mid++
}
arr[mid] == pivot -> mid++
else -> {
val tmp = arr[mid]; arr[mid] = arr[high]; arr[high] = tmp
high--
}
}
}
}
fun main() {
val arr = intArrayOf(2,5,1,2,3,2,4)
threeWayPartition(arr, 2)
println(arr.joinToString())
}
Output:
Input: [2,5,1,2,3,2,4], pivot=2 → One valid result: [1,2,2,2,3,5,4]
Time: O(n), Space: O(1)
8. Minimum Swaps to Group Elements ≤ K Together
Sliding window: window size = count(elements ≤ K). Count bad elements (>K) in windows and take min.
fun minSwapsToGroup(arr: IntArray, k: Int): Int {
val windowSize = arr.count { it <= k }
var bad = arr.take(windowSize).count { it > k } // **bad in first window**
var minSwaps = bad
for (i in windowSize until arr.size) {
if (arr[i - windowSize] > k) bad-- // **outgoing**
if (arr[i] > k) bad++ // **incoming**
minSwaps = minOf(minSwaps, bad)
}
return minSwaps
}
fun main() {
val arr = intArrayOf(2,1,5,6,3)
println(minSwapsToGroup(arr, 3))
}
Output:
Input: [2,1,5,6,3], K=3 → Min swaps required: 1
Time: O(n), Space: O(1)
9. Merge Two Sorted Arrays In-Place (Gap Method)
Use gap = ceil((n+m)/2) and compare elements at distance gap, swapping when needed; reduce gap progressively.
fun nextGap(gap: Int): Int = if (gap <= 1) 0 else (gap + 1) / 2
fun mergeGap(arr1: IntArray, arr2: IntArray) {
var n = arr1.size; var m = arr2.size
var gap = nextGap(n + m)
while (gap > 0) {
var i = 0
while (i + gap < n) {
if (arr1[i] > arr1[i + gap]) { val t = arr1[i]; arr1[i] = arr1[i + gap]; arr1[i + gap] = t }
i++
}
var j = if (gap > n) gap - n else 0
while (i < n && j < m) {
if (arr1[i] > arr2[j]) { val t = arr1[i]; arr1[i] = arr2[j]; arr2[j] = t }
i++; j++
}
j = 0
while (j + gap < m) {
if (arr2[j] > arr2[j + gap]) { val t = arr2[j]; arr2[j] = arr2[j + gap]; arr2[j + gap] = t }
j++
}
gap = nextGap(gap)
}
}
fun main() {
val a1 = intArrayOf(1,4,7,8,10)
val a2 = intArrayOf(2,3,9)
mergeGap(a1, a2)
println(a1.joinToString() + " | " + a2.joinToString())
}
Output:
Input: arr1=[1,4,7,8,10], arr2=[2,3,9] → Merged view: arr1=[1,2,3,4,7], arr2=[8,9,10]
Time: O((n+m) log(n+m)) approx, Space: O(1)
10. Union of Two Sorted Arrays
Two-pointer traversal; add smaller element, handle equal elements once.
fun unionSorted(arr1: IntArray, arr2: IntArray): List<Int> {
var i = 0; var j = 0
val result = mutableListOf<Int>()
while (i < arr1.size && j < arr2.size) {
when {
arr1[i] < arr2[j] -> { result.add(arr1[i]); i++ }
arr1[i] > arr2[j] -> { result.add(arr2[j]); j++ }
else -> { result.add(arr1[i]); i++; j++ }
}
}
while (i < arr1.size) result.add(arr1[i++])
while (j < arr2.size) result.add(arr2[j++])
return result
}
fun main() {
val a = intArrayOf(1,3,4,5,7)
val b = intArrayOf(2,3,5,6)
println(unionSorted(a,b))
}
Output:
Input: [1,3,4,5,7] & [2,3,5,6] → Union: [1,2,3,3,4,5,5,6,7]
Time: O(n+m), Space: O(n+m)
11. Intersection of Two Sorted Arrays
Two-pointer traversal, add elements only when equal.
fun intersectionSorted(arr1: IntArray, arr2: IntArray): List<Int> {
var i=0; var j=0
val res = mutableListOf<Int>()
while (i < arr1.size && j < arr2.size) {
when {
arr1[i] < arr2[j] -> i++
arr1[i] > arr2[j] -> j++
else -> { res.add(arr1[i]); i++; j++ }
}
}
return res
}
fun main() {
val a = intArrayOf(1,3,4,5,7)
val b = intArrayOf(2,3,5,6)
println(intersectionSorted(a,b))
}
Output:
Input: [1,3,4,5,7] & [2,3,5,6] → Intersection: [3,5]
Time: O(n+m), Space: O(min(n,m))
12. Two Sum II (Sorted)
Two-pointer method utilising sorted property to find pair in O(n).
fun twoSumSorted(nums: IntArray, target: Int): Pair<Int,Int>? {
var l = 0; var r = nums.lastIndex
while (l < r) {
val s = nums[l] + nums[r]
if (s == target) return Pair(l+1, r+1) // 1-based
if (s < target) l++ else r--
}
return null
}
fun main() {
val nums = intArrayOf(2,7,11,15)
println(twoSumSorted(nums, 9))
}
Output:
Input: [2,7,11,15], target=9 → Indices (1-based): (1,2)
Time: O(n), Space: O(1)
13. Minimum Absolute Difference (Sorted)
In sorted arrays the minimal absolute difference is between consecutive elements.
fun minAbsDiff(sortedArr: IntArray): Int {
var minDiff = Int.MAX_VALUE
for (i in 0 until sortedArr.size - 1) {
minDiff = minOf(minDiff, kotlin.math.abs(sortedArr[i+1] - sortedArr[i])) // **consec diff**
}
return minDiff
}
fun main() {
val arr = intArrayOf(1,3,6,10,15)
println(minAbsDiff(arr))
}
Output:
Input: [1,3,6,10,15] → Minimum absolute difference = 2 (between 1 & 3)
Time: O(n), Space: O(1)
14. Max Sum Subarray of Size K (Fixed Window)
Sliding window: maintain a running sum for window size k and update max.
fun maxSumSubarray(arr: IntArray, k: Int): Int {
var windowSum = 0
var maxSum = Int.MIN_VALUE
for (i in 0 until k) windowSum += arr[i] // **initial window**
maxSum = windowSum
for (i in k until arr.size) {
windowSum += arr[i] - arr[i - k] // **slide**
maxSum = maxOf(maxSum, windowSum) // **update**
}
return maxSum
}
fun main() {
val arr = intArrayOf(2,1,5,1,3,2)
println(maxSumSubarray(arr, 3))
}
Output:
Input: [2,1,5,1,3,2], k=3 → Max sum = 9
Time: O(n), Space: O(1)
15. Best Time to Buy and Sell Stock I
Keep track of the minimum price seen so far and compute best profit by selling today.
fun maxProfit(prices: IntArray): Int {
var minPrice = Int.MAX_VALUE
var maxProfit = 0
for (p in prices) {
minPrice = minOf(minPrice, p) // **track min price**
maxProfit = maxOf(maxProfit, p - minPrice) // **update profit**
}
return maxProfit
}
fun main() {
val prices = intArrayOf(7,1,5,3,6,4)
println(maxProfit(prices))
}
Output:
Input: [7,1,5,3,6,4] → Max profit = 5 (buy at 1, sell at 6)
Time: O(n), Space: O(1)
16. Two Sum (HashMap)
Use a map to store seen numbers and their indices; check complement each iteration.
fun twoSum(nums: IntArray, target: Int): IntArray {
val map = mutableMapOf<Int, Int>()
for (i in nums.indices) {
val complement = target - nums[i]
if (map.containsKey(complement)) return intArrayOf(map[complement]!!, i)
map[nums[i]] = i
}
return intArrayOf()
}
fun main() {
val nums = intArrayOf(2,7,11,15)
println(twoSum(nums, 9).joinToString())
}
Output:
Input: [2,7,11,15], target=9 → Indices (0-based): [0,1]
Time: O(n), Space: O(n)
17. Move Zeroes (Alternative swap-based)
Swap non-zero with left pointer to minimize writes.
fun moveZeroesSwap(nums: IntArray) {
var left = 0
for (right in nums.indices) {
if (nums[right] != 0) {
val t = nums[left]; nums[left] = nums[right]; nums[right] = t // **swap**
left++
}
}
}
fun main() {
val nums = intArrayOf(0,1,0,3,12)
moveZeroesSwap(nums)
println(nums.joinToString())
}
Output:
Input: [0,1,0,3,12] → Result: [1,3,12,0,0]
Time: O(n), Space: O(1)
18. Remove Duplicates from Sorted Array
Use two pointers: write pointer for last unique element.
fun removeDuplicates(nums: IntArray): Int {
if (nums.isEmpty()) return 0
var write = 0
for (read in 1 until nums.size) {
if (nums[read] != nums[write]) {
write++
nums[write] = nums[read] // **store unique**
}
}
return write + 1
}
fun main() {
val nums = intArrayOf(1,1,2,2,3,4,4,5)
val newLen = removeDuplicates(nums)
println("NewLen: $newLen, Unique array: ${nums.take(newLen)}")
}
Output:
Input: [1,1,2,2,3,4,4,5] → NewLen: 5, Unique: [1,2,3,4,5]
Time: O(n), Space: O(1)
19. Range Sum Query – Immutable (Prefix Sum)
Precompute prefix sums so range queries are O(1).
class NumArray(nums: IntArray) {
private val prefix = IntArray(nums.size + 1)
init {
for (i in nums.indices) prefix[i+1] = prefix[i] + nums[i] // **build prefix**
}
fun sumRange(l: Int, r: Int) = prefix[r+1] - prefix[l] // **range sum**
}
fun main() {
val na = NumArray(intArrayOf(-2,0,3,-5,2,-1))
println(na.sumRange(0,2))
}
Output:
Input: [-2,0,3,-5,2,-1], sumRange(0,2) → 1
Preprocess: O(n), Query: O(1), Space: O(n)
20. Single Number (XOR)
XOR all numbers; duplicates cancel each other leaving single number.
fun singleNumber(nums: IntArray): Int {
var res = 0
for (n in nums) res = res xor n // **duplicates cancel**
return res
}
fun main() {
val nums = intArrayOf(4,1,2,1,2)
println(singleNumber(nums))
}
Output:
Input: [4,1,2,1,2] → Single number: 4
Time: O(n), Space: O(1)
21. Missing Number
Use sum formula or XOR to find the missing number from 0..n.
fun missingNumber(nums: IntArray): Int {
val n = nums.size
val total = n * (n + 1) / 2
return total - nums.sum() // **missing = total - actual**
}
fun main() {
val nums = intArrayOf(3,0,1)
println(missingNumber(nums))
}
Output:
Input: [3,0,1] → Missing number: 2
Time: O(n), Space: O(1)
22. Find All Numbers Disappeared in an Array
Mark visited indices by negation; positive entries at the end correspond to missing numbers.
fun findDisappearedNumbers(nums: IntArray): List<Int> {
for (i in nums.indices) {
val idx = kotlin.math.abs(nums[i]) - 1
if (nums[idx] > 0) nums[idx] = -nums[idx] // **mark visited**
}
val res = mutableListOf<Int>()
for (i in nums.indices) if (nums[i] > 0) res.add(i + 1) // **positive -> missing**
return res
}
fun main() {
val nums = intArrayOf(4,3,2,7,8,2,3,1)
println(findDisappearedNumbers(nums))
}
Output:
Input: [4,3,2,7,8,2,3,1] → Missing: [5,6]
Time: O(n), Space: O(1) (excluding output list)
23. Find Kth Missing Positive Number
Traverse natural numbers and array pointers to count missing numbers until k-th is found.
fun findKthPositive(arr: IntArray, k: Int): Int {
var missing = k
var current = 1
var i = 0
while (true) {
if (i < arr.size && arr[i] == current) i++ // **present**
else {
missing-- // **missing**
if (missing == 0) return current
}
current++
}
}
fun main() {
val arr = intArrayOf(2,3,4,7,11)
println(findKthPositive(arr, 5))
}
Output:
Input: [2,3,4,7,11], k=5 → 9
Time: O(n + k), Space: O(1)
24. Next Greater Element I
Use a monotonic stack to compute the next greater for all elements in nums2, then map answers for nums1.
fun nextGreaterElement(nums1: IntArray, nums2: IntArray): IntArray {
val map = mutableMapOf<Int, Int>()
val stack = ArrayDeque<Int>()
for (n in nums2) {
while (stack.isNotEmpty() && stack.last() < n) {
map[stack.removeLast()] = n // **map smaller -> next greater**
}
stack.addLast(n)
}
while (stack.isNotEmpty()) map[stack.removeLast()] = -1
return nums1.map { map[it] ?: -1 }.toIntArray()
}
fun main() {
val nums1 = intArrayOf(4,1,2)
val nums2 = intArrayOf(1,3,4,2)
println(nextGreaterElement(nums1, nums2).joinToString())
}
Output:
Input: nums1=[4,1,2], nums2=[1,3,4,2] → Output: [-1,3,-1]
Time: O(n + m), Space: O(n)