zoukankan      html  css  js  c++  java
  • 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]了。

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

  • 相关阅读:
    Notes about "Exploring Expect"
    Reuse Sonar Checkstyle Violation Report for Custom Data Analysis
    Eclipse带参数调试的方法
    MIT Scheme Development on Ubuntu
    Manage Historical Snapshots in Sonarqube
    U盘自动弹出脚本
    hg的常用配置
    Java程序员的推荐阅读书籍
    使用shared memory 计算矩阵乘法 (其实并没有加速多少)
    CUDA 笔记
  • 原文地址:https://www.cnblogs.com/lichen782/p/4298615.html
Copyright © 2011-2022 走看看