• LeetCode 笔记24 Palindrome Partitioning II (智商碾压)


    Given a string s, partition s such that every substring of the partition is a palindrome.

    Return the minimum cuts needed for a palindrome partitioning of s.

    For example, given s = "aab",
    Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.

    这种最小啊,最大啊,最长啊,etc肯定是用动态规划无疑了。

    我之前已经知道如何判断一个字符串s中,s[i...j]是否是一个回文。

    isPalindrome[i][j] = true iff s[i] == s[j] && isPalindrome[i + 1][j - 1] 或者 j - i <= 1

    当我们得到这个matrix以后,我们可以认为这是一个邻接矩阵,也就是一个图。那么这个问题可以转换成一个源最短路径问题。那么最简单的就是用bfs了。

    public int minCut(String s) {
            boolean[][] isPalindrome = new boolean[s.length() + 1][s.length() + 1];
            // Map<Integer, Set<Integer>> adjecent = new HashMap<>();
            for (int i = 0; i <= s.length(); i++) {
                isPalindrome[i][i] = true;
                // adjecent.put(i, new HashSet<Integer>());
            }
            for (int i = s.length() - 1; i >= 0; i--) {
                for (int j = i + 1; j <= s.length(); j++) {
                    isPalindrome[i][j] = s.charAt(i) == s.charAt(j - 1)
                            && (j - i == 1 || isPalindrome[i + 1][j - 1]);
                    if (isPalindrome[i][j]) {
                        // adjecent.get(i).add(j);
                    }
                }
            }
    
            LinkedList<Integer> queue = new LinkedList<Integer>();
            boolean[] visited = new boolean[s.length() + 1];
            queue.add(0);
            int head = 0;
            int depth = 0;
            while (!queue.isEmpty()) {
                int w = queue.poll();
                if (head == w) {
                    depth++;
                    head = -1;
                }
                for (int i = 0; i < isPalindrome[w].length; i++) {
                    if (isPalindrome[w][i] && i == s.length()) {
                        return depth - 1;
                    }
                    if (isPalindrome[w][i] && !visited[i]) {
                        visited[i] = true;
                        queue.add(i);
                        if (head == -1) {
                            head = i;
                        }
                    }
                }
            }
            return -1;
        }

    结果这个弄的很郁闷,因为之前我一直用的时hash map来表示邻接矩阵,结果老超时,于是干脆来粗暴的,直接使用得到的二维数组来做,竟然过了。hash map应该给我O(1)的时间才对啊,为啥还不如数组呢?

    于是我google了一下,结果发现求最小的cut居然本身也可以用动态规划来做。算了,哭晕在厕所里。

    先看代码。

    public int minCut(String s) {
            boolean[][] isPalindrome = new boolean[s.length()][s.length()];
            int[] cut = new int[s.length()];
    
            for (int j = 0; j < s.length(); j++) {
                cut[j] = j;
                for (int i = 0; i <= j; i++) {
                    if (s.charAt(i) == s.charAt(j)
                            && (j - i <= 1 || isPalindrome[i + 1][j - 1])) {
                        isPalindrome[i][j] = true;
                        if (i > 0) {
                            cut[j] = Math.min(cut[j], cut[i - 1] + 1);
                        } else {
                            cut[j] = 0;
                        }
                    }
                }
            }
            return cut[s.length() - 1];
        }

    这区区几行就完了。可以观察到在求回文矩阵的部分是一样的。关键是那个cut数组。

    cut[j]表示s[0...j]最小cut数。

    在i移动的过程中,把i作为分割点。

    那么 cut[j] = min(cut[i - 1] + 1) iif s[i...j] 是回文 for i = 0 ~ j

    所以在最里面的一个循环(i 从 0 到j)中,既能求得isPalindrome[0...j][j],同时也能求得cut[j]了。

    该算法还有一点,就是循环方向的选择很合理。

  • 相关阅读:
    MWC飞控增加声纳定高的方法(转)
    c语言字符串分割函数(转)
    移动端IM系统的协议选型:UDP还是TCP?(转)
    如何编写Linux设备驱动程序(转)
    TCP连接探测中的Keepalive和心跳包(转)
    为什么说基于TCP的移动端IM仍然需要心跳保活?(转)
    基于 FPGA 的图像边缘检测(转)
    NTC热敏电阻基础以及应用和选择(转)
    通用CRC32校验程序,可完美匹配STM32硬件CRC算法(转)
    MAX31855 热电偶至数字输出转换器
  • 原文地址:https://www.cnblogs.com/lichen782/p/4298615.html
Copyright © 2020-2023  润新知