双指针法(快慢指针)
一、题源:
27. 移除元素
问题描述
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O ( 1 ) O(1) O(1) 额外空间并原地修改输入数组。
二、 思路:
1、暴力解法
最简单的写法就是直接标记所有等于val的数组元素,然后将后面的元素前移。
时间复杂度:
O
(
n
)
O(n)
O(n)
空间复杂度:
O
(
1
)
O(1)
O(1)
注:暴力法虽然思路简单,容易想到,且宏观上看时间复杂都和快慢指针法在同一量级,但仔细考虑就能知道实际运行时间高于快慢指针法,且标记需要删除的元素受到具体条件的制约,有可能需要引入额外的数组。
2、双指针法
有两个指针从头开始,一个是fastIndex,用来遍历数组,一个是slowIndex, 用来标记下一个将要替换的元素下标
参考代码如下
int removeElement(int* nums, int numsSize, int val){
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < numsSize; fastIndex++) {
if (val != nums[fastIndex]) {
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
三、相关题目及实现
26. 删除排序数组中的重复项
问题描述:
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
实现:
int removeDuplicates(int* nums, int numsSize){
if(numsSize == 0) return 0;
int slowIndex = 0;
for(int fastIndex = 1; fastIndex < numsSize; fastIndex++) {
if(nums[slowIndex] != nums[fastIndex]){
nums[++slowIndex] = nums[fastIndex];
}
}
return slowIndex+1;
}
283. 移动零
问题描述:
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
实现
void moveZeroes(int* nums, int numsSize){
int slowIndex = 0;
for(int fastIndex = 0; fastIndex < numsSize; fastIndex++) {
if(nums[fastIndex] != 0) {
nums[slowIndex++] = nums[fastIndex];
}
}
while(slowIndex < numsSize) nums[slowIndex++] = 0;
}
977. 有序数组的平方
问题描述:
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
实现:
int* sortedSquares(int* nums, int numsSize, int* returnSize){
int headIndex = 0, endIndex = numsSize-1, resultIndex = numsSize-1;
int* squares = (int*)malloc(sizeof(int)*numsSize);
int* result = (int*)malloc(sizeof(int)*numsSize);
for(; headIndex < numsSize; headIndex++) {
squares[headIndex] = nums[headIndex]*nums[headIndex];
}
headIndex = 0;
while(resultIndex >= 0) {
if(squares[headIndex] > squares[endIndex]) result[resultIndex--] = squares[headIndex++];
else result[resultIndex--] = squares[endIndex--];
}
free(squares);
*returnSize = numsSize;
return result;
}
15. 三数之和
问题描述:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
实现:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for(auto it1 = nums.begin(); it1 != nums.end(); ++it1)
{
if (*it1 > 0) break;
auto left = it1 +1,right = nums.end() - 1;
while(left < right)
{
if(!(*left + *right + *it1))
{
result.push_back({*it1, *left, *right});
++left;
while(left != nums.end() && *(left - 1) == *left) ++left;
--right;
while(right!= it1 && *(right + 1) == *right) --right;
}
else if(*left + *right + *it1 > 0)
{
--right;
while(right!= it1 && *(right + 1) == *right) --right;
}
else
{
++left;
while(left != nums.end() && *(left - 1) == *left) ++left;
}
}
while(it1 + 1 != nums.end() && *it1 == *(it1 + 1)) ++it1;
}
return result;
}
};
实际上这道题很像两数之和 ,所以实际上也可以用哈希表,但是如果用哈希表的话,对于一些特殊情况处理比较麻烦,所以下面的实现仅供参考
class Solution{
public:
vector<vector<int>> threeSum(vector<int>& nums) {
unordered_set<int> set;
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for(auto it1 = nums.begin(); it1 != nums.end(); ++it1)
{
if(it1 + 1 != nums.end() && *(it1 + 1) == *it1)
{
if(*it1 <= 0)
{
set.insert(*it1);
++it1;
}
}
for(auto it2 = it1 + 1; it2 != nums.end(); it2++)
{
if(set.find( - *it1 - *it2) != set.end())result.push_back({ - *it1 - *it2, *it1, *it2});
while(it2 + 1 != nums.end() && *it2 == *(it2 + 1)) ++it2;
}
set.insert(*it1);
while(it1 + 1 != nums.end() && *it1 == *(it1 + 1)) ++it1;
}
return result;
}
};
18. 四数之和
问题描述:
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
- 0 <= a, b, c, d < n
- a、b、c 和 d 互不相同
- nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。
实现:
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for(auto it1 = nums.begin(); it1 != nums.end(); ++it1)
{
for(auto it2 = it1 + 1; it2 != nums.end(); ++it2)
{
auto left = it2 +1,right = nums.end() - 1;
while(left < right)
{
if(*left + *right == target - (*it1 + *it2))
{
result.push_back({*it1, *it2, *left, *right});
++left;
while(left != nums.end() && *(left - 1) == *left) ++left;
--right;
while(right!= it2 && *(right + 1) == *right) --right;
}
else if(*left + *right > target - (*it1 + *it2))
{
--right;
while(right!= it2 && *(right + 1) == *right) --right;
}
else
{
++left;
while(left != nums.end() && *(left - 1) == *left) ++left;
}
}
while(it2 + 1 != nums.end() && *it2 == *(it2 + 1)) ++it2;
}
while(it1 + 1 != nums.end() && *it1 == *(it1 + 1)) ++it1;
}
return result;
}
};