双指针比较灵活,可以大大降低时间复杂度,可用在数组,单链表等数据结构中。
在对数组使用双指针法时,通常使用数组下标充当指针。
题一. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
像这样进行数组划分,数组分块的题目可以用双指针法解决。
两个指针的作用:
- right:从左到右扫描遍历数组。
- left:已处理的区间中,非零元素的最后一个位置。
处理的方法:
right在向后遍历的过程中:
- 遇到0元素,right++;
- 遇到非0元素:left++ , 交换数组 left 与 right 这两个下标处的数据 , right++;
数组被分为三个区间
非0区 : [0,left] , 0区 : [left+ 1 , right - 1] , 未处理区 : [right , n - 1]
代码具体实现:
class Solution1 {
public:
void moveZeroes1(vector<int>& nums) {//暴力直接交换
int i = 0;
for (int num = 0; num < nums.size(); num++) {
if (i > 0 && nums[i - 1] == 0)
i--;
if (nums[i] == 0) {
for (int j = i; j < nums.size() - 1; j++) {
swap(nums[j], nums[j + 1]);
}
}
i++;
}
}
void moveZeroes2(vector<int>& nums) {//双指针法
int left = -1,right = 0;
while(right<nums.size())
{
//if (nums[right] == 0) {
// right++;
//}
//else
//{
// left++;
// swap(nums[right], nums[left]);
// right++;
//}
if (nums[right] != 0) {
left++;
swap(nums[right], nums[left]);
}
right++;
}
}
};
void Test01() {
Solution1 s1;
vector<int> v1{ 1,0,2,2,3,0,4,6,7 };
s1.moveZeroes2(v1);
for (auto e : v1) {
cout << e << " ";
}
cout << endl;
}
题二. 盛最多水的容器
给定一个长度为n的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
首先我们可以想到用两个循环,遍历求出每种情况下的的装水量,再取最大值。
但是这种方法时间复杂度高,所以我们可以用双指针法。
再解决这个题目前,我们需要了解:
假设这样一个容器(6 4 3 7 2),取最左边与最右边计算装水量,那么再次以较小一边固定,遍历其他的边,计算出的数据都会更小。
因为就算遍历到的这个数比原本左边与右边中较大的数更大,因为装水量取决于短板,并且宽度下降,总体装水量会更少。
遍历到的数更小,装水量当然会更少。
所以,我们在计算最大的装水量时,只需先取两边的下标 left 与 right ,计算这种情况下的装水量,再比较数组下标 left , right 的数的大小,在较小的那一端指针向中移。
class Solution {
public:
int maxArea(vector<int>& height) {
vector<int> nums;
int left = 0, right = height.size() - 1;
//6 4 3 7 2
//假设这样一个容器,取最左边与最右边计算装水量,那么再次以较小一边固定,遍历其他的边,计算出的数据都会更小
//因为就算遍历到的这个数比原本左边与右边中较大的数更大,因为装水量取决于短板,并且宽度下降,总体装水量会更少
//遍历到的数更小,装水量当然会更少
while (left < right) {
if (height[left] < height[right]) {
nums.push_back((right - left) * height[left]);
left++;
}
else
{
nums.push_back((right - left) * height[right]);
right--;
}
}
int max = nums[0];
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > max)
max = nums[i];
}
return max;
}
};
void Test_04() {
Solution s1;
vector<int> v1{6,4,3,7,2 };
cout << s1.maxArea(v1) << endl;
}
(如有问题,烦请指出)