Leetcode 664. Strange Printer

Problem Explanation

This problem is about an unique printer that can print a sequence of the same character each time. The printer has the capability to print new characters over the existing ones, starting and ending at any places. Given a string consisting of lower English letters, the task is to find the minimum number of turns the printer takes to print the string.

For instance, consider the example where the input string is "aaabbb". The printer will take two turns to print this string - in the first turn, it prints "aaa" and in the second turn, it prints "bbb".

The problem statement also indicates that the length of the given string will not exceed 100 which is an important constraint to be aware of when developing the solution.

Solution Approach

The primary approach to solving problem is using dynamic programming.

Firstly, we initialise a 2D array dp with the size equal to the length of the input string.

The dp[i][j] holds the minimum number of turns needed to print the section of the string from i to j.

Then, we recursively call the function strangePrinter, which calculates and fills up the dp array.

If i > j, the function returns 0 indicating that no turn is needed. If dp[i][j] > 0, it returns the value stored in dp[i][j].

Otherwise, it first prints the character at the position i and increments the count in dp[i][j].

Next, it iterates over the remainder of the string, and if it encounters a character equal to the character at the position i, it recalculates the minimum turns by taking the sum of the turns required to print the section before and after the repeated character.

At the end, the function returns the minimum turns required to print the string from i to j, stored in dp[i][j].

Java Solution

3class Solution {
4    public int strangePrinter(String s) {
5        int n = s.length();
6        int[][] dp = new int[n][n];
7        return helper(dp, s, 0, n - 1);
8    }
10    private int helper(int[][] dp, String s, int i, int j) {
11        if (i > j) return 0;
12        if (dp[i][j] == 0) {
13            dp[i][j] = helper(dp, s, i + 1, j) + 1;
14            for (int k = i + 1; k <= j; k++) {
15                if (s.charAt(k) == s.charAt(i)) {
16                    dp[i][j] = Math.min(dp[i][j], helper(dp, s, i, k - 1) + helper(dp, s, k + 1, j));
17                }
18            }
19        }
20        return dp[i][j];
21    }

Python Solution

3class Solution:
4    def strangePrinter(self, s: str) -> int:
5        memo = {}
6        def dp(i, j):
7            if i > j: return 0
8            if (i, j) not in memo:
9                ans = dp(i+1, j) + 1
10                for k in range(i+1, j+1):
11                    if s[k] == s[i]:
12                        ans = min(ans, dp(i, k-1) + dp(k+1, j))
13                memo[i, j] = ans
14            return memo[i, j]
15        return dp(0, len(s) - 1)

JavaScript Solution

3var strangePrinter = function(s) {
4    const n = s.length;
5    const dp = Array.from(Array(n), () => new Array(n).fill(0));
7    return helper(dp, s, 0, n - 1);
9    function helper(dp, s, i, j) {
10        if (i > j) return 0;
11        if (dp[i][j] === 0) {
12            dp[i][j] = helper(dp, s, i + 1, j) + 1;
13            for (let k = i + 1; k <= j; k++) {
14                if (s[k] === s[i]){
15                    dp[i][j] = Math.min(dp[i][j], helper(dp, s, i, k - 1) + helper(dp, s, k + 1, j));
16                }
17            }
18        }
19        return dp[i][j];
20    }

C++ Solution

3class Solution {
5    int dp[100][100] = {};
6    int strangePrinter(string s) {
7        return helper(s, 0, s.size() - 1);
8    }
10    int helper(string& s, int i, int j) {
11        if (i > j) return 0;
12        if (dp[i][j] == 0) {
13            dp[i][j] = helper(s, i+1 , j) + 1;
14            for (int k = i+1; k <= j; ++k){
15                if (s[k] == s[i]){
16                    dp[i][j] = min(dp[i][j], helper(s, i, k - 1) + helper(s, k + 1, j));
17                }
18            }
19        }
20        return dp[i][j];
21    }

With the aforementioned solutions, we have shown how the problem can be addressed using JavaScript, Python, and Java languages. We also illustrated the use of dynamic programming in solving this problem.

Whether using Java, JavaScript or Python, the main logic remains consistent. The solutions involve creating a 2D array (or a dictionary in Python) that is dynamically filled based on the minimum number of turns required to print sections of the string. The logic also considers the scenario where the same letter appears multiple times within the string, optimizing the printing process further.

It is important to mention that the indices i and j represent the start and end of the substring we are considering at any iteration, giving us flexibility in handling various lengths. The recursive functions then evaluate possible strategies for printing the substring and save the optimal number of moves required in the dp array (or dictionary in Python).

Please note that these solutions have a time complexity of O(n^3) due to the three levels of looping over the given string involved (prep work, main loop, and recursions). Here, n represents the length of the string. However, due to constraint (length of string will not exceed 100), performance should still be reasonable.

Overall, these solutions showcase the power of powerful programming paradigms like dynamic programming in solving complex problems in an efficient manner. It also highlights the versatility of languages like JavaScript, Python, and Java in implementing such intricate solutions.

Got a question? Ask the Teaching Assistant anything you don't understand.

Still not clear? Ask in the Forum,  Discord or Submit the part you don't understand to our editors.

TA 👨‍🏫