【C++】使用双指针算法习题
🎆个人主页:夜晚中的人海
今日语录:用乐观的心态迎接困难,因为能打败你的,只有你自己。
文章目录
- 一、移动零
- 二、复写零
- 三、快乐数
- 四、有效三角形的个数
- 五、和为s的两个数字
一、移动零
题目链接:移动零
题目描述:
解题思路:
1.我们可以使用两个指针cur和dest,一个指针(cur)负责遍历整个数组,另一个指针(dest)用来记录非零序列
2.在遍历过程中会出现两种情况,一个是当遇到的元素为0时,cur直接++;相反当遇到的元素为非0时,让dest指针先自增一(由于不知道最后⼀个非零元素在什么位置,因此初始化为-1 ),与cur指针指向的元素进行交换,不断重复上述过程就可以解决这一类问题
代码实现:
class Solution
{
public:void moveZeroes(vector<int>& nums) {for(int cur = 0, dest = -1; cur < nums.size(); cur++)if(nums[cur]) swap(nums[++dest], nums[cur]);}
};
二、复写零
题目链接:复写零
题目描述:
解决思路:
1.我们使用两个指针cur和dest,当cur小于数组个数时,不断重复下述过程: 判断cur指向的数据元素,如果它为0,那么dest指针移动两位,否则移动一位,每判断完一次cur指针都需要++
2.判断dest指针是否越界到数组大小为n的位置上,如果越界,则直接将数组中最后一个位置赋值给0,然后对两个指针进行回退,cur指针退一步,dest指针退两步
3.然后对数组进行复写,判断cur当前位置是否为0,如果不为0,则将cur位置的值赋值给dest,然后两个指针分别–,否则将dest位置修改为0,重复两次该操作,然后让cur–
代码实现:
class Solution {
public:void duplicateZeros(vector<int>& arr) {int cur = 0,dest = -1;int n = arr.size();while(cur < n){if(arr[cur])dest++;elsedest += 2;if(dest >= n - 1){break;}cur++;}//处理边界情况if(dest == n){arr[n - 1] = 0;cur--;dest -= 2;}while(cur >= 0){if(arr[cur]){arr[dest--] = arr[cur--];}else{arr[dest--] = 0;arr[dest--] = 0;cur--;}}}
};
三、快乐数
题目链接:快乐数
题目描述:
解题思路:
我们可以使用快慢指针的方法,由于快慢指针的特性(注:就是在一个环中,快指针总会追上慢指针,也就是它们会相遇在一个位置上),当相遇位置的值为1时,则这个数为快乐数,否则不是
代码实现:
class Solution {
public:int bitsum(int num){int sum = 0;int i;while(num){i = num % 10;sum += i * i;num /= 10;}return sum;}bool isHappy(int n) {int slow = n,fast = bitsum(n);while(slow != fast){slow = bitsum(slow);fast = bitsum(bitsum(fast));}return slow == 1;}
};
四、有效三角形的个数
题目链接:有效三角形的个数
题目描述:
解题思路:
一、我们可以使用暴力求解的方法,使用三层for循环,枚举出所有的三元组,判断是否构成三角形。但这个方法的时间复杂度太高了,效率低,因此采用另一种方法
二、我们可以对数组先进行排序,然后固定一个最长边nuns[i],使用两个指针left和right(left < right),采用对撞指针的方法,一个指向开头位置,另一个指向i - 1的位置上,如果nums[left] + nums[right] > nums[i],那么满足条件的三角形个数就为right - left,然后让right–再进行判断,否则让left++,不断重复上述过程
代码实现:
class Solution {
public:int triangleNumber(vector<int>& nums) {sort(nums.begin(),nums.end());int n = nums.size();int ret = 0;for(int i = n - 1;i >= 2;i--){int left = 0,right = i - 1;while(left < right){if(nums[left] + nums[right] > nums[i]){ret += right - left;right--;}else{left++;}}}return ret;}
};
五、和为s的两个数字
题目链接:和为s的两个数字
题目描述:
解题思路:
一、暴力求解:使用两层for循环,列出所有两个数字的组合,判断是否等于目标值(结果会超时)
二、使用对撞指针,一个指针left指向开头,另一个指针right指向数组最后一个的位置(left < right),判断price[left] + price[right]是否等于target,如果大于则让right–,否则让left++,不断重复此过程
代码实现:
class Solution {
public:vector<int> twoSum(vector<int>& price, int target) {int n = price.size();int left = 0,right = n - 1;while(left < right){if(price[left] + price[right] > target){right--;}else if(price[left] + price[right] < target){left++;}else{return {price[left],price[right]};}}//照顾编译器return {1,1};}
};