力扣高频|算法面试题汇总(一):开始之前
力扣高频|算法面试题汇总(二):字符串
力扣高频|算法面试题汇总(三):数组
力扣高频|算法面试题汇总(四):堆、栈与队列
力扣高频|算法面试题汇总(五):链表
力扣高频|算法面试题汇总(六):哈希与映射
力扣高频|算法面试题汇总(七):树
力扣高频|算法面试题汇总(八):排序与检索
力扣高频|算法面试题汇总(九):动态规划
力扣高频|算法面试题汇总(十):图论
力扣高频|算法面试题汇总(十一):数学&位运算
力扣高频|算法面试题汇总(二):字符串
力扣链接
目录:
- 1.验证回文串
- 2.分割回文串
- 3.单词拆分
- 4.单词拆分 II
- 5.实现 Trie (前缀树)
- 6.单词搜索 II
- 7.有效的字母异位词
- 8.字符串中的第一个唯一字符
- 9.反转字符串
1.验证回文串
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: “A man, a plan, a canal: Panama”
输出: true
示例 2:
输入: “race a car”
输出: false
思路:使用两个指针,一个从左边开始,一个从右边开始,挨着比较,需要处理的是:1.大写变小写。2. 如果不是字母或者数字,则跳过。
C++
class Solution {
public:
bool isPalindrome(string s) {
// 转换成小写字母
transform(s.begin(),s.end(), s.begin(), ::tolower);
int length = s.size();
int i = 0;
int j = length -1;
while(i < j){
// 判断是否是数字和英文字符
if(!isalnum(s[i])){
//!(s[i]<='9' && s[i] >= '0' && s[i] <= 'z' && s[i] >= 'a')
++i;
continue;
}else if(!isalnum(s[j])){
--j;
continue;
}
// 转换大小写
char a = s[i];
char b = s[j];
if(a == b){
++i;
--j;
}else{
return false;
}
}
return true;
}
};
Python
class Solution:
def isPalindrome(self, s: str) -> bool:
pl = 0
pr = len(s) - 1
while pl < pr:
if not s[pl].isalnum():
pl += 1
continue
elif not s[pr].isalnum():
pr -= 1
continue
if s[pl].lower() == s[pr].lower():
pl += 1
pr -= 1
else:
return False
return True
2.分割回文串
给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。
返回 s 所有可能的分割方案。
示例:
输入: “aab”
输出:
[
[“aa”,“b”],
[“a”,“a”,“b”]
]
参考回溯法
总结一下:
- 1.把字符串“aab”,按长度n(n <= 字符串的长度)进行分割。
- 2.n从1开始。
- 3.start=0,n=1时,按顺序对字符串进行分割,首先得到”a“,判断满足回文要求,进行回溯,end=1。
- 4.下一次开始,start=1,得到”a“,判断满足回文要求,进行回溯,end=2。
- 5.下一次开始,start=2,得到”b“,判断满足回文要求,进行回溯,end=3。
- 6.下一次开始,start=3,已经>=字符串的长度(3),得到分割结果,进行保存,结束回溯,return到上次回溯的的地方,即start=2,然后把res中保存的最后一个结果弹出,此时res中为[“a”, “a”],并依次回溯到start=0,end=1的地方,此时res中的元素已经全部弹出,为空。
- 7.进行下一次for循环,end=2,即分割长度为2,依次进行判断…
C++
class Solution {
public:
// 保存所有的分割结果:
vector<vector<string>> split_results;
vector<vector<string>> partition(string s) {
if(s.size() == 0)
return split_results;
// 单次分割成回文串的结果
vector<string> res;
// 使用回溯法进行结果查找
back(s, 0, res); // s: 完整的字符串, 0: 开始的位置, res: 单次分割的结果
return split_results;
}
void back(string s, int start, vector<string> res){
// 首先判断回溯停止条件
if( start >= s.size()){
// 保存单次分割结果
split_results.push_back(res);
return ;
}
for(int end = start + 1; end < s.size() + 1; ++end){
// 截取字符串
string split_s = s.substr(start, end - start);
// 回文串判断
if (isPalindrome(split_s)){
// 添加当前符合要求的字符串
res.push_back(split_s);
// 回溯
back(s, end, res);
// 弹出栈顶
res.pop_back();
}
}
}
// 是否是回文串判断
bool isPalindrome(string s){
if(s.size() == 0)
return false;
int start = 0;
int end = s.size() -1;
while( start < end){
if(s[start] == s[end]){
++start;
--end;
}else{
return false;
}
}
return true;
}
};
Python
class Solution:
# def partition(self, s: str) -> List[List[str]]:
def partition(self, s):
# 保存分割下来的结果
self.split_results = []
if len(s) == 0:
return self.split_results
# 单次分割的结果
res = []
# 回溯法进行查找
self.back(s, 0, res) # s: 需要分割的字符串 0:起点位置 res:单次分割的结果
return self.split_results
# 回溯法
def back(self, s, start, res):
# 回溯的截止条件
if start >= len(s):
# 一次回溯结束
# 对res进行拷贝,防止弹出时,split_results数据变化
resCopy = res.copy()
self.split_results.append(resCopy)
return
# 以start开始,截取字符串进行判断