• [LeetCode] 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.

    http://blog.csdn.net/yutianzuijin/article/details/16850031

    定义状态 f(i,j) 表示区间 [i,j] 之间最小的 cut 数,则状态转移方程为
    f(i, j) = min { f(i, k) + f(k + 1, j) } , i  <=k <= j, 0 < i <=  j <= n

    我们求解的是整个字符串的最小cut数,可以从字符串的头开始,也可以从尾部开始

    原问题的目的是求一个最小的划分,如果利用count矩阵则会求从位置i开始的每一个可能划分,实际上这是在做无用功。原因就在于f矩阵的第二维为划分个数,这一维对求最小值问题没有意义,我们可以去掉。所以我们重新定义一个新的一维count数组,用来表示从位置i开始到最后的最小划分个数。这时有公式:

    公式的含义是,从i开始的字符串的最小划分为:如果从位置i到位置j的子串是回文串,则从i开始的划分可以通过将i到j的子串看作划分的一部分,然后加上从j+1位置开始的子串最小划分,并选择可能情况中的最小值即为从i开始的最小划分。

    所以可以分两步求解:

    1. 计算 p[i][j],表示s[i][j]是否是回文字串,

    2 计算f[i],也就是count[i]

    class Solution {
        public:
            int minCut(string s) {
    
                const int n = s.size();
                bool p[n][n]; // whether s[i,j] is palindrome
                fill_n(&p[0][0], n * n, false);
                for (int i = n - 1; i >= 0; --i)
                    for (int j = i; j < n; ++j)
                        p[i][j] = s[i] == s[j] && ((j - i < 2) || p[i + 1][j - 1]);
    
                int f[n]; // s[i,n-1] has cut number
                for (int i = 0; i < n; ++i)
                {
                    f[i] = n-1-i;
                }
    
                for (int i = n - 1; i >= 0; --i)
                {
                    for (int j = i; j < n; ++j)
                    {
                        if(p[i][j])
                        {
                            if(j == n-1)
                                f[i] = 0;
                             else
                                 f[i] = min(f[j+1]+1, f[i]);
                        }
                    }
                }
    
    #if 0
                for (int i = 0; i < n; ++i) 
                {
                    cout << f[i] << "	";
                }
                cout << endl;
    #endif
                return f[0];
            }
    };

    转一个,更加紧凑的code

    // LeetCode, Palindrome Partitioning II
    // 时间复杂度 O(n^2),空间复杂度 O(n^2)
    class Solution {
        public:
            int minCut(string s) {
                const int n = s.size();
                int f[n+1];
                bool p[n][n];
                fill_n(&p[0][0], n * n, false);
                //the worst case is cutting by each char
                for (int i = 0; i <= n; i++)
                    f[i] = n - 1 - i; // 最后一个 f[n]=-1
                for (int i = n - 1; i >= 0; i--) {
                    for (int j = i; j < n; j++) {
                        if (s[i] == s[j] && (j - i < 2 || p[i + 1][j - 1])) {
                            p[i][j] = true;
                            f[i] = min(f[i], f[j + 1] + 1);
                        }
                    }
                }
                return f[0];
            }
    };
  • 相关阅读:
    后缀数组 (Suffix Array) 学习笔记
    Miller-Rabin 素性测试 与 Pollard Rho 大整数分解
    [ USACO 2013 OPEN ] Photo
    清华集训2016做题记录
    「UNR#2」黎明前的巧克力
    「UNR#1」奇怪的线段树
    Atcoder Grand Contest 018 E
    「NOI2015」小园丁与老司机
    「集训队作业2018」三角形
    Codeforces 878 E. Numbers on the blackboard
  • 原文地址:https://www.cnblogs.com/diegodu/p/3853537.html
Copyright © 2020-2023  润新知