【刷题】双指针入门

在这里插入图片描述

双指针

双指针是非常经典的算法,包括但不限于前后双指针,快慢双指针,特殊双指针
尤其需要注意的是双指针并不能只局限于指针,数组下标,过程数据都可以成为“指针”。重要的是能够灵活使用双指针的思想,把解题思路捋顺
下面,我们来会会几道双指针的题目:

283.移动零

家人们 !!! 上连接:283.移动零

在这里插入图片描述
通过题目,发现这并不是一到很复杂的题。主要难点在于不改变数组的相对顺序。
这里我们使用前后双指针,逐渐遍历完成操作:

  1. 首先定义两个数组下标 i j
  2. 我们赋予他们不同含义:
    [ 0 ,i)是已经处理过,已经没有零的部分 并按相对顺序排好
    [i , j] 是零的部分
    (j , n) 待处理的部分
  3. 我们控制 j 来进行整个数组的遍历,0 到 i是非零数据。
  4. 遇到 0 ,i j 位置互换即可
    在这里插入图片描述
    来看代码:(类似冒泡排序的过程,把零向后挪动)
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        for(int i = 0,j = 0;j<nums.size();j++)
            if(nums[j] != 0) swap(nums[j],nums[i++]);
    }
};

非常简洁的代码。就可以完成我们的操作。来看效果:
在这里插入图片描述
很好!过啦!!!!

1089. 复写零

家人们!!!跟上节奏:1089. 复写零
在这里插入图片描述
这道题与前面的移动零很像,但使用的算法细节不同。
这里需要的也是双指针 i j:

  1. 首先定义两个数组下标 i j
  2. 赋予他们不同含义:
    0 到 i 是处理完的部分
    i 到 j 是 未处理部分
  3. 首先使用 i 遍历整个数组,j 负责调换未处理的数据(将数据后移,空出新的零的位置)
    在这里插入图片描述
    来看代码:
class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        for(int i = 0;i<arr.size();i++){
            if(arr[i] == 0){
                for(int j = arr.size() - 1 ; j > i ; j--){
                    arr[j] = arr[j - 1];
                }
                ++i;
            }
        }

    }
};

运行效果:
在这里插入图片描述

202. 快乐数

家人们!!! 继续干:202. 快乐数

在这里插入图片描述
这道题是比较特殊的一道题,我们来看奥:
首先看测试用例的 1 9 和 2 ;
在这里插入图片描述
可以发现最后都会处于循环:这里可以证明一下为什么都会处于循环:
假设我们最大数为 99999 99999 那对应的数为 810 ,相当于 0 到 9999999999 只有 810 个数与之对应,所以必然会出现循环。
到这里,大家应该也看出这和判断链表是否有环很像,使用快慢指针,慢指针依次进行一步操作,快指针一次两步操作。这里“指针”代指数字。


class Solution {
public:
	//操作函数
    int getsum(int n ){
        int sum = 0;
        while(n){
            int i = n % 10;
            sum += i*i;
            n /= 10;
        }
         return sum;
        }

    bool isHappy(int n) {
		//初始化
        int slow = n;
        int fast = getsum(n);
		//进行循环 直到相遇
        while(slow != fast){
            slow = getsum(slow);
            fast = getsum(getsum(fast));
           
        }
        //判断一下即可
        if(slow == 1) return true;
        return false;

    }
};

来看效果:
在这里插入图片描述
很好! 过啦!!!!

11. 盛最多水的容器

家人们,终于到了最后一题: 11. 盛最多水的容器
这道题可谓十分抽象:
在这里插入图片描述
这里使用前后双指针,代我细细到来为什么:
首先我们选取前后这一片段,然后得到一个体积值。
这时我们可以进行一下分析:

  1. 如果移动较大这边的指针,那长必然减小 , 高一定不会增加所以不需移动较高这边
  2. 再来看较小这边,移动后不能确定到底是增加还是减少,所以需要移动进行遍历

根据这两条规矩我们就可以完成操作:来看图解(来自 力扣官方题解)
在这里插入图片描述
这样必然可以得到答案。

class Solution {
public:

    int maxArea(vector<int>& height) {
        int i = 0;
        int j = height.size() - 1;
		// 记录答案值
        int ans = 0;
        while(i != j){
        	//求得新的体积
            int v = min(height[i],height[j]) * (j - i);
            //取最大值
            ans = max(ans,v);
            // 移动较小的指针
            if(height[i] < height[j])
                i++;
            else
                j--;

        }
        return ans;
    }
};

来看效果:
在这里插入图片描述
过啦!!!(还存在改进空间)

经过这四道题目的洗礼,我大概对双指针有了初步印象,接下来我会继续努力!!!

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!

评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叫我龙翔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值