1799. Maximize Score after N Operations - Explanation

Problem Link



1. Brute Force (Backtracking)

class Solution:
    def maxScore(self, nums: List[int]) -> int:
        N = len(nums)
        visit = [False] * N

        def dfs(n):
            if n > (N // 2):
                return 0

            res = 0
            for i in range(N):
                if visit[i]:
                    continue
                visit[i] = True
                for j in range(i + 1, N):
                    if visit[j]:
                        continue
                    visit[j] = True
                    g = gcd(nums[i], nums[j])
                    res = max(res, n * g + dfs(n + 1))
                    visit[j] = False
                visit[i] = False

            return res

        return dfs(1)

Time & Space Complexity

  • Time complexity: O(nnlogm)O(n ^ n * \log m)
  • Space complexity: O(n)O(n)

Where nn is the size of the array numsnums and mm is the maximum element in the array.


2. Bitmask DP (Top-Down) - I

class Solution:
    def maxScore(self, nums: List[int]) -> int:
        cache = collections.defaultdict(int)

        def dfs(mask, op):
            if mask in cache:
                return cache[mask]

            for i in range(len(nums)):
                for j in range(i + 1, len(nums)):
                    if (1 << i) & mask or (1 << j) & mask:
                        continue

                    newMask = mask | (1 << i) | (1 << j)
                    score = op * math.gcd(nums[i], nums[j])
                    cache[mask] = max(
                        cache[mask],
                        score + dfs(newMask, op + 1)
                    )

            return cache[mask]

        return dfs(0, 1)

Time & Space Complexity

  • Time complexity: O(n22nlogm)O(n ^ 2 * 2 ^ n * \log m)
  • Space complexity: O(2n)O(2 ^ n)

Where nn is the size of the array numsnums and mm is the maximum element in the array.


3. Bitmask DP (Top-Down) - II

class Solution:
    def maxScore(self, nums: List[int]) -> int:
        n = len(nums)
        GCD = [[0] * n for _ in range(n)]
        for i in range(n):
            for j in range(i + 1, n):
                GCD[i][j] = gcd(nums[i], nums[j])

        dp = [-1] * (1 << n)
        def dfs(mask, op):
            if dp[mask] != -1:
                return dp[mask]

            max_score = 0
            for i in range(n):
                if mask & (1 << i):
                    continue
                for j in range(i + 1, n):
                    if mask & (1 << j):
                        continue
                    new_mask = mask | (1 << i) | (1 << j)
                    max_score = max(
                        max_score,
                        op * GCD[i][j] + dfs(new_mask, op + 1)
                    )

            dp[mask] = max_score
            return max_score

        return dfs(0, 1)

Time & Space Complexity

  • Time complexity: O(n2(2n+logm))O(n ^ 2 * (2 ^ n + \log m))
  • Space complexity: O(n2+2n)O(n ^ 2 + 2 ^ n)

Where nn is the size of the array numsnums and mm is the maximum element in the array.


4. Bitmask DP (Bottom-Up)

class Solution:
    def maxScore(self, nums: List[int]) -> int:
        n = len(nums)
        N = 1 << n
        GCD = [[0] * n for _ in range(n)]
        for i in range(n):
            for j in range(i + 1, n):
                GCD[i][j] = gcd(nums[i], nums[j])

        dp = [0] * N
        for mask in range(N - 1, -1, -1):
            bits = bin(mask).count('1')
            if bits % 2 == 1:
                continue
            op = bits // 2 + 1

            for i in range(n):
                if mask & (1 << i):
                    continue
                for j in range(i + 1, n):
                    if mask & (1 << j):
                        continue
                    new_mask = mask | (1 << i) | (1 << j)
                    dp[mask] = max(dp[mask], op * GCD[i][j] + dp[new_mask])

        return dp[0]

Time & Space Complexity

  • Time complexity: O(n2(2n+logm))O(n ^ 2 * (2 ^ n + \log m))
  • Space complexity: O(n2+2n)O(n ^ 2 + 2 ^ n)

Where nn is the size of the array numsnums and mm is the maximum element in the array.