leetcode刷题之双指针

注意:刷题建议来自 代码随想录 公众号

快慢指针

指针移动方向相同

leetcode27 移除元素

  1. 移除元素
    给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
    不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
    元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
    示例 1:
    输入:nums = [3,2,2,3], val = 3
    输出:2, nums = [2,2]
    解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
    示例 2:
    输入:nums = [0,1,2,2,3,0,4,2], val = 2
    输出:5, nums = [0,1,4,0,3]
    解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
class Solution {
public:
//原地移除数组 快慢指针法
//慢指针匀速,快指针在遇到value时加速度一格,慢指针正常前进,复制发生在慢指针前进前
//结束条件:快指针遍历结束
//注意:不要忘了极端情况:一直到末尾都等于value
    int removeElement(vector<int>& nums, int val) {
        int j=0;
        int i=0;
        for(;j<nums.size();)
        {
            while(j<nums.size()&&nums[j]==val)
            {
                j++;
            }
            if(j!=nums.size())
           { nums[i]=nums[j];
            j++;
            i++;
           }

        }
        return i;

    }
};

leetcode 283. 移动零

  1. 移动零
    给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
    示例:
    输入: [0,1,0,3,12]
    输出: [1,3,12,0,0]
class Solution {
public://参考leetcode27 value=0情况
    void moveZeroes(vector<int>& nums) {
int i=0;
int j=0;
for(;i<nums.size();)
{
    while(j<nums.size()&&nums[j]==0)
    {
        j++;
    }
    if(j<nums.size())
    {
        nums[i++]=nums[j++];
    }
    else
    nums[i++]=0;
}

    }
};

leetcode26 删除有序数组中的重复项

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例 1:
输入:nums = [1,1,2]
输出:2, nums = [1,2]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
示例 2:
输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

class Solution {
public:
//与27区别 27一个不留 26删几个留一个
//快指针遇到重复值加速至非重复值停止,慢指针遇到非重复值时前进一格,复制发生在慢指针前进时
//注意:由于return i+1在输入为空时需要单独考虑
    int removeDuplicates(vector<int>& nums) {
        int i=0;int j=0;
        if(nums.size()==0)
        return 0;//重点
        for(;j<nums.size();)
        {
            
            while(j<nums.size()&&nums[j]==nums[i])
            {
                j++;

            }
            if(j<nums.size())
            nums[++i]=nums[j++];//重点
        }
        
 return i+1;
    }
   
};

滑动窗口

leetcode 209长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0

class Solution {
public:
//滑动窗口的慢指针在快指针前,j(慢指针)正常移动,i快指针收缩窗口时加速
//
    int minSubArrayLen(int target, vector<int>& nums) {
        int i=0;int j=0;
        int add=0;
        int len=nums.size()+2;
        for(;j<nums.size();j++)//慢指针
        {
            add=add+nums[j];
            while(add>=target)//快指针
            {
                len=min(len,j-i+1);
                add=add-nums[i++];
                
            }}
           
   return len==nums.size()+2?0:len;
        }
    
       
    
};

leetcode 904水果成篮

  1. 水果成篮
    在一排树中,第 i 棵树产生 tree[i] 型的水果。
    你可以从你选择的任何树开始,然后重复执行以下步骤:
    把这棵树上的水果放进你的篮子里。如果你做不到,就停下来。
    移动到当前树右侧的下一棵树。如果右边没有树,就停下来。
    请注意,在选择一颗树后,你没有任何选择:你必须执行步骤 1,然后执行步骤 2,然后返回步骤 1,然后执行步骤 2,依此类推,直至停止。
    你有两个篮子,每个篮子可以携带任何数量的水果,但你希望每个篮子只携带一种类型的水果。
    用这个程序你能收集的水果树的最大总量是多少?
    示例 1:
    输入:[1,2,1]
    输出:3
    解释:我们可以收集 [1,2,1]。
    示例 2:
    输入:[0,1,2,2]
    输出:3
    解释:我们可以收集 [1,2,2]
    如果我们从第一棵树开始,我们将只能收集到 [0, 1]。
    示例 3:
    输入:[1,2,3,2,2]
    输出:4
    解释:我们可以收集 [2,3,2,2]
    如果我们从第一棵树开始,我们将只能收集到 [1, 2]。
    示例 4:
    输入:[3,3,3,1,2,1,1,2,3,3,4]
    输出:5
    解释:我们可以收集 [1,2,1,1,2]
    如果我们从第一棵树或第八棵树开始,我们将只能收集到 4 棵水果树。
class Solution {
public://最长字串,子串中包含两种数据
    int totalFruit(vector<int>& fruits) {
        unordered_map<int,int> a;
         int i=0;int j=0;
        int len=0;
        int ans=0;
        for(;j<fruits.size();j++)//慢指针
        {
            a[fruits[j]]++;
            len++;
            while(a.size()>2)//快指针
            {

               a[fruits[i]]--;
                if (a[fruits[i]] == 0) a.erase(fruits[i]);
                i++;
                len--;

                
            }
            ans=max(ans,len);
            }
           
   return ans;

    }
};

leetcode 76 最小覆盖子串

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

class Solution {    
public:
    string minWindow(string s, string t) {
        // 滑动窗口
        unordered_map<char, int> window, need;
        for (const char& c : t) {
            need[c]++;
        }
        int total = need.size();
        int left = 0, right = 0, start = 0, len = INT_MAX, valid = 0;
        while (right < s.length()) {
            // 滑入窗口
            char c = s[right];
            if (need.find(c) != need.end()) {
                window[c]++;
                if (window[c] == need[c]) valid++;
            } 
            right++;

            //判断左侧窗口是否需要收缩
            while (valid == need.size()) {
                 // 在这里更新最小覆盖子串
                 if (right - left < len) {
                     start = left;
                     len = right - left;
                 }
                 //d是将移出窗口的字符
                 char d = s[left];
                 //左移窗口
                 left++;
                 //进行窗口内数据更新
                 if (need.find(d) != need.end()) {
                     if (window[d] == need[d])
                        valid--;
                    window[d]--;
                 }
            }
           
        }
        return len == INT_MAX ? "":s.substr(start,len);

    }
};

作者:fxlego
链接:https://leetcode-cn.com/problems/minimum-window-substring/solution/hua-dong-chuang-kou-jing-dian-jie-fa-mo-3ez4q/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。


剑指offer016 不含重复字符的最长子串

剑指 Offer II 016. 不含重复字符的最长子字符串
给定一个字符串 s ,请你找出其中不含有重复字符的 最长连续子字符串 的长度。
示例 1:
输入: s = “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子字符串是 “abc”,所以其长度为 3。
示例 2:
输入: s = “bbbbb”
输出: 1
解释: 因为无重复字符的最长子字符串是 “b”,所以其长度为 1。
示例 3:
输入: s = “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。
示例 4:
输入: s = “”
输出: 0

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        unordered_map<char,int> win;//滑动窗口
        int len=0;
        int i=0;int j=0;
        for(;i<s.size();)//左指针
        {
            
            while(j<s.size()&&win[s[j]]==0)// 扩张窗口:不含有重复字符
            {
                win[s[j]]++;
                j++;
            }//循环结束后j停在第一个重复的值上
            char c=s[j];
             len=max(len,j-i);
            while(i<s.size()&&s[i]!=c)//循环结束后i停在win中和j重复的值上
            {
            win[s[i]]--;//收缩窗口
            i++;//移动指针
            }
            if(s[i]==c)//删除重复值
            {  win[s[i]]--;
                i++;
              
            }

 

            
        }
        return len;



    }
};

leetcode151反转字符串中单词

给你一个字符串 s ,逐个翻转字符串中的所有 单词 。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
请你返回一个翻转 s 中单词顺序并用单个空格相连的字符串。
说明:
输入字符串 s 可以在前面、后面或者单词间包含多余的空格。
翻转后单词间应当仅用一个空格分隔。
翻转后的字符串中不应包含额外的空格。

class Solution {
public:
void reverse(string&s,int st,int en)
{
    for(int i=st, j=en;i<j;i++,j--)
    {
        swap(s[i],s[j]);
    }
}
    string reverseWords(string s) {
        //擦除空格(字符串涉及删除的动作都要从后向前做)
        for(int i=s.size()-1;i>0;i--)
        {
            if(s[i]==s[i-1]&&s[i]==' ')
            s.erase(s.begin()+i);
            if(s.size()>0&&s[0]==' ')
            s.erase(s.begin());
            if(s.size()>0&&s[s.size()-1]==' ')
            s.erase(s.begin()+s.size()-1);
        }
        //反转整个字符串
        reverse(s,0,s.size()-1);
//反转每个单词
       for(int i=0;i<s.size();i++)//慢指针
       {
           int j=i;
           while(j<s.size()&&s[j]!=' ')//快指针
           j++;
           reverse(s,i,j-1);
           i=j;
       }
        return s;

    }
};

字符串压缩

面试题 01.06. 字符串压缩
字符串压缩。利用字符重复出现的次数,编写一种方法,实现基本的字符串压缩功能。比如,字符串aabcccccaaa会变为a2b1c5a3。若“压缩”后的字符串没有变短,则返回原先的字符串。你可以假设字符串中只包含大小写英文字母(a至z)。
示例1:
输入:“aabcccccaaa”
输出:“a2b1c5a3”
示例2:
输入:“abbccd”
输出:“abbccd”
解释:“abbccd"压缩后为"a1b2c2d1”,比原字符串长度更长。

class Solution {
public:
    string compressString(string S) {
        string s;
        int j=0;
        for(int i=0;i<S.size();)
        {
            j=i;
            while(j<S.size()&&S[j]==S[i])
            j++;
            s+=S[i]+to_string(j-i);//注意要使用+=才不会消耗过多内存
            i=j;
            
        }
        if(s.size()>=S.size())
        return S;
        else 
        return s;

    }
};

双指针

剑指offer05 替换空格

class Solution {
public:
    string replaceSpace(string s) {
        int cnt=0;
        for(int i=0;i<s.size();i++)
        {
            if(s[i]==' ')
            cnt++;
        }//计数空格
        int oldsize=s.size();
        s.resize(s.size()+cnt*2);//扩容
        int j=oldsize-1;
        for(int i=s.size()-1;j<i;i--,j--)
        {
            if(s[j]==' ')
            {
                s[i]='0';
                s[i-1]='2';
                s[i-2]='%';
                i=i-2;
            }
            else
            s[i]=s[j];
        }

return s;
    }
};

kmp

leetcode 28 实现 strStr() 函数

实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1: 输入: haystack = “hello”, needle = “ll” 输出: 2
示例 2: 输入: haystack = “aaaaa”, needle = “bba” 输出: -1
说明: 当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。 对于本题而言,当 needle 是空字符串时我们应当返回 0 。

class Solution {
public:
    int strStr(string haystack, string needle) {
        if(needle.size()==0)
        return 0;
        int next[needle.length()];
        kmp(next,needle);
        int j=0;
        for(int i=0;i<haystack.size();i++)
        {
            while(j>0&&haystack[i]!=needle[j])
            {
                j=next[j-1];
            }
            if(haystack[i]==needle[j])
            {
                j++;
            }
            if(j==needle.size())
            return i-j+1;


        }
        return -1;

    }
    void kmp(int *next,const string &s)
    {

        int j=0;//前缀长度,最长前后缀相等长度
        next[0]=0;
        for(int i=1;i<s.size();i++)
        {
            while(j>0&&s[i]!=s[j])
            {
                j=next[j-1];//跳到前缀一样的最后一个字符
            
            }
            if(s[i]==s[j])
            {
                j++;//记录重复字符长度
            }
            next[i]=j;
        }}
    };

leetcode 459. 重复的子字符串

给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。
示例 1:
输入: “abab”
输出: True
解释: 可由子字符串 “ab” 重复两次构成。
示例 2:
输入: “aba”
输出: False
示例 3:
输入: “abcabcabcabc”
输出: True
解释: 可由子字符串 “abc” 重复四次构成。 (或者子字符串 “abcabc” 重复两次构成。)

class Solution {
public:
    bool repeatedSubstringPattern(string s) {
        int j=0;
        int next[s.size()];
        int len=s.size();
        kmp(next,s);
        if(next[len-1]!=0&&len%(len-next[len-1])==0)
        return true;
        return false;




    }
    void kmp(int *next,const string&s)
    {
        int j=0;
        next[0]=0;
        for(int i=1;i<s.size();i++)
        {
            while(j>0&&s[j]!=s[i])
            {
            
            j=next[j-1];
            }

            if(s[j]==s[i])
            j++;
            next[i]=j;
        }
    }
};
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值