DEV Community

Gopher's Math Note
Gopher's Math Note

Posted on

Beyond Sorting: A mathematical O(n) Solution to Arithmetic Progression

Leetcode's daily challenges can be extremely difficult at times, yet surprisingly simple at others, however even the straightforward problems offer food for thought - which is precisely why I am writing this article ๐Ÿฅบ

But personally, I still think the most straightforward and "standard" solution to this problem is to sort the array first and then check whether it is an arithmetic progression or not.

However, if we can still achieve O(n) solution w/o sorting, I believe it would be a better approach.

Arithmetic Progression

Question: 1502. Can Make Arithmetic Progression From Sequence

Description:

A sequence of numbers is called an arithmetic progression if the difference between any two consecutive elements is the same.

Given an array of numbers arr, return true if the array can be rearranged to form an arithmetic progression. Otherwise, return false.

AC Submission

Intuition

First of all, let's recall the definition and some basic properties of an arithmetic progression:

  • The sum of an arithmetic sequence with nn elements
Sn=12n(2a+(nโˆ’1)d) S_n = \frac{1}{2}n (2a + (n - 1)d)
  • The general formula for an arithmetic sequence:
un=a+(nโˆ’1)d u_n = a + (n - 1)d

Note that: aa is the first term, dd is the common diff., nn is the index.

So for any valid arithmetic sequence, every element must satisfy this formula.

And this leads to a natural idea:

Why not covert the original array into a Set, and check whether every expected value exists in that set?

Refine our validation logic:

  1. The diff between the maximum and minimum values must be divisible by n, where n = arr.length - 1. This is because we need n identical steps (i.e. common diff.) to connect min and max, for example [1(d1)3(d2)5], there is exactly two diffs.
  2. If max == min, then all elements are the same (e.g. [0,0,0,0]), which is trivially an arithmetic progression, we can directly return true.

Approach:

The core steps of the solution are:

  1. Find the max and min vals in the array.
  2. Check whether (max - min) is divisible by n.
  3. Compute the common diff.
  4. Convert the array into a set (or this might be the first step).
  5. Verify that every expected value:
    min+iร—d\text{min} + i \times d
    exists in the set. And if any val is missing, return false immediately.

Complexity:

Time Complexity:

  • Finding min and max: O(n)
  • Building the set: O(n)
  • Iterating through expected values: O(n). Overall, O(n).

Space Complexity:

  • Since an extra set is created to store the els, overall space complexity is O(n)

Code:

Note: in the following code, n = arr.length, and that's why n - 1 is required.

function canMakeArithmeticProgression(arr: number[]): boolean {.

    let n: number = arr.length

    let max: number = Math.max(...arr)
    let min: number = Math.min(...arr)

    if ((max - min) % (n - 1) !== 0){
        return false
    }

    if (max === min){
        return true
    }

    let diff: number = Math.floor((max - min) / (n - 1))

    let tmp =  new Set<number>(arr)

    for (let i = 0; i < n; i++){
        let expected: number = min + i * diff
        if (!tmp.has(expected)){
            return false
        }
    }
    return true
// InkkaPlum https://dev.to/slumhee
Enter fullscreen mode Exit fullscreen mode

Thanks for reading!
If u have any questions, feel free to leave comments.

Top comments (0)