依旧是2道简单+3道中等!
提前说明
题1和2:双指针
题3:哈希表
题4和5:滑动窗口
1、验证回文串II(难度:简单)![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/1794675dbec0446aafc4023702ac36c6.png)
AC代码
还是双指针写的,跟题解的第一个思路一样,只是我写的代码不够简洁,有点耗时和占用内存。
思路是:
先按照判断是否是回文串的思路,l=0,r=n-1
然后遇到s[l]!=s[r]
再判断删除一个字符后是否还是回文串
分成三种情况:
1、s[l]==s[r-1]
2、s[l+1]==s[r]
3、以上两种情况都不是,直接return false
注意,第1、2、的情况都要考虑,是并列关系
最后回文串有两种情况:
1、不用删除字符
2、满足flag1==1 || flag2==1
只需要删除一个字符的情况
class Solution {
public:
bool validPalindrome(string s) {
int n = s.length();
int i,j,k,l=0,r=n-1,flag1=0,flag2=0;
while(l<=r){
if(s[l]==s[r]){
l++;
r--;
}
else{
break;
}
}
int temp1=l,temp2=r;
if(l>r){
//不用删除字符也是回文串
return true;
}
else{
l = temp1;
r = temp2;
if(s[l]==s[r-1]){
flag1++;
r--;
while(l<=r){
cout<<s[l]<<" "<<s[r]<<endl;
cout<<l<<" "<<r<<endl;
if(s[l]!=s[r]){
flag1++;
break;
}
l++;
r--;
}
}
l = temp1;
r = temp2;
if(s[l+1]==s[r]){
flag2++;
l++;
while(l<=r){
if(s[l]!=s[r]){
flag2++;
break;
}
l++;
r--;
}
}
l = temp1;
r = temp2;
if(s[l]!=s[r-1] && s[l+1]!=s[r]){
return false;
}
}
cout<<"flag1:"<<flag1<<endl;
cout<<"flag2:"<<flag2<<endl;
if(flag1==1 || flag2==1){
return true;
}
else{
return false;
}
}
};
2、两数之和II-输入有序数组(难度:中等)
AC代码
思路和之前做的三数之和思路基本一致,做的时候还是踩进了一个之前踩过的误区。
以后要根据数理逻辑关系来分析题目,不能简单通过测试例子来分析(要长记性!)
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int i,j,k;
int n = numbers.size();
j=n-1;
for(i=0;i<n;i++){
while(j>i && numbers[i]+numbers[j]>target){
j--;
}
if(numbers[i]+numbers[j]==target){
return {i+1,j+1};
}
}
return {i,j};
}
};
3、有效的字母异位词(难度:简单)
AC代码
(今天才知道之前博客里用的计算26个英文字母出现次数的方法叫做哈希表,笑了)
首先如果两个字符串长度不相同的话,那每个字符出现的次数也就不可能相同
然后对于长度相同的两个字符串, alpha[s[i]-'a']++; alpha[t[i]-'a']--;
,最后alpha[j]==0
说明对应字符出现次数相同。
class Solution {
public:
bool isAnagram(string s, string t) {
int alpha[26]={0};
int i,j,k;
int n1=s.length();
int n2=t.length();
if(n1!=n2){
return false;
}
for(i=0;i<n1;i++){
alpha[s[i]-'a']++;
alpha[t[i]-'a']--;
}
for(j=0;j<26;j++){
if(alpha[j]!=0){
return false;
}
}
return true;
}
};
4、找到字符串中所有字母异位词(难度:中等)
AC代码
我一点儿也没思路,直接看的题解
又学了一个新的知识点:滑动窗口
以下的代码是套用了题解里一位大佬labuladong的滑动窗口代码模板
果然模板很好用
详细解释可以看题解大佬的解释,讲的很清楚
(另外知道了,原来力扣里输出(cout)代码很耗时)
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector <int> answer;
//哈希表need用来标记子串,window用来标记窗口
unordered_map<char,int> need,window;
//先对子串的字符做统计
for(char c:p) need[c]++;
//left和right在窗口里都初始化为0,滑动窗口是左闭右开区间
int left = 0, right = 0;
int valid = 0; //用来记录窗口内满足子串要求的字符的类数(最多26)
while (right < s.size()) {
// c 是将移入窗口的字符
char c = s[right];
// 右移窗口
right++;
// 进行窗口内数据的一系列更新
if(need.count(c)){
window[c]++;
if(need[c]==window[c]){
valid++;
}
}
/*** debug 输出的位置 ***/
// cout<<left<<" "<<right<<endl;
/********************/
// 判断左侧窗口是否要收缩
//当窗口里的字符个数已经满足子串的要求
while (valid==need.size()) {
// d 是将移出窗口的字符
char d = s[left];
// 左移窗口
left++;
// 进行窗口内数据的一系列更新
if(need.count(d)){
window[d]--;
if(window[d]<need[d]){
valid--;
// cout<<"last:"<<right<<left<<endl;
if(right-left+1==p.length()){
answer.push_back(left-1);
}
}
}
}
}
return answer;
}
};
5、字符串的排列(难度:中等)
AC代码
依旧是滑动窗口,不多说了。
class Solution {
public:
bool checkInclusion(string s1, string s2) {
//哈希表
unordered_map<char,int> need,window;
//初始化need
for(char c : s1) need[c]++;
int left=0,right=0;
int valid=0;
while(right<=s2.size()){
//right右移扩大窗口,直到满足子串s1的条件
char d = s2[right];
right++;
//need.count(d)用来检测是否存在键值d
if(need.count(d)){
window[d]++;
if(need[d]==window[d]){
valid++;
}
}
//left右移,收缩滑动窗口
//在满足s1子串的条件下移动
while(valid==need.size()){
char m = s2[left];
left++;
if(need.count(m)){
window[m]--;
if(need[m]>window[m]){
valid--;
if(right-left+1==s1.length()){
return true;
}
}
}
}
}
return false;
}
};