11.6双指针
11/6
每日一题:3254.长度为k的子数组的能量值I
给你一个长度为 n 的整数数组 nums 和一个正整数 k 。
一个数组的 能量值 定义为:
- 如果 所有 元素都是依次 连续 且 上升 的,那么能量值为 最大 的元素。
- 否则为 -1 。
你需要求出 nums 中所有长度为 k 的 子数组 的能量值。
请你返回一个长度为 n - k + 1 的整数数组 results ,其中 results[i] 是子数组 nums[i..(i + k - 1)] 的能量值。
示例 1:
输入:nums = [1,2,3,4,3,2,5], k = 3
输出:[3,4,-1,-1,-1]
解释:
nums 中总共有 5 个长度为 3 的子数组:
[1, 2, 3]中最大元素为 3 。[2, 3, 4]中最大元素为 4 。[3, 4, 3]中元素 不是 连续的。[4, 3, 2]中元素 不是 上升的。[3, 2, 5]中元素 不是 连续的。
示例 2:
输入:nums = [2,2,2,2,2], k = 4
输出:[-1,-1]
示例 3:
输入:nums = [3,2,3,2,3,2], k = 2
输出:[-1,3,-1,3,-1]
提示:
1 <= n == nums.length <= 5001 <= nums[i] <= 1051 <= k <= n
思路:
用一个计数器
cnt统计连续递增元素的个数,正常i和cnt是从1开始计数。如果
nums[i] = nums[i - 1] + 1满足连续递增,则cnt++。否则置cnt = 1(不用存入ans)如果
cnt >= k,下标i - k + 1到i的子数组的能量值为最后一个数nums[i]最后存到
ans里要偏移k - 1个位置考虑边界特殊样例:
若
nums.size() = k =1,则cnt = 1 ,ans[0] = nums[0]
class Solution {
public:
vector<int> resultsArray(vector<int>& nums, int k) {
//初始化为-1
vector<int> ans(nums.size() - k + 1, -1);
int cnt = 0;
for (int i = 0; i < nums.size(); i++) {
if(i == 0 || nums[i] == nums[i - 1] + 1) cnt++;
else cnt = 1;
if (cnt >= k) {
ans[i - k + 1] = nums[i];
}
}
return ans;
}
};
27. 移除元素
思路:
NOT AC,方法忘了
请注意 ,必须在不复制数组的情况下原地对数组进行操作。这句话就是在变相地提醒用快慢指针法
双指针法:定义慢指针
slow保存最终的数组下标,快指针fast跑完整个数组,如果nums[fast] != val,则把nums[fast]的值保存到下标slow处。
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0;
for (int fast = 0 ; fast < nums.size() ; fast ++)
{
if(nums[fast] != val) nums[slow ++] = nums[fast];
}
return slow;
}
};
相关题:
思路:
快慢指针,跟官方的题解一样。
如果数组 nums 的长度为 0,则数组不包含任何元素,因此返回 0。
当数组 nums 的长度大于 0 时,数组中至少包含一个元素,在删除重复元素之后也至少剩下一个元素,因此
nums[0]保持原状即可,从下标 1 开始删除重复元素。因此初值slow = fast = 1定义两个指针 fast 和 slow 分别为快指针和慢指针,fast表示遍历数组到达的下标位置,slow表示下一个不同元素要填入的下标位置。
如果
nums[fast] !=nums[fast−1],说明 nums[fast] 和之前的元素都不同,因此将nums[fast]的值复制到nums[slow],然后将 slow 的值加 1,即指向下一个位置。
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int slow = 1;
for (int fast = 1 ; fast < nums.size() ; fast ++){
if(nums[fast] != nums[fast - 1]) nums[slow ++] = nums[fast];
}
return slow;
}
};
思路:
法一:快慢指针最后
slow为新nums的长度,从这里开始把nums后面都赋为0法二:使用双指针,左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。
右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换,同时左指针右移。
注意到以下性质:
- 左指针左边均为非零数;
- 右指针左边直到左指针处均为零。
因此每次交换,都是将左指针的零与右指针的非零数交换,且非零数的相对顺序并未改变。
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int slow = 0;
for (int fast = 0 ; fast < nums.size() ; fast ++){
if(nums[fast] != 0) nums[slow ++] = nums[fast];
}
for(int i = slow ; i < nums.size() ; i ++){
nums[i] = 0;
}
}
};
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int l = 0;
for (int r = 0; r < nums.size(); r++) {
//nums[r]非0 的话,换到 l左边去
if(nums[r]) swap(nums[l ++] , nums[r]);
}
}
};
思路:
用栈处理遍历过程,每次我们遍历到一个字符:是退格符,弹出;普通字符,压入栈中。空间复杂度略高为\(o(m+n)\)
双指针法。慢指针的左边维护最后生成的数组,快指针跑完整个字符串。最后定义
ret数组的时候可以用cpp的技巧直接截取定义:string ret(a , 0 , slow);C++string 初始化的几种方式:
- 方式一 :直接赋值
string str1 = "test01" ;
方式2 :以length为长度的ch的拷贝(即length个ch)
string( size_type length, char ch );string str2( 5, 'c' ); // str2 'ccccc'方式3:
string( string &str, size_type index, size_type length );以
index为索引开始的子串,长度为length, 或者 以从start到end的元素为初值.string str4( str3, 0, 4 ); //将str3 的从第0个位置元素起复制4个长度元素到str4本题用到方式三,不用for循环。
//用栈模拟
class Solution {
public:
bool backspaceCompare(string s, string t) {
return tuige(s) == tuige(t);
}
string tuige(string a){
string ret;
for(char ch : a){
if(ch != '#') ret.push_back(ch);
else if(!ret.empty()) ret.pop_back();
}
return ret;
}
};
class Solution {
public:
bool backspaceCompare(string s, string t) {
return tuige(s) == tuige(t);
}
string tuige(string a){
int slow = 0;//slow 的左边是新的最后的数组
for (int fast = 0 ; fast < a.size() ; fast ++){
if(a[fast] != '#') a[slow ++] = a[fast];
else if(slow > 0) slow --;
}
string ret(a , 0 , slow);
return ret;
}
};
NOT AC
思路:
暴力,时间复杂度主要是
遍历数组,所有元素平方 O(n)+排序O(logn)双指针法。
数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
此时可以考虑双指针法了,l指向起始位置,r指向终止位置。
定义一个与原数组等长的数组
res,因为从大到小,所以指针p从后往前遍历。比较
nums[l] * nums[l]与nums[r] * nums[r]大小,大的存入res。这里注意是res[p] = xxx而不是res.push_back(xxx)
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int n = nums.size();
vector<int> res(n);
for(int l = 0 , r = n - 1 ,p = n - 1; l <= r ; p --){
if(nums[l] * nums[l] <= nums[r] * nums[r]){
res[p] = nums[r] * nums[r];
r --;
}
else
{
res[p] = nums[l] * nums[l];
l ++;
}
}
return res;
}
};


浙公网安备 33010602011771号