一、知识点总结
1、char ——> string
// 定义一个大小为1,值为 i+'a' 的字符串
string s(1, i + 'a');
2、定义数组
定义一个大小为26的数组,并将其初始化为 0
int arr[26] = {0};
3、数组填充问题
很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。
利用双指针,从后往前进行填充这么做有两个好处:
- 不用申请新数组。
- 从后向前填充元素,避免了从前先后填充元素要来的 每次添加元素都要将添加元素之后的所有元素向后移动
4、字符串和数组的差别
字符串是若干字符组成的有限序列,也可以理解为是一个字符数组,但是很多语言对字符串做了特殊的规定,接下来我来说一说C/C++中的字符串。
在C语言中,把一个字符串存入一个数组时,也把结束符 '\0’存入数组,并以此作为该字符串是否结束的标志。
在C++中,提供一个string类,string类会提供 size接口,可以用来判断string类字符串是否结束,就不用’\0’来判断是否结束。
那么vector< char > 和 string 又有什么区别呢?
其实在基本操作上没有区别,但是 string提供更多的字符串处理的相关接口,例如string 重载了+,而vector却没有。
所以想处理字符串,我们还是会定义一个string类型
5、最长回文串
解法一:KMP
解法二:马拉车 Manacher
解法三:动态规划
解法四:哈希
二、做题总结
第3题 最长不含重复字符
本题与 剑指offer48 相同
第14题 最长公共前缀
第205题 同构字符串
建立 s 与 t 的两个映射,从 s 到 t,或者是从 t 到 s ,
两个映射都要满足,财富和是同构关系,否则就是属于异构关系
第290题 单词规律
本题与 205 相似,都是两个映射关系。只不过这个题,一个是 <char, string>,一个是<string, char>
说是 easy 题,其实还是有点难啊~ 没见过这个套路的话,会很难想的到
1、关于两个字符串的处理
patten 串是一个一个字符来看
s 串是要自己做分割的,以空格为分界
2、关于映射关系
本题要建立两个映射关系,用哈希映射来对 pattern 和 s 建立一一对应的关系
ch2str
str2ch
这两个映射都满足才是符合题意,否则就return false
第1002题 查找常用字符
对 vector& word 这个原始字符串数组的处理,分为 第一个字符串 和 剩余字符串
这里因为是对单个字符的处理,因此可以用 大小为26的数组来代替
第一个字符串先映射到哈系数组int word[26] = {0}中
然后遍历剩下的字符串,每次遍历剩余字符串中的某个时,也需要建立一个临时的 哈系数组int temp[26] = {0}用来存储映射关系
对这个临时哈系数组映射之后,需要将其余第一个字符串的哈希数组进行比较,更新word是每个下标的都保证是最小值
最后遍历 word,取出对应的元素即可,注意这里是可以有重复元素,而且重复的元素也需要重复的输出
第49题 字母异位分组
本题感觉在联系 哈希映射的嵌套关系
对内层的处理还是很不容易想到的,使用到了 emplace_back()
-
哈希
-
用数组代替哈希
int arr[26] = {0}; // 初始化一个大小为26,初值为0的数组
-
char ——> string
// 定义一个大小为1,值为 i+'a' 的字符串
string s(1, i + 'a');
第249题 移位字符串分组
本题和49题·有点相似,都需要两层的映射关系
49题的处理,是把第一层的映射相当于按字典进行排序,将排序后得到的字符串作为第二次映射的 key
249题的处理,是把第一层的映射都映射为与a有相对距离的关系,然后将这个映射的结果作为 key
感觉这两题还是挺不容易想到的,有点难哦~
本题的两个映射过程
- 1、第一个映射:将原始的字符串 prestr 映射为以a开头的字符串 str,注意str的顺序已经发生了异位
ch = (ch - prestr[0] + 26) % 26 + 'a';
- 2、第二个映射:哈希映射,将映射后的字符串 str 作为哈希的 key,原始的字符串 prestr 作为 value,组成对
mp[str].push_back(prestr);
第151题 花式反转字符串
这个题好难呀!
给定一个字符串,逐个翻转字符串中的每个单词。
输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。输入: “the sky is blue”
输出: “blue is sky the”输入: “a good example”
输出: “example good a”
解题的思路:
整体反转+局部反转 的思想
- 移除多余空格(用双指针法。注意字符串的 前 中 尾 要分三种情况来处理)
- 将整个字符串反转
- 把每个单词反转
剑指58-2题
再来一道绝妙的题——左旋字符串
1、反转区间为前n的子串
2、反转区间为n到末尾的子串
3、反转整个子串经历了上一题的苦难这道题就轻松多了hhhhh
第692题 前K个高频单词
1、看到 前K大 这三个字,应该有 DNA 反应,可以用 堆排序,或者快速排序
2、关于怎么使用堆排序?
- 使用 lambda 表达式 + decltype
- decltype 被称作类型说明符,decltype的结果不是值,而是一个类型。它的作用是选择并返回操作数的数据类型,它的出现主要是解决复杂的类型声明。
- 使用 struct + 重载操作符()
这两种方式在细节处理上有所偏差,但是逻辑上类似,都是将哈希表中的元素全部取出来,建立一个大小为 K 的堆,里面不断排序,最后得到的就是前K大的单词了
3、怎么使用快速排序
- 逻辑:用一个数组将哈希表装起来,然后再里面找到第K大的数,然后根据快速排序的逻辑,保证下标为 [0, k-1] 上的数是前K大的数,但是这个排序的过程不能保证这K个数的顺序,因此需要再这K个数上再进行一次排序,最后输出即可。
解题思路
两步走
- 第一步:使用哈希表,统计相同字符串
- 第二步:在哈希表中,选出频次前K大的单词
时间复杂度分析
- 假设总共有n个单词,哈希表中单词数为m个,选出前k个高频单词,因此有 n ≥ m ≥ k
- 哈希映射 O(n)
- 堆排序 O(m logk)
- 快排分了两步,首先选出第K个大的元素O(m),然后对前k个数排序需要 O(k logk),所以总共是 O(m + klogk)