Arun Pandian M

Arun Pandian M

Android Dev | Full-Stack & AI Learner

Array Traversal Pattern — Problem: Find Maximum Element in an Array

Problem

Given an array of integers, find the largest element in it. You need to scan through all elements and return the one with the highest value.

Example

Input: [3, 7, 2, 9, 5]
Output: 9

Pattern: Array Traversal (Linear Scan)

A common pattern where we visit each element of an array one by one (sequentially or recursively) to perform an operation — such as finding a maximum, minimum, sum, or count.

Core idea

Move through every element in the array **exactly once**, keeping track of the needed result (like the current maximum).

Realtime analogy

Looking for the Tallest Person in a Queue
  • You’re at a school sports day, standing at the front of a line of students.
  • Walk through each student one by one.
  • Keep track of the tallest height so far.
  • At the end, the tallest student in the line is identified.
  • https://storage.googleapis.com/lambdabricks-cd393.firebasestorage.app/array_traversal_linear_scan.svg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=firebase-adminsdk-fbsvc%40lambdabricks-cd393.iam.gserviceaccount.com%2F20260117%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260117T150755Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=7bdbb2854ae8447827d0f84cbc48eba276915df7531406958cff70b7077622e97b8af0557257c063c72d6a9a6e9b7c209d05429cad70e9fc0c4e3d236183a8b35c32f5a0127b9954a752170282cb1cc55dd43f73deeba6845c16b249834b5ec86ad3869990cfa2bdd630f3506f368c6fa0bbe3f1a65f999b9b11b4a2036f5552de87d4ad60f76820d87927689b51d44c1e61ab0dd16c1f1a5fcef9ad0fb098babccb567600c8f17135b3581b027058ba5a03854693c5fd063c5debb7ff6c1bee3c83f0a904d9343020a41d35b141c437d76682fea2194d09c3d659785b66eb2de8ec6766b13170b426c78d5558756448b356187eb5e8c0ea4b25cd8b768cc0b9

    Step-by-step flow

    Start
      |
      v
    Initialize max = 1 (first element)
      |
      v
    Compare next element → 3
      |
      +-- Is 3 > max (1)? --> Yes --> Update max = 3
      |                              
      |--> No  --> max remains 1
      |
      v
    Compare next element → 5
      |
      +-- Is 5 > max (3)? --> Yes --> Update max = 5
      |
      v
    Compare next element → 2
      |
      +-- Is 2 > max (5)? --> No --> max remains 5
      |
      v
    Compare next element → 4
      |
      +-- Is 4 > max (5)? --> No --> max remains 5
      |
      v
    End: max = 5

    Solution

    fun findMaxElement(numbers: IntArray): Int? {
        if (numbers.isEmpty()) return null
        var max = numbers.first()
        numbers.forEach { num ->
            if (num > max)
                max = num
        }
        return max
    }

    Time Complexity

  • Let n be the number of elements in the array.
  • We visit each element exactly once to compare it with max.
  • Operations per element: 1 comparison (and sometimes an update).
  • Time Complexity =O(n)\text{Time Complexity } = O(n)

    Space Complexity

    We only need:
  • 1 variable to store max.
  • We do not use extra arrays or recursion.
  • Space Complexity =O(1)\text{Space Complexity } = O(1)
    We **could solve this max-finding problem using Divide and Conquer** by splitting the array, finding the max in each half, and then combining the results. However, for **small arrays**, this is **overkill** — a simple linear scan is faster and simpler.

    Divide and Conquer (D&C) Pattern:

    Realtime analogy

    Finding the Tallest Person in a Huge Crowd
  • You’re at a school sports day with a long line of students.
  • Instead of checking one by one, you split the line into two smaller groups.
  • Each group is further split into smaller subgroups until you reach groups of one or two students.
  • In each tiny group, find the tallest student.
  • Combine the results of the subgroups step by step to find the tallest student overall.
  • This way, you divide the crowd recursively, conquer each tiny group, and combine results, exactly like Divide and Conquer.
  • https://storage.googleapis.com/lambdabricks-cd393.firebasestorage.app/dc_araay_max_find.svg?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=firebase-adminsdk-fbsvc%40lambdabricks-cd393.iam.gserviceaccount.com%2F20260117%2Fauto%2Fstorage%2Fgoog4_request&X-Goog-Date=20260117T150755Z&X-Goog-Expires=3600&X-Goog-SignedHeaders=host&X-Goog-Signature=96de7a7706cb491728333074a5db84e290acfb53f1e9f8c8a66a62823fe899284ce6e27aa2ed6948c302ebb96ec2ec4d1b3c8c4a579291f8c6209c7f7b45a49c0d995b0151237dc795c2cbf4a54e4cd455d9f8eb8994fd8b3a83c1509d0730fecc55699bac3ee54359be7b7d0f21b7731a94714745a10adc1dfe82a3afc7df49808d72deb9898e6c68acbd8b9a46946b21073ecf9708a58da272b2480b28649cd475b4068053d900c27c71b21a2b3a163bb202bfcedf946150ef80ec894559aaccc0132b1ca174d9cce6b28d6d4857d0c882c077e0b54357027177c90eab39338688b045216a9c846b9d5353e12317a7ae790f9330594bcc93155b489944b3a0

    Step-bystep flow

    Start
      |
      v
    Check array size
      |
      +-- Is array size 1? --> Yes --> Return that element as max
      |                          |
      |                          v
      |                     End recursion
      |
      --> No --> Split array into two halves
      |             |
      |             v
      |       Recur on left half --> LeftMax
      |       Recur on right half --> RightMax
      |
      v
    Compare LeftMax and RightMax
      |
      +-- Which is greater? --> That is the max of current array
      |
      v
    Return max to previous recursion / combine step
      |
      v
    End: max of original array

    solution

    fun dcFindMaxElement(numbers: IntArray, start: Int = 0, end: Int = numbers.size - 1): Int {
        if (start == end) return numbers[start]
        val mid = (start + end) / 2 // bracket is important
        val leftMax = dcFindMaxElement(numbers,start,mid)
        val rightMax = dcFindMaxElement(numbers,mid+1,end)
        return maxOf(leftMax,rightMax)
    }

    Time Complexity

  • Each element is visited once during the combine step.
  • Recursion splits the array into halves until base case (size 1).
  • Recurrence:
  • T(n)=2T(n/2)+O(1)T(n) = 2 \cdot T(n/2) + O(1)
  • Solving this recurrence (Master Theorem) gives:
  • T(n)=O(n)\mathbf{T(n) = O(n)}
    Same as linear scan in terms of **asymptotic time**, but with extra **function call overhead**.

    Space Complexity

  • Requires recursion stack of depth log₂(n) (because we split array in half each time).
  • No additional arrays are created (just indices).
  • Space=O(logn)\mathbf{Space = O(\log n)}
    D&C visits all elements → O(n) time, recursion stack → O(log n) space.

    Conclusion: Linear Scan vs Divide & Conquer

    Linear Scan:

  • Simple, direct, and efficient for small to medium arrays.
  • O(n) time, O(1) space.
  • Minimal overhead, easy to implement and read.
  • Divide & Conquer:

  • Conceptually elegant, demonstrates recursion and problem splitting.
  • O(n) time, O(log n) space due to recursion stack.
  • Useful for teaching recursion, large arrays, or parallel processing, but overkill for small arrays.
  • Takeaway

  • For most practical scenarios, linear scan is enough.
  • Divide & Conquer is a pattern to understand, showing how problems can be split, solved, and merged.
  • #divide_and_conquer#algorithms#recursion#array_traversal#linear_scan#algorithm_patterns#problem_solving#data_structures#time_complexity#kotlin_programming