C++算法之双指针算法

1089.复写0

算法原理

解法双指针算法:

1.先找到最后一个复写的数;

这里同样也可以使用双指针算法

初始化

根据cur遇到的值来选择dest的移动步数,当dest到数组末尾时,cur所在位置就是最后一个复写的数

注意一下可能出现的越界情况

2.之后从后向前完成复写操作;

遇到非零数就正常拷贝复写,遇到零就复写拷贝两次

cpp 复制代码
1class Solution
2 {
3public:
4    void duplicateZeros(vector<int>& arr) 
5    {
6        //先找到最后一个复写数
7        int cur = 0,dest = -1,n = arr.size();
8        while(cur < n )
9        {
10            if(arr[cur])
11            {
12                dest++;
13            }
14            else
15            {
16                dest += 2;
17            }
18            if(dest >= n-1)
19            {
20                break;
21            }
22            cur++;
23        }
24      //处理边界情况
25      if(dest == n)
26      {
27        arr[n-1] = 0;
28        cur--;dest -=2;
29      }
30      //从后向前完成复写操作
31      while(cur >= 0)
32      {
33        if(arr[cur])
34        {
35            arr[dest] = arr[cur];
36            dest--;
37            cur--;
38        }
39        else
40        {
41          arr[dest--] = 0;
42          arr[dest--] = 0;
43          cur--;
44        }
45      }
46    }
47};

202.快乐数

算法原理:

这个类似约瑟夫环,由题目可知这个会是一个循环,就代表一个数无论从哪里开始,走多少步,最后一定会进入一个循环,这个时候就可以使用快慢指针,一个数在前一个数在后,一个一次走一步另一个一次走两步,这两个数一定会相遇,相遇时有两种情况,情况一:快指针在1处循环,慢指针追上,也在1处循环,情况二:快指针走过一遍循环,追上慢指针,那我们就可以在相遇处判断是否为1来输出结果

cpp 复制代码
class Solution 
{
public:
    int nsum(int n)
    {
        int sum =0;
        int ret = 0;
        while(n)
        {
          ret = n%10;
          sum += ret*ret;
          n = n/10;
        }
        return sum;
    } 
    bool isHappy(int n) 
    {
        int slow = n, fast = nsum(n);
        while(slow != fast)
        {
            slow = nsum(slow);
            fast = nsum(nsum(fast));
        }
        return slow == 1;
    }
};

15,三数之和

算法原理:

解法一:排序+暴力+set去重

就是先排序,然后进行三次遍历,然后使用set容器去重

解法二:排序+双指针

首先先进行排序,然后从左到0依次固定数,然后再右边区间内进行双指针算法找到固定数的相反数

1.去重:当找到一种结果后两个指针都要跳过重复元素,使用完一次双指针后,固定的数也要去重

注意指针越界问题

2.不漏:找到一种结果后,不要停,缩小区间,继续寻找

cpp 复制代码
1class Solution {
2public:
3    vector<vector<int>> threeSum(vector<int>& nums) {
4        vector<vector<int>> ret;
5        sort(nums.begin(),nums.end());
6        int n = nums.size();
7        for(int i = 0; i < n;)
8        {
9            if(nums[i] > 0)
10            {
11                break;
12            }
13            int left = i+1, right = n-1;
14            while(left < right)
15            {
16                if(left < right && nums[left] + nums[right] > -nums[i])
17                right--;
18                else if( left < right && nums[left] + nums[right] < -nums[i])
19                left++;
20                else{
21                    ret.push_back({nums[i],nums[left],nums[right]});
22                    right--;
23                    left++;
24                    while(left<right && nums[right] == nums[right+1])
25                    {
26                        right--;
27                    }
28                    while(left < right && nums[left] == nums[left-1])
29                    {
30                        left++;
31                    }
32                }
33            }
34            while(i+1 < n && nums[i] == nums[i+1])
35            {
36                i++;
37            }
38            i++;
39        }
40        return ret;
41    }
42};

18.四数之和

算法原理:

解法一:排序+暴力枚举+set去重

解法二:排序+双指针

1.依次固定一个数a;

2.在a后面的区间内,利用"三数之和"找到三个数,使这三个数的和等于target - a即可

{

1.在前面的基础上,依次固定一个数b;

2.在b后面区间内,利用"双指针"找到两个数,使这两个数的和等于target-a-b

}(嵌套解法)

cpp 复制代码
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>> ret;
        //1.排序
     sort(nums.begin(),nums.end());
      //2.利用双指针解决问题
      int n = nums.size();
      for(int i =0; i <n;)//固定数a
      {
        //利用三数之和解决问题
        for(int j = i+1; j <n;)//固定数b
        {
            //双指针解法
            int left = j+1,right = n-1;
            long long aim = (long long)target -nums[i] - nums[j];
            while(left < right)
            {
                int sum = nums[left] + nums[right];
                if(sum< aim)left++;
                else if( sum > aim)right--;
                else
                {
                   ret.push_back({nums[i],nums[j],nums[left],nums[right]});
                      left++;                     
                      right--;
                   //去重一
                   while(left < right && nums[left] == nums[left-1])
                   left++;
                   while(left < right&& nums[right] == nums[right+1])
                   right--;
                }
            }
            //去重二
            j++;
            while(j < n && nums[j] == nums[j-1])
            j++;
        }
        //去重三
        i++;
        while(i < n&& nums[i] == nums[i-1])
        i++;
      }
      return ret;
    }
};
相关推荐
不知名的老吴1 小时前
一文读懂:单例模式的经典案例分析
java·开发语言·单例模式
承渊政道1 小时前
【递归、搜索与回溯算法】(掌握记忆化搜索的核心套路)
数据结构·c++·算法·leetcode·macos·动态规划·宽度优先
REDcker1 小时前
跨平台编译详解 工具链配置与工程化实践
linux·c++·windows·macos·c·跨平台·编译
天天进步20151 小时前
Python全栈项目实战:自建高效多媒体处理工具
开发语言·python
闻缺陷则喜何志丹1 小时前
【 线性筛 调和级数】P7281 [COCI 2020/2021 #4] Vepar|普及+
c++·算法·洛谷·线性筛·调和级数
zzzsde1 小时前
【Linux】线程概念与控制(1)线程基础与分页式存储管理
linux·运维·服务器·开发语言·算法
waterHBO1 小时前
python + fast-wahisper 读取麦克风,实现语音转录,而且是实时转录。
开发语言·python
凤山老林2 小时前
27-Java final 关键字
java·开发语言
叶子野格2 小时前
《C语言学习:数组》11
c语言·开发语言·c++·学习·visual studio