• 算法专题:双指针


    目录

    题目1:移动零

    题目2:复写零

    题目3:快乐数

    题目4:最多水的容器

    题目5:有效三角形的个数

    题目6:两数之和为s


    题目1:移动零


    给定一个数组nums,编写一个函数将所有的0移动到数组的末尾同时保持非0元素的相对顺序。(就地实现)
    示例 
    散乱数组:nums{0,1,0,3,12 }==》nums{1,3,12,0,0}

    算法原理:利用双指针(数组下标充当指钱)来实现数组划分

    如果cur处为非0,交换dest+1和cur处的值同时两个下标向右走,开始处理dest=-1;cur=0;

    实现代码:

    1. void moveZeroes(vector<int>& nums)
    2. {
    3. for (int cur = 0, dest = -1; cur < nums.size(); cur++)
    4. {
    5. if (nums[cur])
    6. {
    7. swap(nums[++dest], nums[cur]);
    8. }
    9. }
    10. }


    题目2:复写零


    给定一个长度固定的整数数组arr,将该数组中出现的每个0都复写一遍,将其余元素向右平移,不开辟新空间,就地复写
    示例:
    {1,0,2,3,0,4,5,0}==》{1,0,0,2,3,0,0,4}

    算法原理:
    1.先找到最后一个复写的数
    从左往右遍历cur指向第0个元素.
    dest指向一1,若arr[cur]不为0,dest和cur都向后走一步若:arr[cur]为0,则dest何右走两走两步,cur向右走一步。


    2.调整边界
    3.从右往左完成复写

    实现代码:

    1. void doubleZeroes(vector<int>& arr)
    2. {
    3. //1.先找到最后一个复写的数
    4. int cur = 0, dest = -1, n = arr.size();
    5. while (cur < n)
    6. {
    7. if (arr[cur])dest++;
    8. else dest += 2;
    9. if (dest >= n - 1)break;
    10. cur++;
    11. }
    12. //2.处理边界
    13. if (dest == n)
    14. {
    15. arr[n - 1] = 0;
    16. cur--; dest--;
    17. }
    18. //3.从右往右完成复写
    19. while (cur >= 0)
    20. {
    21. if (arr[cur])arr[dest--] = arr[cur--];
    22. else
    23. {
    24. arr[dest--] = 0;
    25. arr[dest--] = 0;
    26. cur--;
    27. }
    28. }
    29. }
    30. //3.快乐数

    题目3:快乐数


    编写一个算法来判断一个数是不是快乐数。
    快乐数定义为:
    1.对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为1,也可能是无限循环但始给达不到1如果这个过程结果为1,那么这个数就是快乐数,如果n是快乐数就返回true,不是则返回false。
    1、题目解析
    示例:n=19                     n=2
    9²+9²=82                       2²=4
    8²+2²=68                       4²=16
    6²+8²=100                     1²+6²=37    
    1²+0²+0²=1                    3²+7²=58......89->145->42->20...2²+0²=2

    19就是快乐数 ,2不是快乐数。

    解法:快慢指针

    定义:

    1.定义快慢指针
    2.慢指针每一次向后移动一步
    3.快指针每一次向后移动两步
    根据鸽巢原理快慢指针最终会相遇
    4.判断相遇的值即可

    代码实现:

    1. int bitSum(int n)//返回n这个数每一位上的平方和
    2. {
    3. int sum = 0;
    4. while (n)
    5. {
    6. int t = n % 10;
    7. sum += t * t;
    8. n /= 10;
    9. }
    10. return sum;
    11. }
    12. bool isHappy(int n)
    13. {
    14. int slow = n, fast = bitSum(n);
    15. while (slow != fast)
    16. {
    17. slow = bitSum(slow);
    18. fast = bitSum(fast);
    19. }
    20. return fast == 1;
    21. }


    题目4:最多水的容器


    给定一个长度为n的整数数组height,有n条垂线,第i条钱的两个端点是(i,0)和(i,height[i])。找出其中两条线,使得它们与X轴共同构成的容器可以容纳最多的水,返回容器可以储存的最大水量。

    算法思想: 

    代码实现:

    1. int maxArea(vector<int>& height)
    2. {
    3. int left = 0, right = height.size() - 1, ret = 0;
    4. while (left < right)
    5. {
    6. int v = min(height[right], height[left]) * (right - left);
    7. ret = max(ret, v);
    8. if (height[right] > height[left])left++;
    9. else right--;
    10. }
    11. return ret;
    12. }

    题目5:有效三角形的个数


    给定一个包含非负整数的数组nums,返回其中可以组成三角形三条边的三元组个数。
    示例:如nums={2,2,3,4}
    输出3。
    解法—:暴力校举 
    解法二:利用单调性使用双指针算法
    1.对数组排序
    2.当对数组进行排序后,我们选定最右边的元素作为第三边,此时,只需在其的左区间找到两个元素之和大于它两组成三角形(最小两边之和大于最大的一边)
    以{2,2,3,4,5,8,9,10}为例

    nums[left]为左区间的最小值,而nums[right]为左区间的最大值,若此时nums[left]与nums[right]之和小于10,则此时在数组 nums中nums[left]无法与10组成三角形;若此时nums[left]与nums[right]之和大于10,则nums[right]与其左区间内的任一元素,都可以和10构成三角形。

    实现思想:

    实现代码:

    1. int triangNumber(vector<int>& nums)
    2. {
    3. //1.优化
    4. sort(nums.begin(), nums.end());
    5. //2.利用双指针结合单调性快速统计
    6. int ret = 0, n = nums.size();
    7. for (int i = n - 1; i >= 2; i--)
    8. {
    9. int left = 0, right = i - 1;
    10. while (left < right)
    11. {
    12. if (nums[left] + nums[right] > nums[i])
    13. {
    14. ret = ret + (right - left);
    15. right--;
    16. }
    17. else
    18. {
    19. left++;
    20. }
    21. }
    22. }
    23. return ret;
    24. }

    题目6:两数之和为s

    输入一个递增的排序数组和一个数字S,在数组中查找两个数使得它们的和正好是S,如果有多对的数字和为S,则输出任意一对即可。

    解法:利用数组递增,使用双推针解决问题

    1.sum>s;right--;
     2.sum 3.sum==t;return{nums[right],retunrn[left]};

    代码实现:

    1. vector<int> towSum(vector<int>& nums, int s)
    2. {
    3. //1, 0, 2, 3, 0, 4, 5, 0
    4. int left = 0, right = nums.size()-1;
    5. while (left < right)
    6. {
    7. int sum = nums[left] + nums[right];
    8. if (sum > s)right--;
    9. else if (sum < s)left++;
    10. else return { nums[left],nums[right] };
    11. }
    12. return { -1,-1 };
    13. }

  • 相关阅读:
    WebStorm的Vue工程如何用Bito插件进行单元测试
    GBASE 8s 数据库复合索引
    Disruptor-源码解读
    Go 原生插件使用问题全解析
    计算机如何自动辨别字义
    pytest自动化框架运行全局配置文件pytest.ini
    springboot项目作为静态文件服务器
    Python如何判断当前时间是否为夏令时?
    libtorch c++ 定义全链接网络
    Linux—软件管理
  • 原文地址:https://blog.csdn.net/weixin_66831846/article/details/133914608