动态规划——子数组系列(单词拆分)

文章介绍了如何使用动态规划解决字符串查找问题,涉及状态表示、状态转移方程、初始化和填表顺序。主要运用了哈希表、字符串操作和状态转移技巧来确定给定字符串是否能由字典中的单词拼接而成。
摘要由CSDN通过智能技术生成

      本节,对于我个人而言不只是学会了做这一题,更多的是学到了更多解题技巧,如哈希表,set.count()计数器,substr(字符串下标,字符串长度)字符串数组像整形数组一样多开一个空间,在字符串数组第一个位置留下一个空字符和建立一个vector<bool> bool类型的dp表等。

我们先分析题目要求,像此类查找字符串的问题十分常见。如:在一个较长的字符串中去查找一个单词出现的次数等问题。该问题就是要求找到所有能在字典中找出能够拼接出s字符串的单词,返回true。

 首先,动态规划5步走:

1.状态表示:

2.状态转移方程

3.初始化

4.填表顺序

5.返回值

那么一,状态表示:

我们先建立dp[i]表,dp[i]:就表示[0,i]区间内的字符串,能否被字典中的单词拼接而成,能->返回true,不能->就返回false。

二:状态转移方程

首先根据最后一个位置的情况来划分问题,在i位置结束时,dp[i]:就表示[0,i]区间内的字符串,能否被字典中的单词拼接而成,那么在i位置之前与i位置能分成两个模块,即设j为最后一个单词的起始位置。那么在s[j,i]区间就是最后一个单词的区间,在dp[j-1]就是字符串s[0,j-1]位置判断这个字符串能否被字典中的单词拼接。

三:初始化

由于,为了字符串s能与我们填入的下标一一对应,且让字符串从首字符开始就能进入我们的填表环节,那么就将字符串s的首字符置为‘  ’空字符。即s=' '+s;就可以完成字符串的内容往后移动一位,让下标映射关系一一对应。

四:填表顺序:从左往右,五:返回值:是返回字符串在[0,n]区间内,能否被字典中的单词拼接而成,即返回 dp[n];

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        int n=s.size();
        set<string> hash;
        for(auto s:wordDict)//将字典里的单词都存入hash中,便于查找
        hash.insert(s);

        vector<bool> dp(n+1);//建立一个bool值的dp表
        dp[0]=true;//初始化为true,就不会影响后面的值
        s=' '+s;//移动字符串的下标,对应映射关系
        for(int i=1;i<=n;i++)
        {
            for(int j=i;j>=1;j--)//最后一个单词的起始位置
            {
                if(dp[j-1]&&hash.count(s.substr(j,i-j+1)))//i-j+1,是最后一个单词的长度,在哈希表里面寻找他出现的次数
//最后一个单词的长度慢慢变长,来开始判断
                {
                    dp[i]=true;//只要有一个满足条件就可以结束判断
                    break;
                }
            }
        }
        return dp[n];
    }
};

 

for(auto s:wordDict)//将字典里的单词都存入hash中,便于查找

 vector<bool> dp(n+1);//建立一个bool值的dp表

if(dp[j-1]&&hash.count(s.substr(j,i-j+1)))//i-j+1,是最后一个单词的长度,在哈希表里面寻找他出现的次数
//最后一个单词的长度慢慢变长,来开始判断.

该环绕字符串只是多了一个条件从'a'->'z',那么就还时创建dp表,dp[i]表示:以i位置的元素为结尾所有子串里面,有多少个在base中出现过,那么必要条件就是以i位置为结尾

状态转移方程:分两种情况考虑,一就是当长度为1时,就是说明自己的字符绝对在字符串中存在一个子串。当长度大于1时,说明就有要细分,当s[i-1]与s[i]的关系。得出这是dp[i-1]所出现的次数

那么就将dp表初始化为1,就可以不用在填表阶段去考虑长度为1的情况

返回值也是一个难点:并不是返回dp表里所有元素的值,而是要返回已经去掉重复字符串所出现次数的和,就是取以某一个字符为结尾,所包含最大次数的和

class Solution {
public:
    int findSubstringInWraproundString(string s) {
        int n=s.size();
        vector<int> dp(n,1);
        for(int i=1;i<n;i++)
        {
            if(s[i-1]+1==s[i]||s[i-1]=='z'&&s[i]=='a')
            {
                dp[i]+=dp[i-1];
            }
        }
        vector<int> hash(26);
        for(int i=0;i<n;i++)
            hash[s[i]-'a']=max(hash[s[i]-'a'],dp[i]);//取出以某一字符为结尾,在字符串中出现最多次的子字符串保留在这个hash数组中

        int _max=0;
        for(auto e: hash)
        _max+=e;
        return _max;    
    }
};

若有不足,欢迎留言~

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值