DSA in Kotlin

Doubly Linked List in Kotlin

Doubly Linked List in Kotlin: Real-World Use Cases and Code Snippets

When working with data structures in Kotlin, arrays and lists often come to mind first. They’re built-in, simple, and cover most scenarios. But sometimes you need more control over how elements are connected, inserted, or removed. That’s where a Doubly Linked List in Kotlin shines.

In this blog, we’ll explore what a doubly linked list is, why it’s useful, real-world applications, and most importantly — how to implement one in Kotlin.

Doubly Linked List in Kotlin

A doubly linked list is a data structure made up of nodes. Each node stores three things:

  1. Data — the actual value.
  2. A reference to the next node.
  3. A reference to the previous node.

This dual-link system allows navigation forward and backward through the list. That’s the main difference from a singly linked list, which only moves forward.

Why Use a Doubly Linked List in Kotlin?

You might ask: “Why bother with a doubly linked list when Kotlin already has List and MutableList?”

Here are a few reasons:

  • Fast insertions and deletions: Unlike arrays, you don’t need to shift elements when adding or removing.
  • Bidirectional traversal: You can move in both directions, which can be handy in scenarios like undo/redo features.
  • Custom data structures: Sometimes you want full control over memory and connections.

Real-World Use Cases

Let’s look at where a Doubly Linked List in Kotlin can be practical:

  • Browser history navigation (go back and forward between pages).
  • Undo/Redo operations in editors.
  • Music playlists where you can jump to the previous or next song.
  • Deque (Double-Ended Queue) implementations for efficient queue operations.

Implementing a Doubly Linked List in Kotlin

Let’s write a clean, easy-to-follow implementation.

Define the Node

Java
class Node<T>(
    var data: T,
    var prev: Node<T>? = null,
    var next: Node<T>? = null
)

Here, Node is generic (<T>) so it can store any type (Int, String, custom objects, etc.). Each node keeps track of its data, the previous node (prev), and the next node (next).

Create the DoublyLinkedList Class

Java
class DoublyLinkedList<T> {
    private var head: Node<T>? = null
    private var tail: Node<T>? = null

    fun isEmpty() = head == null
}

We keep track of two references:

  • head → the first node.
  • tail → the last node.

Add Elements

Let’s add items to the end of the list.

Java
fun append(data: T) {
    val newNode = Node(data)

    if (head == null) {
        head = newNode
        tail = newNode
    } else {
        tail?.next = newNode
        newNode.prev = tail
        tail = newNode
    }
}
  • If the list is empty, both head and tail point to the new node.
  • Otherwise, we connect the new node after the current tail and update tail.

Prepend Elements

Adding to the beginning works similarly:

Kotlin
fun prepend(data: T) {
    val newNode = Node(data)

    if (head == null) {
        head = newNode
        tail = newNode
    } else {
        newNode.next = head
        head?.prev = newNode
        head = newNode
    }
}

Remove Elements

Removing a node requires updating both previous and next references.

Kotlin
fun remove(data: T) {
    var current = head

    while (current != null) {
        if (current.data == data) {
            if (current.prev != null) {
                current.prev?.next = current.next
            } else {
                head = current.next
            }

            if (current.next != null) {
                current.next?.prev = current.prev
            } else {
                tail = current.prev
            }
            break
        }
        current = current.next
    }
}

Here we search for the node, reconnect neighbors around it, and update head or tail if needed.

Print the List

For debugging, let’s add a print function.

Kotlin
fun printForward() {
    var current = head
    while (current != null) {
        print("${current.data} ")
        current = current.next
    }
    println()
}

fun printBackward() {
    var current = tail
    while (current != null) {
        print("${current.data} ")
        current = current.prev
    }
    println()
}

Full Example in Action

Before running the code, make sure all the above functions are inside the DoublyLinkedList<T> class.

Kotlin
fun main() {
    val list = DoublyLinkedList<Int>()

    list.append(10)
    list.append(20)
    list.append(30)
    list.prepend(5)

    println("Forward traversal:")
    list.printForward()

    println("Backward traversal:")
    list.printBackward()

    println("Removing 20...")
    list.remove(20)
    list.printForward()
}

Output:

Kotlin
Forward traversal:
5 10 20 30 
Backward traversal:
30 20 10 5 
Removing 20...
5 10 30 

Conclusion

A Doubly Linked List in Kotlin gives you more control when working with dynamic data. While Kotlin’s standard library handles most needs with List or MutableList, knowing how to build and use a doubly linked list can be a powerful skill.

You now know:

  • What a doubly linked list is.
  • Real-world scenarios where it’s useful.
  • How to implement it step by step in Kotlin.

This structure shines in apps where insertion, deletion, or bidirectional navigation matters — like history tracking, playlists, or undo/redo stacks.

Kotlin Insertion Sort Algorithm

Kotlin Insertion Sort Algorithm: Step-by-Step Guide with Code

Sorting is a fundamental part of programming. Whether you’re working with numbers, strings, or custom objects, knowing how sorting algorithms work builds your understanding of how data is organized behind the scenes. In this guide, we’ll explore the Kotlin Insertion Sort algorithm in detail, walking through its logic and code.

What Is Insertion Sort?

Insertion sort is one of the simplest sorting algorithms. It works the same way many people sort playing cards:

  • Start with the first card in your hand.
  • Pick the next card and insert it into the right position among the already sorted cards.
  • Repeat this until all cards are sorted.

In other words, insertion sort builds the sorted list one element at a time.

Why Learn Insertion Sort in Kotlin?

While Kotlin offers built-in sorting functions like sorted() or sortBy(), understanding Kotlin Insertion Sort helps you:

  • Learn the logic behind sorting.
  • Improve problem-solving and algorithmic thinking.
  • Understand time complexity (important in interviews).
  • Get hands-on with Kotlin basics like loops, arrays, and variables.

How Insertion Sort Works: Step-by-Step

Let’s break it down:

  1. Start with the second element of the array (since the first element is already “sorted”).
  2. Compare it with the elements before it.
  3. If it’s smaller, shift the larger element one position to the right.
  4. Insert the element into the correct position.
  5. Repeat for all elements until the entire array is sorted.

Kotlin Insertion Sort Code

Here’s a clean implementation of the algorithm in Kotlin:

Kotlin
fun insertionSort(arr: IntArray) {
    val n = arr.size
    for (i in 1 until n) {
        val key = arr[i]
        var j = i - 1

        // Move elements greater than key one step ahead
        while (j >= 0 && arr[j] > key) {
            arr[j + 1] = arr[j]
            j--
        }
        arr[j + 1] = key
    }
}

fun main() {
    val numbers = intArrayOf(9, 5, 1, 4, 3)
    println("Before sorting: ${numbers.joinToString()}")

    insertionSort(numbers)

    println("After sorting: ${numbers.joinToString()}")
}
  • fun insertionSort(arr: IntArray) → We define a function that takes an integer array as input.
  • for (i in 1 until n) → Loop starts from index 1 (since index 0 is already “sorted”).
  • val key = arr[i] → The current element we want to insert in the right position.
  • while (j >= 0 && arr[j] > key) → Shift elements greater than key one step forward.
  • arr[j + 1] = key → Place the element in its correct spot.

The main function demonstrates sorting an array [9, 5, 1, 4, 3].

  • Before sorting: 9, 5, 1, 4, 3
  • After sorting: 1, 3, 4, 5, 9

Time Complexity of Insertion Sort

  • Best Case (Already Sorted): O(n)
  • Worst Case (Reverse Sorted): O(n²)
  • Average Case: O(n²)

Insertion sort is not the most efficient for large datasets, but it works well for small arrays and nearly sorted data.

Advantages of Kotlin Insertion Sort

  • Easy to implement and understand.
  • Works efficiently for small or nearly sorted data.
  • Stable algorithm (keeps equal elements in the same order).
  • In-place sorting (doesn’t require extra memory).

When to Use Insertion Sort in Kotlin

  • For small data sets where performance isn’t critical.
  • When you expect the data to be almost sorted.
  • For educational purposes to build a strong foundation in sorting.

Conclusion

The Kotlin Insertion Sort algorithm is a simple yet powerful way to understand sorting from the ground up. While you’ll often rely on Kotlin’s built-in sorting functions in real-world applications, practicing with insertion sort sharpens your coding skills and deepens your understanding of algorithm design.

By walking through the logic step by step and testing with code, you’ve now got a solid grasp of how insertion sort works in Kotlin.

Binary Trees in Kotlin

Mastering Binary Trees in Kotlin: From Basics to Advanced

When you start learning data structures in Kotlin, one of the most useful (and surprisingly elegant) structures you’ll come across is the binary tree. Whether you’re preparing for coding interviews, working on algorithms, or building efficient applications, Binary Trees in Kotlin are a must-have tool in your developer toolkit.

In this post, we’ll take deep dive into binary trees — starting from the basics, moving into real Kotlin code, and exploring advanced concepts. By the end, you’ll not only understand them but also know how to implement and apply them in real-world scenarios.

What Is a Binary Tree?

A binary tree is a hierarchical data structure where each node has at most two children:

  • Left child
  • Right child

The top node is called the root, and the last nodes with no children are called leaves.

Why use binary trees? Because they make searching, sorting, and organizing data efficient. Structures like Binary Search Trees (BST), heaps, and even syntax parsers in compilers rely on binary trees under the hood.

Defining a Binary Tree in Kotlin

Kotlin makes it easy to define data structures using classes. Let’s start simple:

Kotlin
// Node of a binary tree
class TreeNode<T>(val value: T) {
    var left: TreeNode<T>? = null
    var right: TreeNode<T>? = null
}

Here,

  • Each node stores a value.
  • It can have a left child and a right child.
  • We’re using generics (<T>) so the tree can hold any type of data (Int, String, custom objects, etc.).

This flexible design means we can now create and connect nodes to form a tree.

Building a Simple Binary Tree

Let’s create a small binary tree manually:

Kotlin
fun main() {
    val root = TreeNode(10)
    root.left = TreeNode(5)
    root.right = TreeNode(15)

    root.left?.left = TreeNode(2)
    root.left?.right = TreeNode(7)

    println("Root: ${root.value}")
    println("Left Child: ${root.left?.value}")
    println("Right Child: ${root.right?.value}")
}

This represents the tree:

Kotlin
        10
       /  \
      5    15
     / \
    2   7

Run the program, and you’ll see the root and children values printed. Easy, right?

Traversing Binary Trees in Kotlin

Traversal means visiting each node in a specific order. Three main types exist:

  1. Inorder (Left → Root → Right)
  2. Preorder (Root → Left → Right)
  3. Postorder (Left → Right → Root)

Here’s how we can implement them in Kotlin:

Kotlin
fun inorder(node: TreeNode<Int>?) {
    if (node != null) {
        inorder(node.left)
        print("${node.value} ")
        inorder(node.right)
    }
}

fun preorder(node: TreeNode<Int>?) {
    if (node != null) {
        print("${node.value} ")
        preorder(node.left)
        preorder(node.right)
    }
}

fun postorder(node: TreeNode<Int>?) {
    if (node != null) {
        postorder(node.left)
        postorder(node.right)
        print("${node.value} ")
    }
}
  • Inorder traversal (for a Binary Search Tree) gives sorted output.
  • Preorder is useful for copying or serializing the tree.
  • Postorder is used in deleting trees safely or evaluating expressions.

Binary Search Tree (BST) in Kotlin

A Binary Search Tree is a special type of binary tree where:

  • Left child values are smaller than the parent.
  • Right child values are greater than the parent.

Here’s a simple insert function:

Kotlin
fun insert(node: TreeNode<Int>?, value: Int): TreeNode<Int> {
    if (node == null) return TreeNode(value)

    if (value < node.value) {
        node.left = insert(node.left, value)
    } else if (value > node.value) {
        node.right = insert(node.right, value)
    }

    return node
}

Usage:

Kotlin
fun main() {
    var root: TreeNode<Int>? = null
    val values = listOf(10, 5, 15, 2, 7)

    for (v in values) {
        root = insert(root, v)
    }

    println("Inorder Traversal (sorted):")
    inorder(root)
}

This builds the same tree as before, but dynamically by inserting values.

Advanced: Balancing and Height of Trees

Binary trees can get skewed if values are inserted in sorted order. For example, inserting 1, 2, 3, 4, 5 creates a “linked list” shaped tree, which defeats the efficiency.

That’s where balanced trees (like AVL Trees or Red-Black Trees) come into play. While implementing them from scratch is complex, so, understanding the height of a tree is the first step:

Kotlin
fun height(node: TreeNode<Int>?): Int {
    if (node == null) return 0
    return 1 + maxOf(height(node.left), height(node.right))
}

Height helps us measure balance:

  • In an AVL Tree, the heights of the left and right subtrees of any node can differ by at most 1.
  • In a Red-Black Tree, balance is maintained using color properties and black-height rules.

Thus, height is foundational for understanding balance, though balanced trees enforce it using additional rules and (sometimes) rotations.

Real-World Applications of Binary Trees

Binary trees aren’t just academic exercises. They’re used in:

  • Databases (indexing and searching)
  • Compilers (syntax parsing using expression trees)
  • Games (AI decision-making with decision trees)
  • Networking (routing tables)

So, mastering binary trees in Kotlin gives you both practical coding skills and deeper algorithmic insight.

Conclusion

Binary trees may look intimidating at first, but with Kotlin’s clean syntax and strong type system, they become intuitive and fun to implement. From simple trees to Binary Search Trees and beyond, you now have a solid foundation.

Next time you see a coding challenge or need to optimize a search algorithm, you’ll know exactly how to leverage Binary Trees in Kotlin.

Linked List

How to Create a Linked List in Kotlin: Easy Step-by-Step Tutorial

If you’re diving into the world of Kotlin and exploring data structures, you’ve probably come across linked lists. While arrays and lists are common in Kotlin development, understanding linked lists can open up new levels of flexibility in your coding journey. In this guide, we’ll unravel what linked lists are, why you might need them, and most importantly, how to create and use linked lists in Kotlin.

What is a Linked List?

A Linked List is a data structure consisting of a sequence of elements, called nodes. 

Each node has two components:

  • Data: The value we want to store.
  • Next: A reference to the next node in the sequence.

Unlike arrays, Linked Lists are dynamic in size, offering efficient insertions and deletions at any position in the list.

In a linked list, each node stores a value and points to the next node in the chain. The last node in the sequence points to “null,” indicating the end of the list.

Linked lists have several advantages over arrays or ArrayLists in Kotlin:

  • Quick insertions and removals at the front of the list.
  • Consistent performance for operations, especially for inserting or removing elements anywhere in the list.

Types of Linked Lists

  1. Singly Linked List — Each node points to the next node in the sequence (we’ll focus on this one).
  2. Doubly Linked List — Each node has a reference to both the next and the previous node.
  3. Circular Linked List — The last node points back to the first node, forming a loop.

Building a Singly Linked List in Kotlin

Kotlin doesn’t offer a built-in linked list class like Java does. But no worries! We’re going to create our own custom Singly Linked List step-by-step. Let’s create a linked list from scratch! We’ll start by defining the Node class and then build a LinkedList class to manage the nodes.

Defining the Node Class

Each node needs to store data and a reference to the next node. Here’s our Node class:

Kotlin
// We define a node of the linked list as a data class, where it holds a value and a reference to the next node.

data class Node<T>(var value: T, var next: Node<T>? = null) {
    override fun toString(): String {
        return if (next != null) "$value -> ${next.toString()}" else "$value"
    }
}

fun main() {
    val node1 = Node(value = 1)
    val node2 = Node(value = 2)
    val node3 = Node(value = 3)

    node1.next = node2
    node2.next = node3   //here node3 points to null at last, as per our code we only print its value
    println(node1)
}

//OUTPUT

1 -> 2 -> 3

Here, we defined a generic Node class for a linked list in Kotlin. Each Node holds a value of any type (T) and a reference to the next Node, which can be null. The toString() method provides a custom string representation for the node, recursively displaying the value of the node followed by the values of subsequent nodes, separated by ->. If the node is the last in the list, it simply shows its value.

Have you observed how we constructed the list above? We essentially created a chain of nodes by linking their ‘next’ references. However, building lists in this manner becomes impractical as the list grows larger. To address this, we can use a LinkedList, which simplifies managing the nodes and makes the list easier to work with. Let’s explore how we can implement this in Kotlin.

Creating the LinkedList Class

Let’s create our LinkedList class and add core functionalities like adding nodes and displaying the list.

Basically, a linked list has a ‘head’ (the first node) and a ‘tail’ (the last node). In a singly linked list, we usually only deal with the head node, although the tail node can also be relevant, especially when adding elements at the end. The tail node becomes more important in doubly linked lists or circular linked lists, where it supports bidirectional traversal or maintains circular references. However, here, we will use both nodes in a singly linked list.

Kotlin
class LinkedList<T> {
    private var head: Node<T>? = null
    private var tail: Node<T>? = null
    private var size = 0

    // Method to check if the list is empty
    fun isEmpty(): Boolean = size == 0
    
     // to print nodes in linkedlist
    override fun toString(): String {
        if (isEmpty()) {
            return "Empty list"
        } else {
            return head.toString()
        }
    }
}

Here, a linked list has a ‘head’ (the first node) and a ‘tail’ (the last node). We’ll also store the list’s size in a ‘size’ property.

Now, to use this linked list, we need to store or add some values to it. Otherwise, we’d only be using an empty list. There are three major operations for adding values to a linked list, and we’ll explore each one in more details in the next blog. First, let’s see how to add a new value (or node) to the linked list and then print the result.

Kotlin
// Method to add a new node at the beginning
fun addFirst(data: T) {
    val newNode = Node(data)
    newNode.next = head
    head = newNode
    size++
}

Here, we first create a new node with the passed value. Then, the new node’s next points to the head, and finally, we update the head to point to the newly created node. The same process is repeated whenever we add a new value.

Note: Whenever a new value is added, the list size increases. Therefore, we need to increment the size accordingly.

Now, let’s look at the complete code.

Kotlin
class LinkedList<T> {
    private var head: Node<T>? = null
    private var tail: Node<T>? = null
    private var size = 0

    // Method to check if the list is empty
    fun isEmpty(): Boolean = size == 0

    // to print nodes in linkedlist
    override fun toString(): String {
        if (isEmpty()) {
            return "Empty list"
        } else {
            return head.toString()
        }
    }

    // Method to add a new node at the beginning
    fun addFirst(data: T) {
        val newNode = Node(data)
        newNode.next = head
        head = newNode
        size++
    }
}

Using the Linked List in Kotlin

Let’s put our linked list to the test! Here’s how we can use the LinkedList class:

Kotlin
fun main() {
    val myList = LinkedList<String>()

    println("Is the list empty? ${myList.isEmpty()}")

    myList.addFirst("Kotlin")
    myList.addFirst("Hello")
   
    println(myList) // Output: Hello -> Kotlin -> null

    println("Is the list empty? ${myList.isEmpty()}")
}

Output

Kotlin
Is the list empty? true
Hello -> Kotlin
Is the list empty? false

Conclusion

We’ve explored the key insertion operations in linked lists, along with the foundational concepts and structure that make them an essential part of data management. Understanding these operations provides a solid base for working with linked lists in various scenarios. 

Linked lists might seem daunting, but with a bit of practice, you’ll be using them like a pro.

Fibonacci in Kotlin

Fibonacci in Kotlin: Recursion, Loops & Dynamic Programming (Complete Guide)

The Fibonacci sequence isn’t just math trivia — it’s a timeless example used in coding interviews, algorithm practice, and real-world software optimization. In this guide, we’ll explore how to implement Fibonacci in Kotlin using: Recursion — Easy to grasp, but not the fastest. Loops — Simple and efficient. Dynamic Programming — Optimized for large numbers. What is the Fibonacci Sequence? The Fibonacci sequence...

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
Generate All Permutations of a String

How to Generate All Permutations of a String in Kotlin — Fast O(n) Approach (Handles Duplicates + Large Input Tips)

When most developers search for Generate All Permutations of a String, they find solutions that work but are often slow, overly complex, or hard to read.

Today, we’re going to cut through the noise and build a simple, fast, and easy-to-understand Kotlin solution that runs in O(n) time per permutation — which is as efficient as it gets.

We’ll cover:

  • What permutations actually are
  • Why naive solutions are slow
  • The O(n) approach using in-place swapping
  • Clean Kotlin code with full explanation

What Is a String Permutation?

A permutation is simply a different arrangement of the same characters.

For example, the string "ABC" has these permutations:

Kotlin
ABC, ACB, BAC, BCA, CAB, CBA

If a string has n unique characters, there are exactly n! permutations.

e.g 4!=4×3×2×1=24

That means 3 characters → 6 permutations, 4 characters → 24 permutations, and so on.

Why We Need an O(n) Approach

Many beginner solutions to generate all permutations of a string use recursion with string concatenation. That works, but it creates a lot of unnecessary string objects in memory — making it slow for larger strings.

We can do better by:

  • Avoiding extra strings (working on a mutable list of characters instead)
  • Swapping in-place to generate permutations
  • Recursing efficiently without repeated slicing or copying

This gives us O(n) work per permutation instead of heavier O(n²) string-building overhead.

The In-Place Swapping Algorithm

Here’s the idea:

  1. Convert the string into a mutable character array.
  2. Recursively swap the current index with each possible next character.
  3. When we reach the end, print or store the permutation.
  4. Swap back to restore the original state (backtracking).

By doing swaps in-place, we avoid creating new arrays or strings at each step.

Kotlin Implementation

Kotlin
fun generateUniquePermutations(str: String) {
    val chars = str.toCharArray().sortedArray() // Sort to group duplicates
    permuteUnique(chars, 0)
}

private fun permuteUnique(chars: CharArray, index: Int) {
    if (index == chars.size - 1) {
        println(String(chars))
        return
    }

    val seen = mutableSetOf<Char>()

    for (i in index until chars.size) {
        if (chars[i] in seen) continue // Skip duplicate characters
        seen.add(chars[i])
        swap(chars, index, i)          // Place chosen char at 'index'
        permuteUnique(chars, index + 1) // Recurse
        swap(chars, index, i)          // Backtrack
    }
}

private fun swap(chars: CharArray, i: Int, j: Int) {
    val temp = chars[i]
    chars[i] = chars[j]
    chars[j] = temp
}

fun main() {
    generateUniquePermutations("AAB")
}

How This Code Works

Let’s break it down:

generatePermutations

  • Converts the input string to a CharArray so we can modify it directly.
  • Starts recursion from the first index.

permute

  • Base case: If index is at the last character, we’ve found a full permutation, so we print it.
  • Loop: Swap the current index with every possible position (including itself).
  • Recursion: Move to the next index and repeat.
  • Backtrack: Swap back so the next iteration starts with the original order.

swap

  • Simple character swap using a temporary variable.
  • Works in constant time O(1).

Time Complexity

This program generates all permutations of a given string.
 If the string length is n:

  • The number of permutations = n!

For each permutation, the code does:

  • A series of swaps (O(1) each)
  • Recursive calls that together visit all permutations.

The total work is proportional to n × n! because:

  • At each permutation, you spend O(n) to print the result (constructing String(chars) is O(n)).
  • The recursive structure ensures we visit all n! permutations.

So:

T(n)=O(n×n!)

Space Complexity

There are two aspects:

Auxiliary space (call stack):

  • The recursion depth is n (one frame for each index position).
  • Each frame holds constant space aside from parameters and local variables.
  • So the recursion stack = O(n).

Extra storage:

  • You store the characters in a CharArray (size n).
  • No extra big data structures are used.
  • Output printing doesn’t count toward auxiliary space complexity (it’s external).

Thus:

S(n)=O(n)

(excluding the space needed for the output itself).

Why This Is O(n) Per Permutation

Each recursive level only requires:

  • One swap (O(1))
  • One swap back (O(1))
  • A constant amount of work for printing or storing

That’s O(n) for each permutation generated, which is optimal — you can’t generate n! permutations faster than that.

Benefits of This Approach

 Fast — avoids extra string copies
 Memory efficient — works in-place
 Readable — short and clear code
 Scalable — handles larger strings without choking your CPU

Output

Running generatePermutations("ABC") gives:

Kotlin
ABC
ACB
BAC
BCA
CBA
CAB

Exactly all possible permutations — no duplicates, no missing ones.

Handling Duplicate Characters

Without extra care, "AAB" will produce duplicate outputs.

To fix this:

  • Sort the characters first so duplicates are adjacent.
  • At each recursion level, use a Set<Char> to skip duplicates.

Kotlin Implementation (Fast + Duplicate-Safe)

Kotlin
fun generateUniquePermutations(str: String) {
    val chars = str.toCharArray().sortedArray() // Sort to group duplicates
    permuteUnique(chars, 0)
}

private fun permuteUnique(chars: CharArray, index: Int) {
    if (index == chars.size - 1) {
        println(String(chars))
        return
    }

    val seen = mutableSetOf<Char>()

    for (i in index until chars.size) {
        if (chars[i] in seen) continue // Skip duplicate characters
        seen.add(chars[i])
        swap(chars, index, i)          // Place chosen char at 'index'
        permuteUnique(chars, index + 1) // Recurse
        swap(chars, index, i)          // Backtrack
    }
}

private fun swap(chars: CharArray, i: Int, j: Int) {
    val temp = chars[i]
    chars[i] = chars[j]
    chars[j] = temp
}

fun main() {
    generateUniquePermutations("AAB")
}

For "AAB", output is:

Kotlin
AAB
ABA
BAA

— unique, no duplicates.

Wait, what if we used all 26 characters? Hmm… actually, let’s just go with 25. 

There are a few limitations we need to talk about.

Limitations & Large Input Handling

Even with an O(n) per permutation algorithm, the total permutations grow as n! (factorial).


 For "ABCDEFGHIJKLMNOPQRSTUWXYZ" (25 characters):

25!≈1.55×10²⁵ permutations

This number is so huge that:

  • You can’t generate all permutations in your lifetime.
  • You can’t store them — it would require trillions of terabytes.
  • Even printing them will eventually cause OutOfMemoryError in the JVM because the output stream and StringBuilder can’t keep up.

How to Avoid Crashes for Large Strings

  1. Generate Lazily (Streaming)
     Use Kotlin sequences to yield one permutation at a time:
Kotlin
fun permutationsSequence(chars: CharArray, index: Int = 0): Sequence<String> = sequence {
    if (index == chars.size - 1) {
        yield(String(chars))
    } else {
        for (i in index until chars.size) {
            swap(chars, index, i)
            yieldAll(permutationsSequence(chars, index + 1))
            swap(chars, index, i)
        }
    }
}

With this, you process each permutation immediately, instead of storing them.

2. Limit Output
 If you just need the first k permutations:

Kotlin
var count = 0
val maxCount = 1000
for (p in permutationsSequence("ABCDEFGHIJKLMNOP".toCharArray())) {
    println(p)
    if (++count >= maxCount) break
}

3. Use Next-Permutation Algorithm
 Instead of generating all permutations at once, generate only the next one on demand — useful for lexicographic iteration without memory blow-up.

Why This Approach Stands Out

O(n) time per permutation — optimal.
Memory-friendly with in-place swaps.
Duplicate-safe.
Large input advice so you don’t crash your program.

Conslusion

If you need to generate all permutations of a string in Kotlin, the in-place swapping method is your best friend for performance and readability. But remember — factorial growth is unavoidable, so for very large strings, think streaming, limiting, or on-demand generation instead of trying to produce everything at once.

With this, you’ve got a production-ready, safe, and scalable solution for permutations in Kotlin.

Fibonacci in Kotlin Using Dynamic Programming

Fibonacci in Kotlin Using Dynamic Programming: The Ultimate Guide

If you’ve ever dived into programming, chances are you’ve come across the famous Fibonacci sequence. It’s a classic problem that teaches us a lot about algorithms and optimization techniques. In this ultimate guide, we’ll explore Fibonacci in Kotlin Using Dynamic Programming in a friendly and easy-to-understand way. Whether you’re a beginner or an experienced Kotlin...

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here
Fibonacci Using Loops in Kotlin

Fibonacci Using Loops in Kotlin: A Simple & Efficient Approach

If you’ve just started learning Kotlin and want to practice loops in a real-world example, generating the Fibonacci series is a perfect choice. It’s simple enough to grasp, yet teaches you how to handle variables, loops, and logic in Kotlin efficiently.

In this guide, we’ll explore Fibonacci Using Loops in Kotlin, break down the code step-by-step, and keep it beginner-friendly — without skipping important details.

What is the Fibonacci Sequence?

The Fibonacci sequence is a series of numbers where each number is the sum of the two before it.

It starts like this:

Kotlin
0, 1, 1, 2, 3, 5, 8, 13, 21, 34...

Mathematically:

Kotlin
F(n) = F(n-1) + F(n-2)

Where:

  • F(0) = 0
  • F(1) = 1

Why Use Loops Instead of Recursion?

While recursion can generate Fibonacci numbers, it’s less efficient for large sequences because:

  • It repeats calculations unnecessarily.
  • It uses more memory due to function calls.

Using loops in Kotlin:
 Saves memory.
 Runs faster.
 Easier to understand for beginners.

That’s why Fibonacci Using Loops in Kotlin is both simple and efficient.

Kotlin Program for Fibonacci Using Loops

Here’s the complete Kotlin code:

Kotlin
fun main() {
    val terms = 10  // Number of Fibonacci numbers to print
    var first = 0
    var second = 1

    println("Fibonacci Series using loops:")

    for (i in 1..terms) {
        print("$first ")
        // Calculate the next number
        val next = first + second
        first = second
        second = next
    }
}

Step-by-Step Code Explanation

Let’s break it down so you truly understand:

1. Declaring Variables

Kotlin
fun main() {
    val terms = 10  // Number of Fibonacci numbers to print
    var first = 0
    var second = 1

    println("Fibonacci Series using loops:")

    for (i in 1..terms) {
        print("$first ")
        // Calculate the next number
        val next = first + second
        first = second
        second = next
    }
}
  • terms → how many numbers you want to print.
  • first and second → the first two Fibonacci numbers.

2. Using a Loop

Kotlin
for (i in 1..terms) {
    print("$first ")
    val next = first + second
    first = second
    second = next
}
  • Loop runs from 1 to terms → controls how many numbers are printed.
  • print("$first ") → displays the current number.
  • val next = first + second → calculates the next Fibonacci number.

We then shift the values:

  • first becomes the old second.
  • second becomes the new next.

Not clear — let’s dry run it for better understanding.

Iteration 1 (i = 1)

  • Print first → prints 0
  • next = first + second = 0 + 1 = 1
  • Update:
     first = second = 1
     second = next = 1

Output: 0

Iteration 2 (i = 2)

  • Print first → prints 1
  • next = 1 + 1 = 2
  • Update:
     first = 1
     second = 2

Output: 0 1

Iteration 3 (i = 3)

  • Print first → prints 1
  • next = 1 + 2 = 3
  • Update:
     first = 2
     second = 3

Output: 0 1 1

Iteration 4 (i = 4)

  • Print first → prints 2
  • next = 2 + 3 = 5
  • Update:
     first = 3
     second = 5

Output: 0 1 1 2

Iteration 5 (i = 5)

  • Print first → prints 3
  • next = 3 + 5 = 8
  • Update:
     first = 5
     second = 8

Output: 0 1 1 2 3

Iteration 6 (i = 6)

  • Print first → prints 5
  • next = 5 + 8 = 13
  • Update:
     first = 8
     second = 13

Output: 0 1 1 2 3 5

Iteration 7 (i = 7)

  • Print first → prints 8
  • next = 8 + 13 = 21
  • Update:
     first = 13
     second = 21

Output: 0 1 1 2 3 5 8

Iteration 8 (i = 8)

  • Print first → prints 13
  • next = 13 + 21 = 34
  • Update:
     first = 21
     second = 34

Output: 0 1 1 2 3 5 8 13

Iteration 9 (i = 9)

  • Print first → prints 21
  • next = 21 + 34 = 55
  • Update:
     first = 34
     second = 55

Output: 0 1 1 2 3 5 8 13 21

Iteration 10 (i = 10)

  • Print first → prints 34
  • next = 34 + 55 = 89
  • Update:
     first = 55
     second = 89

Output: 0 1 1 2 3 5 8 13 21 34

Final Output

If terms = 10, output will be:

Kotlin
Fibonacci Series using loops:
0 1 1 2 3 5 8 13 21 34

Tips to Make It Even Better

  • User Input: Instead of hardcoding terms, ask the user how many numbers they want.
Kotlin
print("Enter the number of terms: ")
   
val n = readLine()!!.toInt()
  • Formatting: Add commas or line breaks for readability.
  • Performance: This loop method already runs in O(n) time, making it efficient even for large terms.

Why This Approach Works Well

The Fibonacci Using Loops in Kotlin approach is ideal for:

  • Beginners learning loops.
  • Anyone needing quick and efficient Fibonacci generation.
  • Avoiding recursion stack overflow for large sequences.

It’s clean, easy to debug, and performs well.

Conclusion

The Fibonacci sequence is a timeless example for learning programming logic. By using loops in Kotlin, you get the perfect balance between simplicity and efficiency. Whether you’re practicing for interviews or just improving your coding skills, this method will serve you well.

Next time you think about Fibonacci, remember — you don’t always need recursion. A good old loop can do the job beautifully.

Fibonacci Sequence in Kotlin Using Recursion

Fibonacci Sequence in Kotlin Using Recursion — From Theory to Code

If you’ve ever been fascinated by numbers that seem to appear everywhere in nature — from the petals of flowers to the spirals in seashells — then you’ve already met the Fibonacci sequence.

In this blog, we’ll explore Fibonacci Sequence in Kotlin Using Recursion step by step. We’ll start with the theory, then move into writing simple yet powerful Kotlin code. Everything will be easy to follow, and beginner-friendly.

Understanding the Fibonacci Sequence

The Fibonacci sequence is a series of numbers where:

Kotlin
F(n) = F(n-1) + F(n-2)

with:

Kotlin
F(0) = 0
F(1) = 1

So, the sequence begins like this:

Kotlin
0, 1, 1, 2, 3, 5, 8, 13, 21, ...

Each term is the sum of the previous two terms. It’s a simple rule with surprisingly deep applications — mathematics, art, computer science, and even stock market analysis.

Why Use Recursion?

Recursion is when a function calls itself to solve smaller parts of a problem.
 In the case of the Fibonacci sequence, recursion works naturally because the definition of Fibonacci is already recursive in nature:

  • To find F(n), you find F(n-1) and F(n-2) and add them.
  • Each of those smaller problems breaks down further until you hit the base case (F(0) or F(1)).

Think of it like climbing stairs:

  • To reach the nth step, you must have come from either step (n-1) or (n-2).
  • You keep breaking it down until you reach the first or second step.

Writing Fibonacci Sequence in Kotlin Using Recursion

Here’s the code:

Kotlin
fun fibonacci(n: Int): Int {
    // Base cases: when n is 0 or 1
    if (n == 0) return 0
    if (n == 1) return 1

// Recursive call
    return fibonacci(n - 1) + fibonacci(n - 2)
}

fun main() {
    val terms = 10

    println("Fibonacci sequence up to $terms terms:")

    for (i in 0 until terms) {
        print("${fibonacci(i)} ")
    }
}

Code Explanation

1. Base Cases

Kotlin
if (n == 0) return 0
if (n == 1) return 1

These are our stopping points. If n is 0 or 1, we simply return the value without further calculations.

2. Recursive Step

Kotlin
return fibonacci(n - 1) + fibonacci(n - 2)

The function calls itself twice:

  • Once for the previous term (n-1)
  • Once for the term before that (n-2)
     It then adds them together to produce the nth term.

3. Main Function

Kotlin
for (i in 0 until terms) {
    print("${fibonacci(i)} ")
}

We loop through and print the first terms Fibonacci numbers, giving us a clean, readable sequence.

A Note on Performance

While Fibonacci Sequence in Kotlin Using Recursion is elegant and easy to understand, pure recursion can be slow for large n because it recalculates the same values multiple times.

Example:

  • fibonacci(5) calls fibonacci(4) and fibonacci(3).
  • But fibonacci(4) again calls fibonacci(3) — we’re repeating work.

Solution: Use memoization or dynamic programming to store results and avoid recalculations. But for learning recursion, the basic approach is perfect.

Real-World Applications

  • Algorithm practice: Great for learning recursion and problem-solving.
  • Mathematical modeling: Growth patterns in populations or financial data.
  • Computer graphics: Spiral designs and procedural patterns.

Key Takeaways

  • The Fibonacci sequence is naturally suited to recursion because of its self-referential definition.
  • Kotlin makes it clean and readable with its concise syntax.
  • For small inputs, recursion works perfectly, but for larger inputs, optimization is needed.

Conclusion

Recursion is like magic — it hides complexity behind a few lines of code. With the Fibonacci Sequence in Kotlin Using Recursion, you get both an elegant algorithm and a deep understanding of how problems can solve themselves step by step.

Finding the First Non-Repeating Character in a String Using Kotlin

Finding the First Non-Repeating Character in a String Using Kotlin

When working with strings in Kotlin, you may encounter scenarios where you need to find the first character that does not repeat. This problem is common in text processing, competitive programming, and software development.

In this blog, we’ll walk through an efficient approach to finding the first non-repeating character in a string using Kotlin. We’ll also explore a detailed explanation of the logic, why it works, and how it can be optimized for better performance.

Understanding the Problem

Given a string, our goal is to identify the first character that appears only once. If all characters are repeated, we should return null or a suitable indicator that no unique characters exist.

Kotlin
Input: "abcdhbac"
Output: 'd'

Here, ‘a’, ‘b’, and ‘c’ are repeated, but ‘d’ appears only once, making it the first non-repeating character.

Step-by-Step Approach (HashMap-based )

To solve this problem efficiently, we follow these steps:

  1. Use a HashMap (Mutable Map in Kotlin) to count occurrences of each character.
  2. Loop through the string to populate the frequency map.
  3. Loop through the string again to find the first character with a count of 1.
  4. Return the first unique character found; otherwise, return null.

Kotlin Implementation

Now, let’s implement this approach in Kotlin:

Kotlin
fun findNonRepeatedLetter(str: String): Char? {
    val charCount = mutableMapOf<Char, Int>()

    // Count occurrences of each character
    for (char in str) {
        charCount[char] = charCount.getOrDefault(char, 0) + 1
    }
    // Find the first character with a count of 1
    for (char in str) {
        if (charCount[char] == 1) {
            return char
        }
    }
    
    return null // Return null if no unique character exists
}

fun main() {
    val str = "abcdhbac"
    val result = findNonRepeatedLetter(str)
    
    println("First non-repeating character: ${result ?: "None"}")
}

Here,

  • Step 1: We create a mutable map charCount to store character frequencies.
  • Step 2: We iterate over the string, updating the map with each character’s occurrence count.
  • Step 3: We loop through the string again to check which character appears only once.
  • Step 4: If found, we return it; otherwise, we return null.

Output

Kotlin
First non-repeating character: d

Why This Approach Works Efficiently

This method ensures an optimal time complexity of O(n):

  • First loop (O(n)) — Counts character occurrences.
  • Second loop (O(n)) — Finds the first unique character.
  • Overall Complexity: O(n) + O(n) = O(n), making it very efficient.

Edge Cases to Consider

  1. All Characters Repeated: Input: "aabbcc" Output: None
  2. String with Only One Character: Input: "x" Output: x
  3. Empty String: Input: "" Output: None
  4. String with Multiple Unique Characters: Input: "kotlin" Output: k

Alternative Optimized Approach (Array-based)

Instead of using a HashMap, we can use an Array of size 256 (for ASCII characters) to store occurrences, making it even more memory-efficient for large-scale data.

Kotlin
fun findNonRepeatedLetterOptimized(str: String): Char? {
    val charArray = IntArray(256) // For ASCII characters
    
    for (char in str) {
        charArray[char.toInt()]++
    }
    
    for (char in str) {
        if (charArray[char.toInt()] == 1) {
            return char
        }
    }
    
    return null
}

Let’s walk through code and try to dry run it.

Step 1: Initialize charArray

The charArray will look like this initially (all zeros):

Kotlin
[0, 0, 0, 0, ..., 0]  // 256 zeros

Step 2: Count the characters

For each character in "abcdhbac", the array will be updated based on their ASCII values:

  • ‘a’ has an ASCII value of 97, so charArray[97]++ (now charArray[97] = 1).
  • ‘b’ has an ASCII value of 98, so charArray[98]++ (now charArray[98] = 1).
  • ‘c’ has an ASCII value of 99, so charArray[99]++ (now charArray[99] = 1).
  • ‘d’ has an ASCII value of 100, so charArray[100]++ (now charArray[100] = 1).
  • ‘h’ has an ASCII value of 104, so charArray[104]++ (now charArray[104] = 1).
  • ‘b’ has an ASCII value of 98 again, so charArray[98]++ (now charArray[98] = 2).
  • ‘a’ has an ASCII value of 97 again, so charArray[97]++ (now charArray[97] = 2).
  • ‘c’ has an ASCII value of 99 again, so charArray[99]++ (now charArray[99] = 2).

Now, the charArray looks like this (only showing relevant indexes):

Kotlin
charArray[97] = 2  // 'a' appears 2 times
charArray[98] = 2  // 'b' appears 2 times
charArray[99] = 2  // 'c' appears 2 times
charArray[100] = 1 // 'd' appears 1 time
charArray[104] = 1 // 'h' appears 1 time

Step 3: Find the first non-repeating character

  • Now, we iterate through the string again:
  • ‘a’: charArray[97] == 2 → Skip.
  • ‘b’: charArray[98] == 2 → Skip.
  • ‘c’: charArray[99] == 2 → Skip.
  • ‘d’: charArray[100] == 1Return ‘d’ (First non-repeating character).

Thus, the output will be 'd'.

Execution Flow:

  1. First loop: Count character occurrences in the string.
  2. Second loop: Check for the first character that appears only once.
  3. Return: Return the first non-repeating character or null if there are no non-repeating characters.

This approach is very efficient, with a time complexity of O(n), where n is the length of the string.

Why this approach is optimized?

  • Space is constant: The array size is fixed (256), regardless of the length of the input string. This means the space complexity of the solution is O(1) (constant space), as the array size does not grow with the input size, and you can use it regardless of whether the string is long or short.
  • No need for dynamic data structures like HashMap: The use of a fixed-size array eliminates the need for dynamically resizing a hash map as new characters are added, which would typically require reallocation of memory.

Conclusion

Finding the first non-repeating character in a string is a common problem, and Kotlin provides powerful tools like mutableMapOf and IntArray to solve it efficiently. The HashMap-based approach is easy to understand and works well in most cases, while the Array-based approach can be optimized for performance in certain situations.

error: Content is protected !!