本文所涉及的题目的核心思想都是:双指针结合单调性
题一:盛最多水的容器
1.1链接
1.2思路
前提知识:
- 数组名为height
- 木桶装多少水取决于短板的长度
- 首先,我们先定义两个指针,一个为left,一个为right,体积V=h*w(h为高,w为宽)left = 0,right = height.size ( ) - 1,我们先计算此时的V为多少,然后再去分析,
- 若我们将长板往后(或前)挪一位,则其h可能发生的变化是不变或者变得更小,并且此时宽度也在减小,故体积V一定减小;
- 若我们把短板往后(或前)挪一位,体积V有变大的可能;
- 故我们每计算好一个V后,就对短板进行挪动操作,看那个V更大,再去更新最大值
1.到这,可能大家还会有疑问,就是那为什么要挪短板了?
这是因为我们如果继续挪长板的操作,是没有任何意义的,我们最终要找到的是最大值。
1.3代码实现
class Solution {
public:
int maxArea(vector<int>& height) {
int left = 0, right = height.size() - 1;
long long int ret = 0;
while (left < right) {
long long int v = min(height[left], height[right]) * (right - left);
ret = max(ret, v);
if (height[right] < height[left])
right--;
else {
left++;
}
}
return ret;
}
};
题二:有效三角形的个数
1.1链接
1.2思路
前提知识:
- 判断一个三角形,是任意二边之和大于第三边
- 对于已知大小的 a>=b>=c ,则只要保证 b+c>a 就可以
- 首先先对数组进行排序,将数组排成升序,并创建2个左右指针和count=0;
- 然后,我们在固定一个数c,我们数组后面往前去固定;left=0,right=固定数字的下标减1,sum = nums[left] + nums[right]
- 我们再去判断sum和c的关系,如果sum>c,那么此时count+=right-left,是因为++后,得到的 nums[left] 大于之前的值,一定可以构成三角形;
- 如果sum<=c,那么此时我们希望sum要大一点,由于数组此时是升序,那么则就是要将left++;
- 当left>=right,就结束一次判断,再固定另一个数,进行相同的操作
小优化:由于构成三角形一定要三个数,则我们 i>=2,没必要 i>0
1.3代码
class Solution {
public:
int triangleNumber(vector<int>& nums) {
sort(nums.begin(), nums.end());
int count = 0;
for (int i = nums.size() - 1; i >= 2; i--) {
int left = 0;
int right = i - 1;
int c = nums[i];
while (left < right) {
if (nums[left] + nums[right] > c) {
count += right - left;
right--;
} else {
left++;
}
}
}
return count;
}
};
题三:三数之和
1.1链接
1.2思路
这里的基本思路与题二一样,只是比较对象换了,操作换了。其他都是一样的。
- 这里要注意的是要进行排重,首先由于数组经过排序处理的,已经排好了升序;
- 那么我们在处理left和right的排重的时候,如果left++后下标所对应的值,与之前下标所对应的值相同,则left++,这里要保证left<right,这是为了不发生越界;
- 如果right--后下标所对应的值,与之前下标所对应的值相同,则right--,这里要保证left<right,这是为了不发生越界
- 接下来进行固定的数的排重,i++后下标所对应的值,与之前下标所对应的值相同,则i++,这里也要保证i<n,这是为了不发生越界;
1.3代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> arr;
int n = nums.size();
for (int i = 0; i < n;) {
if (nums[i] > 0)
break;
int left = i + 1;
int right = n - 1;
int c = -nums[i];
while (left < right) {
int sum = nums[left] + nums[right];
if (sum < c)
left++;
else if (sum > c)
right--;
else {
arr.push_back({nums[left], nums[right], nums[i]});
left++;
right--;
//排重 left和right
while (left < right && nums[left] == nums[left - 1])
left++;
while (right > left && nums[right] == nums[right + 1])
right--;
}
}
//排重i
i++;
while (i < n && nums[i] == nums[i - 1])
i++;
}
return arr;
}
};