知识点:双向指针盛最多水的容器 接雨水【基础算法精讲 02】_哔哩哔哩_bilibili
相关题目与题解:
- 盛最多水的容器
cpp
class Solution {
public:
int maxArea(vector<int>& height) {
// 思路:面积=宽度*最小高度,优先缩宽度、提高度
int n = height.size();
int left = 0; // 左指针,初始在数组最左端
int right = n - 1; // 右指针,初始在数组最右端
int ans=0, area = 0; // 【问题1】ans未初始化!会导致随机值,最终结果错误
while (left < right) { // 指针相遇时停止(宽度为0,无意义)
// 计算当前指针组合的面积:最小高度 * 指针间距(宽度)
area = min(height[left], height[right]) * (right - left);
// 更新最大面积:取当前最大面积和新计算面积的较大值
ans = max(ans, area);
// 核心策略:移动较矮的指针(移动较高指针无法提升最小高度,只会缩宽度)
if (height[left] < height[right]) {
left++;
} else
right--;
}
return ans;
}
};
- 接雨水
cpp
class Solution {
public:
int trap(vector<int>& height) {
// 边界处理:数组长度<3时无法接水,直接返回0
//if (height.size() < 3) return 0;
int n = height.size();
// 初始化前后缀数组大小为n,避免越界
vector<int> pre_height(n);
// 前缀最大值数组:pre_height[i]表示i左侧(含i)的最大高度
vector<int> pro_height(n);
// 后缀最大值数组:pro_height[i]表示i右侧(含i)的最大高度
// 构建前缀最大值数组
pre_height[0] = height[0];
for (int i = 1; i < n; i++) { // 遍历整个数组,而非到n-1
pre_height[i] = max(height[i], pre_height[i - 1]);
}
// 构建后缀最大值数组
pro_height[n - 1] = height[n - 1];
for (int i = n - 2; i >= 0; i--) { // 遍历到0,而非>0
pro_height[i] = max(height[i], pro_height[i + 1]);
}
int ans = 0;
// 遍历每个位置(0到n-1),计算每个位置能接的水量
for (int i = 0; i < n; i++) {
// 每个位置接水量 = 左右两侧最大高度的较小值 - 当前高度(结果≥0才有效)
ans += min(pre_height[i], pro_height[i]) - height[i];
}
return ans;
}
};
- 验证回文串
cpp
class Solution {
public:
bool isPalindrome(string s) {
// 将所有大写字符转换为小写字符、并移除所有非字母数字字符之后.
//! isalnum() 用于判断 "非字母数字字符"
// 思路:左指针往前走,右指针往后走,遇到非字母数字字符跳过;全转化为小写字母进行判断
// isalpha() 判断是否是字母 过滤数字 / 符号
// isdigit() 判断是否是数字 提取数字 / 过滤字母
// tolower() 转小写字母 忽略大小写比较
// toupper() 转大写字母 忽略大小写比较
int n=s.size()-1;
int left=0; int right=n;
while(left<right){
if(!isalnum(s[left])) left++;
else if(!isalnum(s[right])) right--;
else if(tolower(s[left])==tolower(s[right])) {
left++;
right--;
}//下面两个都用else if,可以保证每次都只移动一个指针,不会出现移动两个造成指针交叉的情况
else return false;
}
return true;
}
};
- 给植物浇水 II
cpp
class Solution {
public:
int minimumRefill(vector<int>& plants, int capacityA, int capacityB) {
// 直接模拟
// capacity先于plants[i]作比较,// 如果<,ans+1,capacity恢复
// capacity>plants[i],capacity-=plants[i];i++;
int left = 0;
int right = plants.size() - 1;
int ans = 0;
int cura = capacityA;
int curb = capacityB;
while (left < right) {
//先处理A
if(cura<plants[left]){
ans++;
cura=capacityA;
}
cura-=plants[left];
left++;
//于此同时B
if(curb<plants[right]){
ans++;
curb=capacityB;
}
curb-=plants[right];
right --;
}
if(left==right&&max(cura,curb)<plants[left]){
ans+=1;
}
return ans;
}
};
复盘与总结
记录错题本
题目一:
cpp
int ans, area = 0; // 【问题1】ans未初始化!会导致随机值,最终结果错误
一开始需要先计算面积大小,然后不断迭代变大。
//面积公式写在前面
题目二:
cpp
vector<int> pre_height(n); //声明时长度的写法
// 构建前缀最大值数组
pre_height[0] = height[0];
for (int i = 1; i < n; i++) { // 遍历整个数组,而非到n-1
pre_height[i] = max(height[i], pre_height[i - 1]);
}
第一个的赋值不要忘记!
题目三:
cpp
while(left<right){
if(!isalnum(s[left])) left++;
else if(!isalnum(s[right])) right--;
else if(tolower(s[left])==tolower(s[right])) {
left++;
right--;
}
下面两个都用else if,可以保证每次都只移动一个指针,不会出现移动两个造成指针交叉的情况
题目四:逻辑的整理
代码模板
cpp
int n = height.size();
int left = 0; // 左指针,初始在数组最左端
int right = n - 1; // 右指针,初始在数组最右端
int ans = 0;
while (left < right){
这里面也要时刻保证left<right!!
}