8.15 哈希表中等 139 Word Break review 467 Unique Substrings in Wraparound String

139 Word Break【逐一对比vs.多种 分割 组合】

在这里插入图片描述
在这里插入图片描述

片面思考的思路:

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        //字符串和对应的字典,如果s种可以用空格分隔出一个或多个字典里的词就返回true
        //核心:按照字典里的词对s断句,对s遍历,如何判断s种有多余的字母是字典中不包含的?
        //细节:字典里的词会被多次使用,且不按顺序出
        //在这道题中,哈希表是怎么使用的?是存储字典中出现的单词个数?还是存储s中的单词出现的位置?
        //如何确定单词范围?对dic也是一个一个比较吗?比较后怎么锁定s中的位置?
        //单词范围由wordDic[i].size()确定,通过substr(pos,len)确定子串中的位置,哈希表用于存储开始位置和单词长度
        //是哪个循环套哪个循环?
        //因为一个字典会在s中多次出现且s的长度最大值才300所以Dic中嵌套s
        //如何让s遍历的时候跳过已经判断出的范围?或者说如何判定s没有被排除完?
        //s.replace(pos,len,'0')那这样就不需要哈希表了啊,直接最后遍历一遍是否全为0就好了
        //unordered_map<int,int> StartAndLength;
        int index = 0;
        for(int i = 0 ; i < wordDict.size();i++){
            int len = wordDict[i].size();
            int index = 0;//每次都从头开始遍历
            while(index < s.size()){
                if(s[index] == wordDict[i][0] && s.substr(index,len) == wordDict[i]){
                    //StartAndLength[index] = len;
                    s.replace(index,len,string(len,' '));
                    index+=len;
                }else{
                    index++;
                }
            }
        }
        for(char ch : s){
            if(ch != ' '){
                return false;
            }
        }
        return true;
    }
};

分析思路过程:

按照字典里的词对s断句,对s遍历,如何判断s种有多余的字母是字典中不包含的?
细节:字典里的词会被多次使用,且不按顺序出
在这道题中,哈希表是怎么使用的? 是存储字典中出现的单词个数?还是存储s中的单词出现的位置?-----》都是对中间态的记录,没有考虑哈希表的快速查找
如何确定单词范围? 对dic也是一个一个比较吗?比较后怎么锁定s中的位置?
单词范围由wordDic[i].size()确定,通过substr(pos,len)确定子串中的位置,哈希表用于存储开始位置和单词长度-------》没有考虑多种组合的情况
//是哪个循环套哪个循环?
//因为一个字典会在s中多次出现且s的长度最大值才300所以Dic中嵌套s

如何让s遍历的时候跳过已经判断出的范围?或者说如何判定s没有被排除完?
完全遍历一遍,所以主体还是对s的遍历

在这里插入图片描述

在这里插入图片描述

重新思考这道题目

按照难度来说,中等题也不太可能使用逐一对比+替换就能解决这个问题;
按照题型来说,这道题肯定需要用哈希表来解决
重新思考这道题,复盘哪些问题需要继续去思考的:

  • 在这道题中,哈希表是怎么使用的?
  • 如何确定单词范围?
  • 如何判断s中有多余的字母是字典中不包含的?---->这个是多种组合?

第一个问题: 哈希表可以完成字典的快速查找unordered_set,记录中间状态 unordered_map;
如果是前一种,也就是将wordDict变了一下,用于快速查找s子串种是否是字典中的单词hash.find(s.substr(pos,len)) != hash.end()就是查到了,这段子串是存在于hash中的。
【这种方式特别适合需要频繁查找字典的情况,因为 unordered_set 的查找操作具有平均 O(1) 的时间复杂度,非常高效。】
后一种的话,就是用哈希表记录检查过的字符串段,用于判断s已经被分割的字段,但这个不适合多种组合的情况,类似于逐一对比,认准一个死理不改变,所以还是使用字典的快速查找。
第二个问题: 单词范围一种是遍历,确定s中的开始位置使用while和Dict中的单词逐一对比,已经被pass了;另一种是动态规划,动态规划尤其适用于需要检查多个可能分割点并且组合的情况,如字符串分割、路径问题等。
第三个问题: 实际上是回答怎么判定s是否可以被Dict中的单词们分割,结合第二个问题,使用动态规划划分单词范围,其中的dp[i]数组表示的是s中前i个字符是否可以被完全分割,如果在最终的dp数组中s.size()位置标记为false则表示无法分割。

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        //动态规划
        //要做的事情是确定s中前i位是否可以被分割 dp[i]
        vector<bool> dp(s.size()+1,false);
        unordered_set<string> wordSet(wordDict.begin() , wordDict.end());
        //初始条件dp[0] = true;
        dp[0] = true;
        //遍历string s找合适的切割组合
        for(int i = 1 ; i <= s.size() ; i++){
            //判定是否可以被分割
            for(int j = 0 ; j < i ; j++){
                //判定条件,关系式:wordSet.find(s.substr(j , i-j)) != wordSet.end()
                if(dp[j] && wordSet.find(s.substr(j , i-j)) != wordSet.end()){
                    //可以被分割
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp[s.size()];
    }
};

review 467 Unique Substrings in Wraparound String

在这里插入图片描述在这里插入图片描述

class Solution {
public:
    int findSubstringInWraproundString(string s) {
        //不同的非空的子串数目 不同+非空怎么判定-->记录数组dp 仅记录以26字母为结尾的
        //要找的是 且是不同的 存在于base中的子串 所以判定dp[i]为以i = ch - 'a'为索引,以ch为结尾的最长子串
        vector<int> dp(26,0);
        int maxLen = 0;
        //base的判定前者-后者为1 或者前者为z后者为a,记录长度
        for(int i = 0 ; i < s.size() ; i++){
            char ch = s[i];
            if(i>0 && (s[i] - s[i-1] == 1 || (s[i-1] == 'z' && s[i] == 'a'))){
                maxLen++;
            }else{
               //初始条件
               maxLen = 1;
            }
            dp[ch-'a'] = std::max(maxLen,dp[ch-'a']);
        }
        int ans = 0;
        for(int len : dp){
            ans += len;
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值