LeetCode in Kotlin

3149. Find the Minimum Cost Array Permutation

Hard

You are given an array nums which is a permutation of [0, 1, 2, ..., n - 1]. The score of any permutation of [0, 1, 2, ..., n - 1] named perm is defined as:

score(perm) = |perm[0] - nums[perm[1]]| + |perm[1] - nums[perm[2]]| + ... + |perm[n - 1] - nums[perm[0]]|

Return the permutation perm which has the minimum possible score. If multiple permutations exist with this score, return the one that is lexicographically smallest among them.

Example 1:

Input: nums = [1,0,2]

Output: [0,1,2]

Explanation:

The lexicographically smallest permutation with minimum cost is [0,1,2]. The cost of this permutation is |0 - 0| + |1 - 2| + |2 - 1| = 2.

Example 2:

Input: nums = [0,2,1]

Output: [0,2,1]

Explanation:

The lexicographically smallest permutation with minimum cost is [0,2,1]. The cost of this permutation is |0 - 1| + |2 - 2| + |1 - 0| = 2.

Constraints:

Solution

import kotlin.math.abs
import kotlin.math.min

class Solution {
    private fun findMinScore(mask: Int, prevNum: Int, nums: IntArray, dp: Array<IntArray>): Int {
        val n = nums.size
        if (Integer.bitCount(mask) == n) {
            dp[mask][prevNum] = abs((prevNum - nums[0]))
            return dp[mask][prevNum]
        }
        if (dp[mask][prevNum] != -1) {
            return dp[mask][prevNum]
        }
        var minScore = Int.MAX_VALUE
        for (currNum in 0 until n) {
            if ((mask shr currNum and 1 xor 1) == 1) {
                val currScore = (
                    abs((prevNum - nums[currNum])) + findMinScore(
                        mask or (1 shl currNum),
                        currNum,
                        nums,
                        dp,
                    )
                    )
                minScore = min(minScore, currScore)
            }
        }
        return minScore.also { dp[mask][prevNum] = it }
    }

    private fun constructMinScorePermutation(n: Int, nums: IntArray, dp: Array<IntArray>): IntArray {
        val permutation = IntArray(n)
        var i = 0
        permutation[i++] = 0
        var prevNum = 0
        var mask = 1
        while (i < n) {
            for (currNum in 0 until n) {
                if ((mask shr currNum and 1 xor 1) == 1) {
                    val currScore =
                        (abs((prevNum - nums[currNum])) + dp[mask or (1 shl currNum)][currNum])
                    val minScore = dp[mask][prevNum]
                    if (currScore == minScore) {
                        permutation[i++] = currNum
                        prevNum = currNum
                        break
                    }
                }
            }
            mask = mask or (1 shl prevNum)
        }
        return permutation
    }

    fun findPermutation(nums: IntArray): IntArray {
        val n = nums.size
        val dp = Array(1 shl n) { IntArray(n) }
        for (row in dp) {
            row.fill(-1)
        }
        findMinScore(1, 0, nums, dp)
        return constructMinScorePermutation(n, nums, dp)
    }
}