Mastering Coding Patterns in Kotlin
General
Mastering Coding Patterns in Kotlin
Akshay Nandwana
March 12, 2025
5 min read
167 views

As an Android Kotlin developer, understanding coding patterns is essential for writing clean, efficient, and scalable code. If you're preparing for coding interviews or just want to improve your problem-solving skills, mastering these patterns can significantly enhance your approach to problem-solving.

In this blog, we'll explore some fundamental coding patterns in Kotlin with real-world examples. These patterns are crucial for interviews and general software development.

1. Sliding Window Pattern

The sliding window pattern is useful for solving problems related to contiguous subarrays, substrings, and sequences.

Example: Maximum Sum Subarray of Size K

kotlin
fun maxSumSubarray(arr: IntArray, k: Int): Int {
    var maxSum = 0
    var windowSum = 0
    var start = 0

    for (end in arr.indices) {
        windowSum += arr[end]
        
        if (end >= k - 1) {
            maxSum = maxOf(maxSum, windowSum)
            windowSum -= arr[start]
            start++
        }
    }
    return maxSum
}

2. Two Pointers Pattern

This pattern is commonly used when dealing with sorted arrays or linked lists to find pairs that match a condition.

Example: Pair Sum in Sorted Array

kotlin
fun hasPairWithSum(arr: IntArray, target: Int): Boolean {
    var left = 0
    var right = arr.size - 1

    while (left < right) {
        val sum = arr[left] + arr[right]
        when {
            sum == target -> return true
            sum < target -> left++
            else -> right--
        }
    }
    return false
}

3. Fast & Slow Pointers Pattern

This pattern is useful for cycle detection in linked lists and similar structures.

Example: Detecting Cycle in Linked List

kotlin
class ListNode(val value: Int) {
    var next: ListNode? = null
}

fun hasCycle(head: ListNode?): Boolean {
    var slow = head
    var fast = head
    
    while (fast?.next != null) {
        slow = slow?.next
        fast = fast.next?.next
        if (slow == fast) return true
    }
    return false
}

4. Merge Intervals Pattern

This pattern is useful for interval-related problems, such as merging overlapping intervals.

Example: Merging Overlapping Intervals

kotlin
data class Interval(val start: Int, val end: Int)

fun mergeIntervals(intervals: List<Interval>): List<Interval> {
    if (intervals.isEmpty()) return emptyList()
    
    val sortedIntervals = intervals.sortedBy { it.start }
    val merged = mutableListOf(sortedIntervals[0])
    
    for (i in 1 until sortedIntervals.size) {
        val last = merged.last()
        val current = sortedIntervals[i]
        
        if (current.start <= last.end) {
            merged[merged.lastIndex] = Interval(last.start, maxOf(last.end, current.end))
        } else {
            merged.add(current)
        }
    }
    return merged
}

5. Backtracking Pattern

Backtracking is useful for problems like permutations, combinations, and solving puzzles.

Example: Generating All Subsets

kotlin
fun generateSubsets(nums: IntArray): List<List<Int>> {
    val result = mutableListOf<List<Int>>()
    fun backtrack(start: Int, current: MutableList<Int>) {
        result.add(ArrayList(current))
        for (i in start until nums.size) {
            current.add(nums[i])
            backtrack(i + 1, current)
            current.removeAt(current.size - 1)
        }
    }
    backtrack(0, mutableListOf())
    return result
}

6. Dynamic Programming (DP) Pattern

DP is a powerful technique for optimizing recursive solutions by storing intermediate results.

Example: Fibonacci Sequence Using Memoization

kotlin
fun fibonacci(n: Int, memo: MutableMap<Int, Int> = mutableMapOf()): Int {
    if (n <= 1) return n
    if (memo.containsKey(n)) return memo[n]!!
    
    memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo)
    return memo[n]!!
}

7. Greedy Algorithm Pattern

Greedy algorithms work by making the locally optimal choice at each step.

Example: Minimum Coins for Change

kotlin
fun minCoins(coins: IntArray, amount: Int): Int {
    coins.sortDescending()
    var remaining = amount
    var count = 0
    
    for (coin in coins) {
        if (remaining == 0) break
        count += remaining / coin
        remaining %= coin
    }
    return if (remaining == 0) count else -1
}

8. Graph Traversal Pattern

Graph algorithms often use BFS and DFS for traversal and search problems.

Example: BFS Traversal in Graph

kotlin
fun bfs(graph: Map<Int, List<Int>>, start: Int): List<Int> {
    val queue = ArrayDeque<Int>()
    val visited = mutableSetOf<Int>()
    val result = mutableListOf<Int>()
    
    queue.add(start)
    visited.add(start)
    
    while (queue.isNotEmpty()) {
        val node = queue.removeFirst()
        result.add(node)
        
        for (neighbor in graph[node] ?: emptyList()) {
            if (neighbor !in visited) {
                visited.add(neighbor)
                queue.add(neighbor)
            }
        }
    }
    return result
}

Here’s a comprehensive list of coding patterns commonly used in problem-solving and coding interviews:

Array & String Patterns

  1. Sliding Window

  2. Two Pointers

  3. Fast & Slow Pointers

  4. Merge Intervals

  5. Kadane’s Algorithm (Maximum Subarray)

  6. Dutch National Flag (Sort Colors)

  7. Cyclic Sort (Find Missing Numbers)

Recursion & Backtracking Patterns

  1. Backtracking (Subset, Permutation, Combination)

  2. Branch & Bound

  3. Divide and Conquer

Dynamic Programming (DP) Patterns

  1. Knapsack (0/1 & Unbounded)

  2. Fibonacci Series (Memoization & Tabulation)

  3. Longest Common Subsequence (LCS)

  4. Palindrome Partitioning

  5. Coin Change / Minimum Steps to Reduce a Number

Greedy Algorithm Patterns

  1. Activity Selection

  2. Huffman Encoding

  3. Interval Scheduling

  4. Job Scheduling with Deadlines

Graph Traversal Patterns

  1. Breadth-First Search (BFS)

  2. Depth-First Search (DFS)

  3. Dijkstra’s Algorithm (Shortest Path)

  4. Bellman-Ford Algorithm

  5. Floyd-Warshall Algorithm

  6. Topological Sorting (Kahn’s Algorithm)

  7. Union-Find (Detect Cycle in Graphs)

  8. Minimum Spanning Tree (Kruskal, Prim’s Algorithm)

Tree & Binary Search Patterns

  1. Binary Search

  2. Binary Search on Answer (Minimize Max Distance, Aggressive Cows)

  3. Inorder, Preorder, Postorder Traversal

  4. Lowest Common Ancestor (LCA)

  5. Trie (Prefix Tree) Usage

  6. Segment Tree / Fenwick Tree (Range Queries)

Heap & Priority Queue Patterns

  1. Top K Elements (Kth Largest, Kth Smallest)

  2. Median of a Stream

  3. Merge K Sorted Lists

Bit Manipulation Patterns

  1. XOR Manipulation (Find Missing Number, Single Non-Duplicate)

  2. Bitmask DP

Matrix Patterns

  1. Spiral Traversal

  2. Flood Fill (DFS/BFS in Grid)

  3. Matrix Exponentiation

This covers most of the major coding patterns used in problem-solving and interviews.

Conclusion

Understanding these patterns will help you write efficient, readable, and optimized Kotlin code. If you're preparing for interviews, mastering these patterns is crucial.

📢 Don't forget to share this with fellow developers and subscribe to my newsletter for more Kotlin and Android tips! 🚀


Akshay Nandwana
Founder
AndroidEngineers

You can connect with me on:


Book 1:1 Session here
Click Here

Join our upcoming classes
Our Courses