单词拆分 - 不是很理解 - 需要重新编辑

*************

C++

题目:139. 单词拆分 - 力扣(LeetCode)

*************

简单看一眼题目:

这个就是判断是否是子集的问题。突然想到这个题目在实际生活中有哪些应用呢,不然做题没有啥积极性。第一个想到的就是我高中考试的时候,那个英语卷子有整整16页,然后我脑子里的wordDict并没有那么多的词汇,导致我输出的时候经常输出不对。就好像一个女孩子说 'Hey, you are the apple of my eye.' 然后呢,我的wordDict不允许我浪漫,就会输出‘嚯,这女的说你是她眼里的异物,这个异物有苹果那么大,搁这阴阳怪气你呢。’

好的,这个起手肯定就是,到这里我不是很确定了,之前的起手都是

int n = array.size();

但是这里没有array,拔剑四顾心茫然。但是除了矩阵,我还喜欢穷举,那就直接举例子吧,如果我是世界上最NB的芯片,我看一眼就知道 s 在不在 m 里,虽然不知道大脑怎么处理的,但是就是一眼就能看出来谁是sm。好的,对于计算机来说,可能优势就是非常的严谨,计算非常的快速,那就直接暴力的穷举,也是很优雅的,就好像Dr. Strang一样。

奇异博士没档期,请卷福来客串一下。

在‘最长回文子串’中学到的一个小技巧在这里用到了,s.substr(0, 1)表示在s中,从第一个字母开始取字母,只取第一个字母。这里举一反三一下,某天张三去了一个商K,妈妈桑领进来一串字母,你在心里从左到右给他们标上了0-13的编号,这里共14个字母,对妈妈桑说‘s.substr(1,2)’,妈妈桑就懂了,从左往右数,第一个字母开始,安排两个到你的 char 里面,为啥要char 而不是 int 呢?因为char相当于大床房,有1个字节,最多可容纳8位。但是 int 有2个字节,相当于标间了。

这里又学到一个新的语法, unordered_set, 这个代表启用快速查找,有很多多的优点:

  1. 查找效率unordered_set 在 C++ 中是基于哈希表实现的,它提供了平均时间复杂度为 O(1) 的查找性能。这意味着检查一个单词是否存在于 wordDict 中是非常快速的。

  2. 避免重复unordered_set 只存储唯一的元素,如果 wordDict 中有重复的单词,使用 unordered_set 可以自动去除重复项,虽然在这个特定问题中,重复单词是被允许的,但去除重复项可以减少哈希表的大小,从而可能提高性能。

  3. 代码简洁性:使用 unordered_set 可以简化代码,因为不需要额外的数据结构来存储单词,也不需要手动检查单词是否已经存在于集合中。

  4. 直接访问unordered_set 提供了直接访问其元素的能力,这意味着你可以快速地遍历所有的单词,这对于动态规划中的子问题解决是非常有用的。

  5. 算法要求:在动态规划中,我们需要频繁地检查子串是否为 wordDict 中的单词。如果使用其他数据结构,如 vectorlist,查找操作的时间复杂度将是 O(n),这将大大降低算法的效率。

  6. 实现简单unordered_set 的使用非常简单,可以直接使用构造函数从 vector 构造,不需要手动插入每个元素。

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        // make words in wordDict store in unordered_set, for quick finding
        unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
        
        vector<bool> dp(s.size() + 1, false); //need a extra room for check if dp[i] can be accessed from the back
        dp[0] = true; // can be accessed from the back
        
        
    }
};

接下来是写主代码逻辑了,矩阵虽然不用,但是矩阵永远都在。

就是说,i得确保整个string都被检查到,因为不确定string中的第几个字母组成的单词是可以在字典中被找到的,所以我直接穷举。这样不管第几个字母开头的几位数的单词,都确保在字典中被比对。

举例, 假设我得到一个 字符串s = "leetcode"  和 字典 wordDict = {"leet", "code"}。

观察到leetcode有8个字母,但是这里要设置一个9位数的string的长度,先别管为什么要多一位,直接暴力优雅学:

  • i = 1 时,检查 s.substr(0, 1)(即 "l"),它不在字典中,所以 dp[1] = false

  • i = 2 时,检查 s.substr(0, 2)(即 "le"),它不在字典中,所以 dp[2] = false

  • i = 3 时,检查 s.substr(0, 3)(即 "lee"),它不在字典中,但是 s.substr(0, 1)(即 "l")不在字典中,s.substr(1, 2)(即 "ee")也不在字典中,所以 dp[3] = false

  • i = 4 时,检查 s.substr(0, 4)(即 "leet"),它在字典中,所以 dp[4] = true

  • i = 5 时,检查 s.substr(0, 5)(即 "leetc"),它不在字典中,但是 s.substr(0, 4)(即 "leet")在字典中,且 s.substr(4, 1)(即 "c")不在字典中,所以 dp[5] = false

  • i = 6 时,检查 s.substr(0, 6)(即 "leetco"),它不在字典中,但是 s.substr(0, 4)(即 "leet")在字典中,且 s.substr(4, 2)(即 "co")不在字典中,所以 dp[6] = false

  • i = 7 时,检查 s.substr(0, 7)(即 "leetcod"),它不在字典中,但是 s.substr(0, 4)(即 "leet")在字典中,且 s.substr(4, 3)(即 "cod")不在字典中,所以 dp[7] = false

  • i = 8 时,检查 s.substr(0, 8)(即 "leetcode"),它不在字典中,但是 s.substr(0, 4)(即 "leet")在字典中,且 s.substr(4, 4)(即 "code")在字典中,所以 dp[8] = true

又得学习一个新的用法,wordSet.find(s.substr(j, i - j)) 尝试在 wordSet 中查找子串 s.substr(j, i - j)。如果这个子串存在于 wordSet 中,find() 会返回一个指向该子串的迭代器。如果子串不存在,find() 会返回 wordSet.end()

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        // make words in wordDict store in unordered_set, for quick finding
        unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
        
        vector<bool> dp(s.size() + 1, false); //need a extra room for check if dp[i] can be accessed from the back
        dp[0] = true; // can be accessed from the back
        
        // from 1,cuz dp[0] has been initialised true
        for (int i = 1; i <= s.size(); ++i) {
            for (int j = 0; j < i; ++j) {
                // if the first j element can be scrambled,and the substring between j and i-1 of s is in wordSet
                if (dp[j] && wordSet.find(s.substr(j, i - j)) != wordSet.end()) {
                    dp[i] = true;
                    break; // once finded, then break
                }
            }
        }
        
        return dp[s.size()];
    }
};

今天的学习有点超标了,我不是很明白那个最后一段的 if 判断语句,我明天再看看,如果有新的理解,我会在这个基础上继续更新。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值