【C++算法】双指针

简介: 【C++算法】双指针

移动零

  • 算法原理

这类题是属于数组划分、数组分开题型

  • 代码步骤:
  1. 使用cur遍历数组
  2. 当cur所指的元素等于0时,cur向后面移动
  3. 当cur所指的元素不等于0时,dest向后面移动,cur所指元素与dest移动后所指的元素交换
  4. 当cur指向最后一个元素的下一个时,结束。
  • 代码展示
class Solution {
public:
    void moveZeroes(vector<int>& nums) 
    {
        int dest = -1;
        for(int cur = 0; cur < nums.size(); ++cur)
        {
            //如果cur所指的元素非0,交换
            if(nums[cur] != 0)
            {
                swap(nums[++dest], nums[cur]);
            }
        }
    }
};

复写零

题目链接:

  • 算法原理

  • 代码步骤:

  • 代码展示
class Solution {
public:
    void duplicateZeros(vector<int>& arr) 
    {
        //寻找复写的最后一个元素
        int cur = 0;
        int dest = -1;
        int n = arr.size();
        //注意arr.sizr()是size_t无符号类型
        //int(-1)比size_t整数大
        while(cur < n)
        {
            if(arr[cur])
            {
                ++dest;
            }
            else
            {
                dest += 2;
            }
            //注意这个判断条件需要在里面实现
            //如果在整个循环结束判断,cur的值无法保证
            if(dest >= n-1) break;
            cur++;
        }
        //特殊情况处理
        if(dest == n)
        {
            arr[n - 1] = 0;
            --cur;
            dest -= 2;
        }
        //进行从右向左的复写操作
        for(; cur >= 0; --cur)
        {
            if(arr[cur])
            {
                arr[dest--] = arr[cur];
            }
            else
            {
                arr[dest--] = 0;
                arr[dest--] = 0;
            }
        }  
    }
};

快乐数

题目链接:

  • 算法原理

  • 代码步骤:

采用快慢双指针的思想:

  1. 定义快慢双指针
  2. 设置一个每个位置平方和的函数
  3. 慢指针每次向后移动一步
  4. 快指针每次向后移动俩步
  5. 判断快慢指针相遇的时候的值是否为1即可
  • 代码展示
class Solution {
public:
    //计算数每个位置上数字的平方和
    int SquareSum(int n)
    {
        int sum =0;
        while(n > 0)
        {
            int num = n % 10;
            sum += num * num;
            n /= 10;
        }
        return sum;
    }
    bool isHappy(int n) 
    {
        int slow = n;
        int fast = SquareSum(n);
        while(slow != fast)
        {
            fast = SquareSum(SquareSum(fast));
            slow = SquareSum(slow);
        }
        if(slow == 1)
        {
            return true;
        }
        else 
        {
            return false;
        }
    }
};

盛最多水的容器

题目链接:

  • 算法原理

  • 代码步骤:
  1. 记录初始w最大时的初始容积
  2. left与right二者中较小者向里面移动,寻找比自己大的值
  3. 找到比自己大的值,记录面积,并与之前的面积比较大小
  4. 当left与right相遇的时候,结束
  • 代码展示
class Solution 
{
public:
    int maxArea(vector<int>& height) 
    {
        int left = 0;
        int right = height.size() - 1;
        //寻找边界的最小值
        int min = (height[left] < height[right]) 
        ? height[left] 
        : height[right];
        //起始容积
        int vmax = min * (right - left);
        while(left < right)
        {
            if(height[left] < height[right])
            {
                //记录此时的left
                int num = left;
                while(left < right)
                {
                    //比较看是否有比height[left]大的值
                    ++left;
                    if(height[num] < height[left])
                    {
                        break;
                    }
                }
            }
            else
            {
                //记录此时的left
                int num = right;
                while(left < right)
                {
                    //比较看是否有比height[left]大的值
                    --right;
                    if(height[num] < height[right])
                    {
                        break;
                    }
                }
            }
            min = (height[left] < height[right]) 
            ? height[left] 
            : height[right];
            int v = min * (right - left);
            vmax = (v > vmax) ? v : vmax; 
        }
        return vmax;
    }
};
class Solution {
public:
    int maxArea(vector<int>& height) 
    {
        int left = 0, right = height.size() - 1, vmax = 0;
        while(left < right)
        {
            int v = min(height[left], height[right]) * (right - left);
            vmax = max(vmax, v);
            if(height[left] < height[right]) ++left;
            else --right;
        }
        return vmax;
    }
};

有效三角形个数

题目链接:

  • 算法原理

  • 代码步骤:
  1. 对数组进行排序
  2. 设置三个指针,一个指向最大值,另外俩个形成单调双指针
  3. 当left + right < max时,个数为right-left,right--
  4. 当left + right >= max时,个数为0,left++
  • 代码展示
class Solution {
public:
    int triangleNumber(vector<int>& nums) 
    {
        int n = nums.size();
        //排序升序
        sort(nums.begin(), nums.end());
        int sum = 0;
        //最大值向前移动
        while(n >= 2)//确保right不越界
        {
            int max = nums[n - 1];
            int left = 0, right = n - 2;
            //利用单调性使用双指针
            while(left < right)
            {
                if(nums[left] + nums[right] > max)
                {
                    sum += (right - left);
                    right--;
                }
                else
                {
                    left++;
                }
            }
            --n;
        }
        return sum;
    }
};

三数之和

题目链接:

  • 算法原理

  • 代码步骤:
  1. 排序
  2. 固定一个数min(注意当min > 0的时候,也是可以直接结束的)
  3. 在该数的后面的区间之内,利用单调性使用双指针,快速找到俩个和等于-min的值
  4. 细节1:不漏数据
  5. 细节2:去重操作
  • 代码展示
class Solution 
{
public:
    vector<vector<int>> threeSum(vector<int>& nums) 
    {
        vector<vector<int>> vv;
        //排序
        sort(nums.begin(), nums.end());
        int n = nums.size();
        //固定一个数
        int min = 0;
        for(int min = 0; min < n - 2; ++min)
        {
            //优化
            if(nums[min] > 0) break;
            int left = min + 1, right = n - 1;
            while(left < right)
            {
                if(nums[left] + nums[right] < -nums[min])
                {
                    left++;
                }
                else if(nums[left] + nums[right] > -nums[min])
                {
                    right--;
                }
                else
                {
                    //添加数据
                    vv.push_back({nums[min], nums[left], nums[right]});
                    while(left < right && nums[left] == nums[left + 1])
                    {
                        left++;
                    }
                    while(left < right && nums[right] == nums[right - 1])
                    {
                        right--;
                    }
                    if(left < right)
                    {
                        left++;
                        right--;
                    }
                }
            }
            while(min < n - 2 && nums[min] == nums[min + 1])
            {
                min++;
            }
        }
        return vv;
    }
};

四数之和

题目链接:

  • 算法原理

  • 代码步骤:

  • 代码展示
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) 
    {
        vector<vector<int>> ret;
        //排序
        sort(nums.begin(), nums.end());
        int n = nums.size();
        //四数之和
        for(int minA = 0; minA < n;)
        {
            long targetA = target - nums[minA];
            //三数之和
            for(int minB = minA + 1; minB < n;)
            {
                long targetB = targetA - nums[minB];
                int left = minB + 1, right = n - 1;
                while(left < right)
                {
                    //利用单调性使用双指针
                    if(nums[left] + nums[right] < targetB)
                    {
                        left++;
                    }
                    else if(nums[left] + nums[right] > targetB)
                    {
                        right--;
                    }
                    else
                    {
                        ret.push_back({nums[minA], nums[minB], nums[left], nums[right]});
                        //left不重
                        while(left + 1 < right && nums[left] == nums[left + 1])
                        {
                            left++;
                        }
                        //right不重
                        while(left < right - 1 && nums[right] == nums[right - 1])
                        {
                            right--;
                        }
                        //不漏
                        if(left < right)
                        {
                            left++;
                            right--;
                        }
                    }
                }
                //minB不重
                while(minB + 1 < n && nums[minB] == nums[minB + 1])
                {
                    minB++;
                }
                ++minB;
            }
            //minA不重
            while(minA + 1 < n && nums[minA] == nums[minA + 1])
            {
                minA++;
            }
            ++minA;
        }
            return ret;
    }
};  


相关文章
|
2月前
|
算法 测试技术 C++
【动态规划算法】蓝桥杯填充问题(C/C++)
【动态规划算法】蓝桥杯填充问题(C/C++)
|
5天前
|
存储 程序员 C++
深入解析C++中的函数指针与`typedef`的妙用
本文深入解析了C++中的函数指针及其与`typedef`的结合使用。通过图示和代码示例,详细介绍了函数指针的基本概念、声明和使用方法,并展示了如何利用`typedef`简化复杂的函数指针声明,提升代码的可读性和可维护性。
22 0
|
1月前
|
存储 编译器 Linux
【c++】类和对象(上)(类的定义格式、访问限定符、类域、类的实例化、对象的内存大小、this指针)
本文介绍了C++中的类和对象,包括类的概念、定义格式、访问限定符、类域、对象的创建及内存大小、以及this指针。通过示例代码详细解释了类的定义、成员函数和成员变量的作用,以及如何使用访问限定符控制成员的访问权限。此外,还讨论了对象的内存分配规则和this指针的使用场景,帮助读者深入理解面向对象编程的核心概念。
87 4
|
2月前
|
存储 安全 编译器
在 C++中,引用和指针的区别
在C++中,引用和指针都是用于间接访问对象的工具,但它们有显著区别。引用是对象的别名,必须在定义时初始化且不可重新绑定;指针是一个变量,可以指向不同对象,也可为空。引用更安全,指针更灵活。
|
2月前
|
存储 算法 C++
高精度算法(加、减、乘、除,使用c++实现)
高精度算法(加、减、乘、除,使用c++实现)
666 0
高精度算法(加、减、乘、除,使用c++实现)
|
2月前
|
存储 C++
c++的指针完整教程
本文提供了一个全面的C++指针教程,包括指针的声明与初始化、访问指针指向的值、指针运算、指针与函数的关系、动态内存分配,以及不同类型指针(如一级指针、二级指针、整型指针、字符指针、数组指针、函数指针、成员指针、void指针)的介绍,还提到了不同位数机器上指针大小的差异。
61 1
|
2月前
|
存储 编译器 C语言
C++入门2——类与对象1(类的定义和this指针)
C++入门2——类与对象1(类的定义和this指针)
43 2
|
2月前
|
算法 数据处理 C++
c++ STL划分算法;partition()、partition_copy()、stable_partition()、partition_point()详解
这些算法是C++ STL中处理和组织数据的强大工具,能够高效地实现复杂的数据处理逻辑。理解它们的差异和应用场景,将有助于编写更加高效和清晰的C++代码。
43 0
|
2月前
|
存储 算法 决策智能
【算法】博弈论(C/C++)
【算法】博弈论(C/C++)
|
2月前
|
存储 算法 C++
【算法】哈希映射(C/C++)
【算法】哈希映射(C/C++)
下一篇
DataWorks