LeetCode Entry

2366. Minimum Replacements to Sort the Array

30.08.2023 hard 2023 kotlin

Minimum number of number splits to make an array non-decreasing

2366. Minimum Replacements to Sort the Array hard blog post substack

image.png

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/324

Problem TLDR

Minimum number of number splits to make an array non-decreasing

Intuition

The first idea is, if we walk the array backwards, suffix is a maximum number. The second idea is how to split the current number optimally. Consider example:

        // 3  8   3
        // 3  53  3 +1 split
        // 3  233 3 +1 split
        // 12 233 3 +1 split

We shall not split 8 into numbers bigger than 3, so keep extracting them, until some remainder reached. However, this will not be the case for another example: 2 9 4, when we split 9 -> 5 + 4, we should not split 5 into 1 + 4, but 2 + 3, but optimal split is 3 + 3 + 3, as 3 < 4 and 3 > 2. Another strategy is to consider how many split operations we should do: 9 / 4 = 2, then we know the number of parts: 9 = (x split y split z) = 3 + 3 + 3. Each part is guaranteed to be less than 4 but the maximum possible to sum up to 9.

Approach

  • explicitly write the corner cases to simplify the thinking: ` x < prev, x == prev, prev == 1, x % prev == 0`
  • give a meaningful variable names and don’t prematurely simplify the math
  • try to find the good example to debug the code

Complexity

  • Time complexity: \(O(n)\)

  • Space complexity: \(O(1)\)

Code


    fun minimumReplacement(nums: IntArray): Long {
        if (nums.isEmpty()) return 0L
        // 3  8   3
        // 3  53  3 +1 split
        // 3  233 3 +1 split
        // 12 233 3 +1 split
        var prev = nums.last()
        var count = 0L
        for (i in nums.lastIndex downTo 0) {
            if (nums[i] == prev) continue
            if (nums[i] < prev) prev = nums[i]
            else if (prev == 1) count += nums[i] - 1
            else if (nums[i] % prev == 0) count += (nums[i] / prev) - 1
            else {
                val splits = nums[i] / prev // 15 / 4 = 3
                count += splits
                val countParts = splits + 1 // 4 = (3 4 4 4)
                prev = nums[i] / countParts // 15 / 4 = 3
            }
        }
        return count
    }