LeetCode Entry

664. Strange Printer

21.08.2024 hard 2024 kotlin rust

Minimum continuous replacements to make a string programming

664. Strange Printer hard blog post substack youtube 1.webp

Join me on Telegram

https://t.me/leetcode_daily_unstoppable/709

Problem TLDR

Minimum continuous replacements to make a string #hard #dynamic_programming

Intuition

Last time I solved it fine (1 year ago, https://t.me/leetcode_daily_unstoppable/291), this time, however, I was stuck with the corner cases, ultimately failing to solve it in 1.5 hours.

The not working idea was to consider the case of painting the [i..j] substring when its endings are equal s[i] == s[j], and choose between repainting entire thing or just appending one symbol. This also has to consider the background color already painted, so it is dp[i][j][b]:


    // abcabc
    // aaaaaa
    //  bb
    //   c
    //     bb
    //      c

    // abcdcba     cdc + ab..ba, cdc = d + c..c,  cd = d + c.. or c + ..d
    //             cdcba = c + ..dcba or cdcb + ..a
    // cdc = 1 + min(cd + c, c + dc)

The if tree grown too much, and some cases were failing, and I still think I missing some cases or idea is just completely wrong.

The working idea: try all possible splits to paint and choose the minimum.

Approach

Let’s implement both recursive and bottom-up iterative solutions.

Complexity

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

  • Space complexity: \(O(n^2)\)

Code


    fun strangePrinter(s: String): Int {
        val dp = mutableMapOf<Pair<Int, Int>, Int>()
        fun dfs(i: Int, j: Int): Int =
            if (i == j) 1 else if (i > j) 0
            else if (i == j - 1) { if (s[i] == s[j]) 1 else 2 }
            else dp.getOrPut(i to j) {
                if (s[i] == s[i + 1]) dfs(i + 1, j)
                else if (s[j] == s[j - 1]) dfs(i, j - 1)
                else (i..j - 1).map { dfs(i, it) + dfs(it + 1, j) }.min() -
                    if (s[i] == s[j]) 1 else 0
            }
        return dfs(0, s.lastIndex)
    }


    pub fn strange_printer(s: String) -> i32 {
        let n = s.len(); let mut dp = vec![vec![-1; n]; n];
        let s = s.as_bytes();
        for (j, &b) in s.iter().enumerate() {
            for i in (0..=j).rev() {
                dp[i][j] = if j - i <= 1 { if s[i] == b { 1 } else { 2 }}
                else if s[i] == b { dp[i + 1][j] }
                else {
                    (i..j).map(|k| dp[i][k] + dp[k + 1][j] ).min().unwrap() -
                    if s[i] == b { 1 } else { 0 }
                }}}
        dp[0][n - 1]
    }