双指针
注意:刷题建议来自 代码随想录 公众号
快慢指针
指针移动方向相同
leetcode27 移除元素
- 移除元素
给你一个数组 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. 移动零
- 移动零
给定一个数组 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水果成篮
- 水果成篮
在一排树中,第 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;
}
}
};
868

被折叠的 条评论
为什么被折叠?



