【字符串】【双指针+哈希表+滑动窗口】1、验证回文串II+2、两数之和II-输入有序数组+3、有效的字母异位词+4、找到字符串中所有字母异位词+5、字符串的排列

依旧是2道简单+3道中等!

提前说明

题1和2:双指针
题3:哈希表
题4和5:滑动窗口

1、验证回文串II(难度:简单)在这里插入图片描述

该题对应力扣网站

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;

    }
};
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

每天都要学算法(努力版)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值