【优先算法】双指针

news/2024/10/30 12:39:44/

✨✨欢迎大家来到Celia的博客✨✨

🎉🎉创作不易,请点赞关注,多多支持哦🎉🎉

所属专栏:优先算法

个人主页:Celia's blog~

目录

​​​​​​移动零

复写零

快乐数

盛水最多的容器

有效三角形个数

查找价值为目标值的两个商品

三数之和

四数之和




​​​​​​移动零

通过维护两个指针将数组分为三个部分:

  • 非零
  • 全零
  • 未处理

保证各个区间的要求不变:

  • cur指向的值为0, cur++
  • cur指向的值不为0,由于des本身的位置的值不为0,所以先要des++,再交换两个位置的值。
  • cur++,移动到下一个位置,以保证区间特点要求。

class Solution {
public:void moveZeroes(vector<int>& nums){int cur = 0, prev = -1;while(cur < nums.size()){if(nums[cur]){prev++;swap(nums[prev], nums[cur]);cur++;}else{cur++;}}    }
};

复写零

需要先模拟遍历,确定从哪一个位置开始复写(有特殊情况需要额外处理)。再从后向前遍历,进行复写。

class Solution {
public:void duplicateZeros(vector<int>& arr){int cur = 0, prev = -1;int n = arr.size();while(cur < n){if(arr[cur]) prev++;else prev += 2;if(prev >= n - 1) break;cur++;}if(prev >= n){arr[n - 1] = 0;prev -= 2;cur -= 1;}while(cur >= 0){if(arr[cur]) arr[prev--] = arr[cur--];else {arr[prev--] = 0;arr[prev--] = 0;cur--;}}}
};

快乐数

 把数字变化的过程抽象两种成环链表

  • 环中全为1
  • 环中不是1

一次计算来模拟链表的一次向后遍历,使用快慢指针来找到相交节点,并判断该节点的值。

class Solution {
public:int change(int num){int tmp = 0;while(num){int x = num % 10;tmp += x * x;num /= 10;}return tmp;}bool isHappy(int n) {int low = n, fast = change(n);while(low != fast){low = change(low);fast = change(fast);fast = change(fast);}if(low == 1) return true;return false;}
};

盛水最多的容器

 先定位最左最右节点。

若r向左移动:

  • 长度一定减小
  • 若是遇到比r节点高的,高度不变(由于取最小)。
  • 若是遇到比r节点小的,高度减小(由于取最小)。
  • 所以r,l中小的那一个无论怎么移动,总体积都在减小。没有必要继续遍历。
  • 故只要移动l,r中最小的那一个,就可以不断尝试其他的结果。

class Solution {
public:int maxArea(vector<int>& height){int l = 0, r = height.size() - 1;int maxV = 0;while(l < r){int V = min(height[l], height[r]) * (r - l);if(V > maxV) maxV = V;if(height[l] < height[r]) l++;else r--;}return maxV;}
};

有效三角形个数

 判断三角形的方法:

  • 两边之和大于第三边,判断三次
  • 有序:判断一次

故选择有序的情况进行三角形判断。先对数组进行排序,取一个最大的边(最后一个数组元素开始,依次向后移动)。再定义l,r分别在0位置和max-1位置处。

  • 若是l和r的和大于max,由于数组有序,l之后的元素必然都符合要求,共有r-l个结果。此时r的所有情况统计完毕,将r向左移动一位。
  • 若是l和r的和小于max,由于数组有序,l之后的元素必然都不符合要求,无结果。此时l的所有情况统计完毕,将l向右移动一位。
  • 当l >= r时,一轮遍历结束,将max向左移动一位,继续上述操作。

class Solution {
public:int triangleNumber(vector<int>& nums){sort(nums.begin(), nums.end());int max = nums.size() - 1;int count = 0;while(max >= 2){int l = 0, r = max - 1;while(l < r){if(nums[l] + nums[r] > nums[max]) count += r - l, r--;else l++;}max--;}return count;}
};

查找价值为目标值的两个商品

利用数组有序的特点,用两个指针快速遍历数组,找到结果后立即返回即可。

  • l和r的和小于目标值:l和最大的元素相加小于目标值,那么当前l右边的值都必然不符合要求,l++。
  • l和r的和大于目标值:r和最小的元素相加大于目标值,那么当前r左边的值都必然不符合要求,r--。

class Solution {
public:vector<int> twoSum(vector<int>& price, int target){int l = 0,r = price.size() - 1;while(l < r){if(price[l] + price[r] > target) r--;else if(price[l] + price[r] < target) l++;else break;}return {price[l], price[r]};}
};

三数之和

  • 与上一题思路大致相同,但必须保证数组有序,故需要先排序。
  • 并且这道题需要例出所有情况,不能找到马上返回,需要继续遍历。
  • 所有的情况不能有重复,所以移动所有指针时需要跳过重复的元素。

此题相比两个数多了一个数:

  • 先固定一个数
  • 再将剩余的两个数,用“两个数的和”这道题的方法来做(双指针)。
  • 之后大体框架相同,需要注意一些细节(越界问题、去重、不漏可能情况)。

class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums){sort(nums.begin(), nums.end());vector<vector<int>> vv;int cur = 0;while(cur < nums.size() - 2){int l = cur + 1, r = nums.size() - 1;while(l < r){int tmp = nums[l] + nums[r] + nums[cur];if(!tmp){vv.push_back({nums[l], nums[r],  nums[cur]});r--, l++;while(l < r && r >= 0 && nums[r] == nums[r + 1]){r--;}while(l < r && l < nums.size() && nums[l] == nums[l - 1]){l++;}}else if(tmp > 0){r--;while(l < r && r >= 0 && nums[r] == nums[r + 1]){r--;}}else{l++;while(l < r &&(l < nums.size() && nums[l] == nums[l - 1])){l++;}}}cur++;while(cur < nums.size() && nums[cur] == nums[cur - 1]){cur++;}}return vv;}
};

四数之和

此题在三个数的基础上多了一个数:

  • 固定两个数
  • 剩下两个数按照双指针思路来做,大体框架一模一样。

此题需要注意数组元素的大小容易过大,导致计算溢出,所以需要采用两两相加的方式来比较大小。

class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target){vector<vector<int>> vv;int n = nums.size();sort(nums.begin(), nums.end());int a = 0;while(a < n - 3){int b = a + 1;while(b < n - 2){int l = b + 1, r = n - 1;long long aim = (long long)target -  nums[a] - nums[b];while(l < r){long long sum = nums[l] + nums[r];if(sum == aim){vv.push_back({nums[a], nums[b], nums[l], nums[r]});l++, r--;while(l < r && nums[l] == nums[l - 1]) l++;while(l < r && nums[r] == nums[r + 1]) r--;}else if(sum < aim) l++;else r--;}b++;while(b < n - 2 && nums[b] == nums[b - 1]) b++;}a++;while(a < n - 3 && nums[a] == nums[a - 1]) a++;}return vv;}
};

http://www.ppmy.cn/news/1543103.html

相关文章

驱动和芯片设计哪个难

驱动和芯片设计哪个难 芯片设计和驱动开发 芯片设计和驱动开发 都是具有挑战性的工作&#xff0c;它们各自有不同的难点和要求。 对于芯片设计&#xff0c;它是一个集高精尖于一体的复杂系统工程&#xff0c;涉及到从需求分析、前端设计、后端设计到流片的全过程。 芯片设计的…

Mask RCNN原理详解(个人学习笔记)

目录 mask RCNN1. Background2. ROIAlign3. Network Architecture4. class-specific mask mask RCNN 首先从introduction看起&#xff0c;mask RCNN是在Faster R-CNN的基础上添加了一个额外的分割分支&#xff08;该分支和Faster RCNN的分类分支及回归分支并行运行&#xff09…

nrm的使用

在安装nrm之前&#xff0c;要先完成node.js的安装。 1、nrm的介绍 ‌nrm&#xff08;npm registry manager&#xff09;是一个npm源管理器&#xff0c;允许用户在不同npm源之间快速切换。 关于npm和nvm的介绍&#xff0c;详见文章nvm的使用-CSDN博客。 解释&#xff1a;比如…

macOS开发环境配置与应用开发教程

macOS开发环境配置与应用开发教程 引言 macOS是一个强大的操作系统&#xff0c;广泛应用于软件开发&#xff0c;尤其是iOS和macOS应用开发。本文将详细介绍如何配置macOS开发环境&#xff0c;并通过实例演示如何进行应用开发。希望通过这篇文章&#xff0c;帮助读者快速上手m…

破解OCR生僻字难题,中安文字识别技术让文字录入更简单

生僻字的困扰已经逐渐渗透到我们的日常生活和工作中。无论是档案整理、系统录入&#xff0c;还是智能校对&#xff0c;越来越多的信息系统对文字输入的准确性提出了更高要求。然而&#xff0c;面对动辄万千的汉字&#xff0c;以及少数民族语言的应用&#xff0c;许多传统识别系…

基于uniapp微信小程序的旅游系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

武汉赛思云科技签约汽车之家,DuDuTalk语音工牌助力汽车门店线下服务过程管理智能化

近日&#xff0c;武汉赛思云科技有限公司与知名汽车服务平台汽车之家达成重要合作。双方将共同推动汽车销售和服务领域的数字化转型&#xff0c;其中关键一环便是引入由赛思云科技自主研发的DuDuTalk语音工牌系统。这一创新解决方案旨在通过提升汽车门店的服务质量和管理效率&a…

在IDEA中运行Mybatis后发现取出的password值为null

问题&#xff1a; 解决方案&#xff1a;修改sql文如下&#xff08;取别名&#xff09; Select("select id,name,pwd as password from user where id #{id}") 重新运行即可