双指针法(双循环变量法)
一、快慢指针(同向指针)
例1:27. 移除元素
链接:https://leetcode-cn.com/problems/remove-element
给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
总结:所有“原地”操作的空间复杂度均为 O(1),这一类算法就是使用快慢指针,建立基于慢指针索引的数组覆盖掉原数组,不必开辟额外空间。**
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int j = 0;
for(int i = 0; i < nums.size(); i++)
{
if(nums[i] != val)
{
nums[j]=nums[i];
j++;
}
}
return j;
}
};
思考1:如果返回值写为 “return nums.size();” 是否正确?
错误,因为vector< int >初始化的是一个固定长度的数组,在函数执行的过程中只是修改了数组的元素,并没有修改固定数组的长度。如果想要返回移除后的数组,应使用可变长度的动态数组实现,或者使用vector中的resize(j)方法。
思考2:若数组是无序的,如何设计算法?
例2:26. 删除有序数组中的重复项
链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array
给你一个有序数组 nums ,请你原地删除重复出现的元素,使每个元素只出现一次,返回删除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if(nums.size()==0)
return 0;
int j = 0;
for(int i = 0; i < nums.size(); i++)
{
if(nums[i] != nums[j])
{
j++;
nums[j] = nums[i];
}
}
return j+1;
}
};
思考:下列算法是否正确?
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if(nums.size()==0)
return 0;
int j = 0;
for(int i = 0; i < nums.size(); i++)
{
if(nums[i+1] != nums[i])
{
nums[j] = nums[i];
j++;
}
}
return j;
}
};
例3:283. 移动零
链接:https://leetcode-cn.com/problems/move-zeroes
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
思考:下列算法的时间复杂度为多少?能否提高该算法的效率?
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int j = 0;
for(int i = 0; i < nums.size(); i++)
{
if(nums[i] != 0)
{
nums[j] = nums[i];
j++;
}
}
for(; j < nums.size(); j++)
nums[j] = 0;
}
};
例4:844. 比较含退格的字符串
链接:https://leetcode-cn.com/problems/backspace-string-compare
给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,请你判断二者是否相等。# 代表退格字符。如果相等,返回 true;否则,返回 false 。注意:如果对空文本输入退格字符,文本继续为空。
方法一:同向指针法
从前面开始比较,如果不是退格,就放进Buffer中,如果出现了退格,就在Buffer中删除一个元素,原地删除数据就是将数组的第二下标往首地址移动(从前往后存数据,从后往前删数据)。
class Solution {
public:
bool backspaceCompare(string s, string t) {
backspaceString(s);
backspaceString(t);
return s==t;
}
void backspaceString(string &s)
{
int j = 0;
for(int i = 0; i < s.length(); i++)
{
if(s[i] != '#') //注意使用if-else if-else非此即彼的性质
{
s[j] = s[i];
j++;
}
else if(j != 0) //隐含了对backspace的判断
j--;
}
s.resize(j);
}
};
方法二:利用栈来实现
这里是引用
二、对立指针
例5:344. 反转字符串
链接:https://leetcode-cn.com/problems/reverse-string
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组,使用 O(1) 的额外空间解决这一问题。
class Solution {
public:
void reverseString(vector<char>& s) {
int i, j;
i = 0;
j = s.size()-1;
while(i < j)
{
char temp = s[i];
s[i] = s[j];
s[j] = temp;
i++;
j--;
}
}
};
例6:977. 有序数组的平方
链接:https://leetcode-cn.com/problems/squares-of-a-sorted-array
给你一个按非递减顺序排序的整数数组 nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int a, b, k;
a = 0;
b = nums.size()-1;
k = nums.size()-1;
vector<int> result(nums.size());
while(a <= b)
{
if(nums[a]*nums[a] > nums[b]*nums[b])
{
result[k] = nums[a]*nums[a];
a++;
}
else
{
result[k] = nums[b]*nums[b];
b--;
}
k--;
}
return result;
}
};
思考:下列算法有哪些问题?
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int a, b, k;
a = 0;
b = nums.size()-1;
k = nums.size()-1;
vector<int> result;
while(a < b)
{
int A = nums[a]*nums[a];
int B = nums[b]*nums[b];
if(A > B)
{
result[k] = A;
a++;
k--;
}
else
{
result[k] = B;
b--;
k--;
}
}
return result;
}
};