检查单词是否为句中其他单词的前缀
给出一个句子,句子是由若干个单词组成的,每个单词之间用 1 个空格隔开,检查给定的单词是 句子中 哪个单词的前缀
单词的下标从 1 开始,输出单词的编号
如果给定单词是多个单词的前缀,输出第一个是前缀的编号
如果这个单词不是句子中任何一个单词的前缀就输出 -1,表示无解
示例1:给出四个单词,给定单词 burg 是 第四个单词 burger 的前缀,输出 4
示例2:pro 是第 1 个 problem 和第 2 个 problem 的前缀,输出第 1 个 problem 的编号
示例3:you 不是任何一个单词的前缀,输出 -1
从前往后枚举句子中的所有的单词,判断当前枚举的单词是不是以给定单词为前缀的
①如何把字符串中的每个单词拿出来(找出所有的单词)
iostream:从标准输入输出中读入读出
fstream:从文件中读入读出
stringstream:从字符串中读入读出
②如何判断当前单词是否是某个单词的前缀(判断字符串 A 是不是字符串 B 的前缀)
substr():返回 B 的某一个子串,想判断 A 是不是 B 的前缀,只需要判断 B.substr()从 0 开始的长度是 size 的字符串是不是等于 A
B.substr(0,A.size()) == A
substr() 如果 searchWord 长度超过给定串 word 的长度不会报错,会取到最后一个字符截止,有几个取几个
word == 4,searchWord == 5,只会取四个字符
class Solution {
public:
int isPrefixOfWord(string sentence, string searchWord) {
//定义 stringstream 用 sentence 初始化
stringstream ssin(sentence);
string word;
//每次从 stringstream 中读出一个字符串
for(int i = 1;ssin >> word;i++ ) {
//判断 searchWord 是不是当前 Word 的前缀
if(word.substr(0,searchWord.size()) == searchWord) {
return i;
}
}
return -1;
}
};
定长子串中元音的最大数目
给出一个字符串 s 和整数 k
在字符串中找到所有长度是 k 的子串,在所有长度为 k 的子串当中哪个子串包含的元音字母数量最多,输出最大个数
示例1:k = 3,看一下所有长度是 3 的子串,看一下哪个子串中包含的元音字母数量最多
a b c i i i d e f
a b c 1
b c i 1
c i i 2
i i i 3
i i d 2
i d e 2
d e f 1
不能暴力求解:不能先枚举所有子串,再扫描这个子串中有多少个元音字母,时间复杂度为 O( n^k ) 10^10,时间复杂度应该控制在 10^8 内
动态维护区间:一开始维护区间 abc 里面的元音数量是 1,每次把整个区间往后移动一格,其实就是把下一个字母加进来(把 i 加进来,把 a 删去). . .
每次往后移动一格,最多只会加一个字母,只会删一个字母,每移动一次需要的操作都是 O( 1 ),就可以用线性的方法把每一个区间中的元音字母数量统计出来
C++:unordered_set的count_百步送剑的博客-CSDN博客_unordered_set的count
class Solution {
public:
int maxVowels(string s, int k) {
//定义 res 表示最大值
int res = 0;
//开一个哈希表存储所有的元音-> 用于判断每个字符是不是元音
unordered_set<char> S({'a','e','i','o','u'});
//从前往后扫描所有的字符串 cnt用于动态记录有多少个元音字母
for(int i = 0,cnt = 0;i< s.size();i++ ) {
//如果元素存在于容器中,则此函数返回1,否则返回0
cnt += S.count(s[i]);
//表示当前已经把前 k 个字母加进来了-> i 每次向后移动一个后一定要把最前面一个删掉
if(i >= k) cnt -= S.count(s[i - k]);
//表示已经有 k 个数了-> 更新答案 0 ~ k - 1表示区间中已经包含 k 个数
if(i >= k - 1) res = max(res,cnt);
}
return res;
}
};
二叉树中的伪回文路径
给出一个二叉树,二叉树的每个节点都有一个权值,权值为 1 ~ 9
二叉树的一条路径是伪回文的,满足路径上的所有数,如果存在一种给它重新排序的方式,使得它变成回文串
2 2 2 2 1
2 2 1 2 2
把能够通过调整变成回文的串称为伪回文串,只需要判断伪回文串中每个字符出现的次数是奇数还是偶数,如果没有任何一个字符出现的次数是奇数,或者只有一个字符出现的次数是奇数,就是伪回文,如果有两个以上(包括两个)字符出现的次数是奇数,那么这两个字符一定不能对应起来,如果只有一个的字符的话,可以把它放在中间
如果一个串是伪回文串,等价于最多只有一个字符出现的次数是奇数
伪回文串是对应树从根节点到叶节点的路径来说的,判断从根节点到叶节点的路径中,有多少条路径是伪回文串( DFS ),只需要把所有从根节点到叶节点的路径遍历一遍,依次判断每条路径是不是回文串即可
示例1:有 3 个叶节点,所以有 3 条从根到叶节点的路径
2 3 3→ 3 2 3,所以 233 是 一 个伪回文串
2 3 1,不是伪回文串
2 1 1→1 2 1,所以 211 是 一 个伪回文串
由于 一 共有 2 个伪回文串,所以返回 2
数据范围(节点数量)为1 ~ 10^5 之间,时间复杂度要控制在 O( n ),最多为 O( nlogn )
①节点数量 ≥ 1,树不为空
②每个节点的权值是 1 ~ 9
DFS遍历,遍历过程中每次记录所有从根节点到叶节点的路径,统计 1 ~ 9 每个数出现的次数(开一个长度为 10 的数组),单独判断每条路径是否满足条件,如果满足条件答案 + 1
c++ 里面的map容器的迭代器first、second用法_漂过的博客-CSDN博客_c++ map second
关联容器:unordered_map详细介绍(附可运行代码)_weixin_30448685的博客-CSDN博客
遍历二叉树,当遍历到叶节点的时候,判断数组中是否存在两个奇数数字个数就可以了,当判断结束后或者递归结束后,将计数恢复成原始状态,避免对后面产生影响
因为一个回文路径只能有一个或 0 个奇数的数字个数,比如101只有1个奇数数字个数(1个0),11只有0个奇数数字个数(0个0),12因为有2个奇数数字个数(1个1,1个2),怎么排列都不是回文数,所以不是伪回文路径
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
//哈希表用于统计 1 ~ 9 每个数出现多少次
unordered_map<int,int> cnt;
int pseudoPalindromicPaths (TreeNode* root) {
//每次递归前先把当前节点的值存在哈希表中
cnt[root->val] ++;
//判断是不是叶子节点-> 当前节点没有左子树并且没有右子树
if(!root->left && !root->right) {
//记录符合要求的路径数
int t = 0;
//统计当前的路径上,值为奇数的个数 如果为奇数的个数 > 1 那么一定不能组成回文串
for(auto item : cnt)
if(item.second % 2)
t++;
//返回之前需要回溯-> 当前值-- 意味着回到当前节点的父节点
cnt[root->val] --;
//t<=1 返回1 t>1 返回0
return t <= 1;
}
int res = 0;
//遍历左右子树
if(root->left) res += pseudoPalindromicPaths(root->left);
if(root->right) res += pseudoPalindromicPaths(root->right);
//恢复
cnt[root->val] --;
return res;
}
};
两个子序列的最大点积