{x}
blog image

Optimal Division

You are given an integer array nums. The adjacent integers in nums will perform the float division.

  • For example, for nums = [2,3,4], we will evaluate the expression "2/3/4".

However, you can add any number of parenthesis at any position to change the priority of operations. You want to add these parentheses such the value of the expression after the evaluation is maximum.

Return the corresponding expression that has the maximum value in string format.

Note: your expression should not contain redundant parenthesis.

 

Example 1:

Input: nums = [1000,100,10,2]
Output: "1000/(100/10/2)"
Explanation: 1000/(100/10/2) = 1000/((100/10)/2) = 200
However, the bold parenthesis in "1000/((100/10)/2)" are redundant since they do not influence the operation priority.
So you should return "1000/(100/10/2)".
Other cases:
1000/(100/10)/2 = 50
1000/(100/(10/2)) = 50
1000/100/10/2 = 0.5
1000/100/(10/2) = 2

Example 2:

Input: nums = [2,3,4]
Output: "2/(3/4)"
Explanation: (2/(3/4)) = 8/3 = 2.667
It can be shown that after trying all possibilities, we cannot get an expression with evaluation greater than 2.667

 

Constraints:

  • 1 <= nums.length <= 10
  • 2 <= nums[i] <= 1000
  • There is only one optimal division for the given input.

Solution Explanation for LeetCode 553: Optimal Division

This problem asks to find the optimal parenthesization of a division expression to maximize the result. Surprisingly, the solution doesn't require complex dynamic programming or exhaustive search. The optimal solution is always to group all numbers after the first one in the denominator.

Mathematical Intuition

Consider an example: [a, b, c, d]. We want to maximize a / (b / (c / d)). The key observation is that dividing by a smaller number yields a larger result. By grouping b, c, d in the denominator, we minimize the denominator and maximize the overall result. This holds true regardless of the number of elements.

Algorithm

  1. Base Cases:

    • If there's only one number, return the number as a string.
    • If there are two numbers, return the expression a/b.
  2. General Case:

    • If there are three or more numbers, construct a string of the form a/(b/c/d...), where a is the first number and b, c, d... are the remaining numbers, grouped in the denominator. This ensures the denominator is minimized, maximizing the overall result.

Time and Space Complexity

  • Time Complexity: O(n), where n is the length of the input array. This is because constructing the string takes linear time in relation to the number of elements.
  • Space Complexity: O(n), where n is the length of the input array. This is because the space used is proportional to the length of the generated string.

Code Implementation (Python)

class Solution:
    def optimalDivision(self, nums: List[int]) -> str:
        n = len(nums)
        if n == 1:
            return str(nums[0])
        if n == 2:
            return str(nums[0]) + "/" + str(nums[1])
        result = str(nums[0]) + "/(" + "/".join(map(str, nums[1:])) + ")"
        return result
 

Code Implementation (Java)

class Solution {
    public String optimalDivision(int[] nums) {
        int n = nums.length;
        if (n == 1) return String.valueOf(nums[0]);
        if (n == 2) return nums[0] + "/" + nums[1];
        StringBuilder sb = new StringBuilder(nums[0] + "/(");
        for (int i = 1; i < n; i++) {
            sb.append(nums[i]);
            if (i < n - 1) sb.append("/");
        }
        sb.append(")");
        return sb.toString();
    }
}

Code Implementation (C++)

class Solution {
public:
    string optimalDivision(vector<int>& nums) {
        int n = nums.size();
        if (n == 1) return to_string(nums[0]);
        if (n == 2) return to_string(nums[0]) + "/" + to_string(nums[1]);
        string result = to_string(nums[0]) + "/(";
        for (int i = 1; i < n; ++i) {
            result += to_string(nums[i]);
            if (i < n - 1) result += "/";
        }
        result += ")";
        return result;
    }
};

The other languages (Go, TypeScript, Rust) follow a similar pattern, adapting the string manipulation to their respective syntax and libraries. The core logic of handling the base cases and creating the optimal string remains consistent.