Mastering Coding Patterns in Kotlin

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

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

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

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

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

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

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

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

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

Love from our past students

Excellent list of questions really helped me to coverup all the topics before interview.

Saiteja Janjirala

10th Oct, 2024

I had an exceptional experience with the 1:1 mentorship session. Akshay was incredibly friendly and provided invaluable guidance on focusing on long-term goals. They also gave great interview tips, including a thorough resume review. Additionally, the discussion on Data Structures and Algorithms (DSA) was insightful and practical. Highly recommended for anyone looking to advance their career!

Nayab khan

11th Sep, 2024

Cleared my major points for what I am missing in the resume and also suggested what I can work on for further growth in the career.

Ketan Chaurasiya

7th Aug, 2024

What impressed me most was his personalized approach and practical tips that I could immediately apply. Akshay’s guidance not only improved my technical skills but also boosted my confidence in navigating my career path. His insights and encouragement have been a game-changer for me. I highly recommend Akshay’s mentorship to anyone looking to advance their Android development career.

Hardik Kubavat

5th Aug, 2024

2025© Made with   by Android Engineers.