【双指针】算法题(二)
前言:
这里是几道算法题,双指针说明在上一章。
一、有效三角形的个数
题目链接:
有效三角形的个数
题目叙述:
解法一:暴力循环,叠加三层for循环,但是这个方法会超时。
解法二:排序+双指针
这个方法减少for循环,是上一个方法的优化
算法思路:
- 由数学知识可知,两边之和大于第三边可构成三角形。
- 首先进行排序,然后固定一个较大的数 i ;
- 定义两个指针,在较大数 i 的前面区间进行遍历(即(0~i-1)区间);
- 若是nums[left]+nums[right]>nums[i] ,则次数ret+=right-left ;
- 否则,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;int right=i-1;while(left<right){if(nums[left]+nums[right]>nums[i]){ret+=right-left;right--;}else{left++;}}}return ret;}
};
二、盛最多水的容器
题目链接:
盛最多水的容器
题目描述:
解法一:暴力循环,枚举出来所有容器,然后找最大的那个容器的值,输出。(会超时)
解法二:对撞指针
- 定义两个指针,分别指向数组的左右两边,然后由于容器的高度是由短的那边决定高度的,因此容器容积公式是v=(right - left) * min(height[left],height[right]);
- 移动指针然后确定最大的容器。
代码:
class Solution {
public:int maxArea(vector<int>& height) {int n=height.size();int left=0;int right=n-1;int ret=0;while(left<right){int v=(right-left)*min(height[left],height[right]);ret=max(ret,v);if(height[left]<height[right]) left++;else right--;}return ret;}
};
三、三数之和
题目链接:
三数之和
题目描述:
解法:排序+双指针
算法思路:
- 先排序
- 然后固定一个数a;
- 然后在a后面的区间找出两个数之和等于 -a 即可。
- 需要注意的是,在数组中有一些重复的数,这些重复的数是我们要跳过的数,即去重操作。
代码:
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> ret;sort(nums.begin(),nums.end());int n=nums.size();for(int i=0;i<n;){if(nums[i]>0) break;int left=i+1,right=n-1,target=-nums[i];while(left<right){int sum = nums[left] + nums[right];if(sum<target) left++;else if(sum>target) right--;else {ret.push_back({nums[i],nums[left],nums[right]});left++;right--;while(left<right&&nums[left]==nums[left-1]) left++;//这里是去重操作,下面类似的也是while(left<right&&nums[right]==nums[right+1]) right--;}}i++;while(i<n&&nums[i]==nums[i-1]) i++;}return ret; }
};
做完这题可以试试四数之和
题目链接:
四数之和