【回文串5 重点+动态规划】LeetCode 132. Palindrome Partitioning II

LeetCode 132. Palindrome Partitioning II

Solution1:我的答案1
直接模仿131那道题的DFS解法,找其中size最小的。果不其然,因为超时只能部分AC。代码如下,仅供记录:

class Solution {
public:
    int minCut(string s) {
        vector<string> temp;
        vector<string> res;
        PalinDFS(s, 0, temp, res);
        return res.size() - 1;
    }

    void PalinDFS (string str, int start, vector<string> &temp, vector<string> &res) {
        if (start == str.size()) {
            if (res.size() == 0 || res.size() > temp.size())
                res = temp;
            return;
        } 
        for (int i = start; i < str.size(); i++) {
            if (isPalin(str, start, i)) {
                temp.push_back(str.substr(start, i - start + 1));
                PalinDFS(str, i + 1, temp, res);
                temp.pop_back();
            }
        }
    }

    bool isPalin(string str, int begin, int end) { //[begin, end]是[闭,闭]区间
        int left = begin, right = end;
        while (left < right) {
            if (str[left] != str[right])
                return false;
            else {
                left++;right--;
            }
        }
        return true;
    }
};

Solution2:
参考网址:https://blog.csdn.net/jingsuwen1/article/details/51934277
解题思路:动态规划问题。
dp[i]表示子串[0, i]的最小回文切割,则最优解在dp[s.length-1]中。[0, i]的子串中包括了i+1个字符。
分几种情况:
1.初始化:当字串s[0:i] (包括i位置的字符)是回文串时,dp[i] = 0(表示不需要分割);否则,dp[i] = i(表示至多分割i次);
2.对于任意大于1的i,如果s[j:i]( 1 =< j <= i,即遍历i之前的每个子串)是回文时,dp[i] = min(dp[i], dp[j-1]+1);
(注:j不用取0是因为若j == 0,则又表示判断(0,i))。
相对容易理解的动态规划方法。

class Solution {
public:
    int minCut(string s) {
        if (s.size() == 0) return 0;
        //dp[i]存放以i位置字符结尾的字符串的最小切割数,即所求为dp[s.size() - 1]
        int dp[s.size()];
        dp[0] = 0;//单个字符,无需切割
        for(int i = 0; i < s.size(); i++) {
            //dp[i]赋初值
            dp[i] = isPalin(s, 0, i)? 0 : i;
            //1 =< j <= i子串回文判定
            for (int j = i; j >= 1; j--) {
                if (isPalin(s, j, i))
                    dp[i] = min(dp[i], dp[j-1] + 1);
            }
        }
        return dp[s.size() - 1];
    }

    bool isPalin(string &str, int begin, int end) {
        while (begin < end) {
            if (str[begin] != str[end])
                return false;
            else 
                begin++;end--;
        }
        return true;
    }
};

//20180718日更新,DP算法真厉害啊!
class Solution {
public:
    int minCut(string s) {
        if (s.size() <= 1) return 0;
        int dp[s.size()];
        for (int i = 0; i < s.size(); i++) {
            dp[i] = isPalin(s, 0, i) == 1? 0:i;
            for (int j = 1; j <= i; j++) {
                if (isPalin(s, j, i)) {
                    dp[i] = min(dp[i], dp[j-1] + 1);
                }
            }
        }
        return dp[s.size() - 1];
    }

    int isPalin(string& str, int begin, int end) {
        while (begin < end) {
            if (str[begin] != str[end])
               return 0;
            else {
                begin++;
                end--;
            }
        }
        return 1;
    }
};

Solution3:更优化的动态规划方法
参考网址:
http://www.cnblogs.com/grandyang/p/4271456.html
这道题是让找到把原字符串拆分成回文串的最小切割数,需要用动态规划Dynamic Programming来做,使用DP的核心是在于找出递推公式,之前有道地牢游戏Dungeon Game的题也是需要用DP来做,而那道题是二维DP来解,这道题由于只是拆分一个字符串,需要一个一维的递推公式,我们还是从后往前推,递推公式为:dp[i] = min(dp[i], 1+dp[j+1] ) i<=j

//在20180719搞懂了。。。
class Solution {
public:
    int minCut(string s) {
        int len = s.size();
        bool P[len][len];
        int dp[len + 1];
        for (int i = 0; i <= len; ++i) {
            //之所以要初始化dp[len] = -1
            //是为了当 j + 1 == len时计算用
            dp[i] = len - i - 1;
        }
        for (int i = 0; i < len; ++i) {
            for (int j = 0; j < len; ++j) {
                if (i == j) 
                    P[i][j] = true;
                else
                    P[i][j] = false;
            }
        }
        for (int i = len - 1; i >= 0; --i) {
            for (int j = i; j < len; ++j) {
                //更新p[i][j]时要用到i + 1和j - 1,故i要从大到小遍历,j要从小到大遍历
                if (s[i] == s[j] && (j - i <= 1 || P[i + 1][j - 1])) {
                    P[i][j] = true;
                    //dp[i]表示从s[i, s.size()-1]部分(闭闭区间)字符串的最小分割数
                    dp[i] = min(dp[i], dp[j + 1] + 1);
                }
            }
        }
        return dp[0];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于计算机专业的学生而言,参加各类比赛能够带来多方面的益处,具体包括但不限于以下几点: 技能提升: 参与比赛促使学生深入学习和掌握计算机领域的专业知识与技能,如编程语言、算法设计、软件工程、网络安全等。 比赛通常涉及实际问题的解决,有助于将理论知识应用于实践中,增强问题解决能力。 实践经验: 大多数比赛都要求参赛者设计并实现解决方案,这提供了宝贵的动手操作机会,有助于积累项目经验。 实践经验对于计算机专业的学生尤为重要,因为雇主往往更青睐有实际项目背景的候选人。 团队合作: 许多比赛鼓励团队协作,这有助于培养学生的团队精神、沟通技巧和领导能力。 团队合作还能促进学生之间的知识共享和思维碰撞,有助于形成更全面的解决方案。 职业发展: 获奖经历可以显著增强简历的吸引力,为求职或继续深造提供有力支持。 某些比赛可能直接与企业合作,提供实习、工作机会或奖学金,为学生的职业生涯打开更多门路。 网络拓展: 比赛是结识同行业人才的好机会,可以帮助学生建立行业联系,这对于未来的职业发展非常重要。 奖金与荣誉: 许多比赛提供奖金或奖品,这不仅能给予学生经济上的奖励,还能增强其成就感和自信心。 荣誉证书或奖状可以证明学生的成就,对个人品牌建设有积极作用。 创新与研究: 参加比赛可以激发学生的创新思维,推动科研项目的开展,有时甚至能促成学术论文的发表。 个人成长: 在准备和参加比赛的过程中,学生将面临压力与挑战,这有助于培养良好的心理素质和抗压能力。 自我挑战和克服困难的经历对个人成长有着深远的影响。 综上所述,参加计算机领域的比赛对于学生来说是一个全面发展的平台,不仅可以提升专业技能,还能增强团队协作、沟通、解决问题的能力,并为未来的职业生涯奠定坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值