1.字符串的旋转
给定abcdef,例如把字符串的前三个字符移动到后面。形如:defabc!
解法一:暴力法
每次所有字符串向前移动一位,移动m次即可。但是复杂度为O(mn)
解法二:三步反转法(类比结构的对称性)
通过m把字符串分割成两个字符串,然后对这两个字符串分别反转。最后在对字符串整体反转。
abcdef-- ba fedc -- cdef ab
扩展:对输入的英文单词进行反转:"i am a student." 变为 "student. a am i"!
是不是只要对每个单词翻转一次,在对整体翻转一次不就行了。
2.字符串的包含
给定长字符串a和短字符串b,要b中的元素在a中都出现过!
解法一:暴力法
枚举短字符b,判断在a中是否出现过。时间复杂度为O(m*n)
解法二:排序+暴力法
先对a和b字符排序,然后枚举b,只要a的字符大于b的字符那么就可以判断不包含,如果字符相等就下一个b字符,小于就找下一个a字符。
解法三:hash表(类似了计数排序方法)
把所有a字符都用hash表存储(用长度26的数组简单来模拟),然后遍历b字符进行查找。时间O(m+n)!
扩展:给定两个串a和b,问b是否是a的子串的变位词。例如输入a = hello, b = lel, lle, ello都是true,但是b = elo是false。
思路: 比如b的长度是3,则考察a[0..2], [1..3],[2..4]是否和b是变位词,需要hash表进行更新元素,
扩展:第一个只出现一次的字符?
思路一:暴力法是对每一个字符查找是否出现过,时间为N的平方;
思路二:哈希表可以进行加速线性时间可以完成;
3.字符串的全排列
输入字符串“abc”,按字典序排列,输出所有排列后的字符串"abc","acb","bac","bca"......
解法一:递归实现
每次固定一个位置,然后递归下去(第一个位置,第二个.....第n个),第一个位置可放n个,第二个可放n-1个,最后一个放一个。使用交换元素的思路,要注意交换后得交换回去复原!
字符串有重复的时候,当前元素只要没有与之前对应的元素相等那么就可以交换,否则不可以,因为start位置的元素已经交换过了这个元素!
4.字符串转化成整数
直接写出代码容易:从左向右使用n = n*10 + c公式即可!
ps:要判断空,要判断正负号,要判断字符串是否合法,要判断是否会溢出。
5.判断字符数组是否所有字符都出现过一次
思路一:使用哈希表来判断是否出现了重复。
思路二:进行排序但是题目要求空间复杂度为常量,所以快排(递归和非递归版本都需要空间),归并两个较快的使用不了,只能使用非递归的堆排序了。
6.字符串的调整与替换
把字符串的空格替换为"%20",设右半区足够大
思路:遍历左半区,计算出最终一共需要的位置,然后逆序遍历进行填补。
扩展:字符串中有字符"*"要把该字符全部移动到前面。
因为不用扩充字符,所以直接逆序遍历进行判断,再把前面的空字符填补成"*"。
7.数组中两个字符的最小距离
思路:需要两个指针和一个遍历指针,分别记录字符最近一次出现的位置,每更新一次位置就计算一次最短距离。
8.添加最少字符使字符串整体都是回文子串
思路:设dp(i,j)代表字符i到j为回文串的最少添加字符数。需要注意i到j只有一个字符,i到j有两个字符的特殊情况,i到j多于两个字符为一般情况, if s(i)=s(j) dp(i,j)=dp(i+1,j-1) if 不等,需要添加一个字符给i还是j找一个最小的即可,dp(i,j)=min(dp(i+1,j),dp(i,j-1))+1
扩展:如果需要打印出来构造的回文串,需要逆序遍历构造出来,注意判断在左边加字符还是在右边加字符。
9.回文最少分割数
思路一:使用暴力递归,每个位置分和不分,返回分割最少的即可,如果分那么前一部分必须是回文串。
思路二:dp(i)代表i到字符串结尾回文串的最少分割。在i到len中找到一个j,i到j必须为回文串找出分割最少的那个即可。dp(i)=min(dp(j+1)+1)i<=j<len。要快速判断i到j为回文串,需要构造一个数组boolean(i,j)代表i字符到j字符是否为回文串。
10.正则表达式匹配(自动机:动态规划 | DFS)
'*'表示它前面的字符可以出现任意次(包含0次)
思路:使用递归进行判断,如果当前位置的下一个元素是*,如果不是*,按这两种情况来处理。
class Solution {
public:
bool match(char* str, char* pattern) {
if(str==NULL||pattern==NULL)
return false;
return dfs(str,pattern);
}
bool dfs(char* str, char* pattern) {
if(*str=='\0'&&*pattern=='\0')
return true;
if(*str!='\0'&&*pattern=='\0')
return false;
if(*(pattern+1)=='*') {
if(*pattern==*str||(*pattern=='.'&&*str!='\0'))
return dfs(str+1,pattern)||dfs(str,pattern+2);
else
return dfs(str,pattern+2);
}
if(*str==*pattern||(*pattern=='.'&&*str!='\0'))
return dfs(str+1,pattern+1);
return false;
}
};
11.给定一个字符串,找出不含有重复字符的最长子串的长度。
思路:使用动态规划,dp(i)代表以第i个字符为结尾的最长子串,记录第i个字符最近一次出现的位置是否在dp(i-1)区域内
12.字符串匹配
思路一:KMP算法,是对暴力算法回溯的一种改进(不需要进行回溯,直接从原位进行匹配),并且新增引进了已经匹配字符串的最长公共前缀和后缀的概念(前缀和后缀相同模式串可以移位),让下一次从模式串开始匹配的位置尽可能大。
13.把一个0-1串(只包含0和1的串)进行排序,你可以交换任意两个位置,问最少交换的次数?
思路:最左边的那些0和最右边的那些1都可以不管;一个指针p1指向0的下一个字符和一个遍历指针
14.字符串的最长公共子串和最长公共子序列
公共子串
思路:都可以使用dp(i,j)来处理,代表s1以i结尾和s2以j结尾的最长公共子串;
公共子序列
思路:dp(i,j)代表s1在i和s2在j的最长公共子序列;字符相等(+1)字符不等(以每一个字符串为结尾取最大)
15.大数相加
思路:两个字符串进行相加,在返回字符串即可;处理好进位问题即可。
扩展:大数相乘
思路:按位相乘得到的结果,存起来,转化为大数相加问题
扩展:打印从 1 到最大的 n 位数
思路:每次确定一位,每次都确定为0~9直到位数够,进行打印即可。