枚举右,维护左
参考资料来源灵神在力扣所发的题单,仅供分享学习笔记和记录,无商业用途。
核心思路:用一个数据结构维护遍历过的区间,枚举未遍历区间
应用场景:解决双变量问题,例如两数之和 ai+aj=t,可以枚举右边的 aj,转换成 单变量问题,也就是在 aj 左边查找是否有 ai=t−aj,这可以用哈希表维护。
补充:不会漏掉一个组合,也不会出现重复组合情况
模板:
class Solution {
public:vector<int> twoSum(vector<int>& nums, int target) {unordered_map<int,int> map;for(int i=0;i<nums.size();i++){//查看维护的区间内是否包含需要的变量if(map.find(target-nums[i])!=map.end()) return {map[target-nums[i]],i};//更新维护区间map[nums[i]]=i;}return {0,0};}
};
力扣题单练习(灵神题单中摘取题目)
2441. 与对应负数同时存在的最大正整数 模板题
class Solution {
public:int findMaxK(vector<int>& nums) {set<int> s;int ret=-1;for(int i=0;i<nums.size();i++){//维护区间内找到相反数,判断是否为最大正整数if(s.find(-nums[i])!=s.end()) ret=max(ret,abs(nums[i]));//更新维护区间s.insert(nums[i]);}return ret;}
};
121. 买卖股票的最佳时机
核心思路:维护左(最小值),枚举右(当前元素-左区间最小值达到当前组合最优结果)。
class Solution {
public:int maxProfit(vector<int>& prices) {//核心思路:维护左(最小值),枚举右(当前元素-左区间最小值达到当前组合最优结果)。int ret=0,buff=INT_MAX;for(auto x:prices){ret=max(ret,x-buff);buff=min(buff,x);}return ret;}
};
624. 数组列表中的最大距离
核心思路:
采用枚举右维护左方式
需要在不同的数组中选取两个数求最大绝对差值。维护前面遍历过的数组最大值和最小值
枚举当前数组中的每一个数从而得出结果
class Solution {
public:int maxDistance(vector<vector<int>>& arrays) {//核心思路:采用枚举右维护左方式//需要在不同的数组中选取两个数求最大绝对差值。维护前面遍历过的数组最大值和最小值//枚举当前数组中的每一个数从而得出结果sort(arrays.begin(),arrays.end());int buff=INT_MAX,full=INT_MIN,ret=0,b,f;//维护左初始化第一个数组的最大最小值for(int i=0;i<arrays[0].size();i++){buff=min(buff,arrays[0][i]);full=max(full,arrays[0][i]);}b=buff;f=full;for(int i=1;i<arrays.size();i++){for(int j=0;j<arrays[i].size();j++){//更新结果ret=max(ret,abs(arrays[i][j]-buff));ret=max(ret,abs(full-arrays[i][j]));//更新最小值和最大值b=min(b,arrays[i][j]);f=max(f,arrays[i][j]);}//由于选的元素不能在同一个数组中,所以只有遍历完当前数组才能更新最大值和最小值buff=b;full=f;}return ret;}
};
2364. 统计坏数对的数目
核心思路:将j - i != nums[j] - nums[i]转换:nums[j]-j!=nums[i]-i;
正难反之:将问题转换成两个数的组合总量-好数对=坏数对,统计nums[j]-j==nums[i]-i数量;
class Solution {
public:long long countBadPairs(vector<int>& nums) {//核心思路:将j - i != nums[j] - nums[i]转换:nums[j]-j!=nums[i]-i;//正难反之:将问题转换成两个数的组合总量-好数对=坏数对,统计nums[j]-j==nums[i]-i数量;int n=nums.size();unordered_map<int,int> map;long long ret=1LL*n*(n-1)/2; //两个数的组合总量,等差公式:(首项+尾项)*累加个数/2for(int i=0;i<nums.size();i++) ret-=map[nums[i]-i]++;return ret;}
};
2905. 找出满足差值条件的下标 II
核心思路:枚举右,维护左(采用不定长滑窗维护满足abs(i - j) >= indexDifference的区间)
class Solution {
public:vector<int> findIndices(vector<int>& nums, int indexDifference, int valueDifference) {//核心思路:枚举右,维护左(采用不定长滑窗维护满足abs(i - j) >= indexDifference的区间)int min_buff=0,max_buff=0;for(int j=indexDifference;j<nums.size();j++){ //维护abs(i - j) >= indexDifferenceint i=j-indexDifference;if(nums[i]>nums[max_buff]){ //维护最大值下标max_buff=i;}else if(nums[i]<nums[min_buff]){ //维护最小值下标min_buff=i;}//枚举当前元素,在根据维护最大/最小值判断是否满足abs(nums[i] - nums[j]) >= valueDifferenceif(nums[max_buff]-nums[j]>=valueDifference) return {max_buff,j}; if(nums[j]-nums[min_buff]>=valueDifference) return {min_buff,j};}return {-1,-1};}
};
3584. 子序列首尾元素的最大乘积
核心思路:枚举右,在子序列为m的前提下,采用不定长滑窗维护从开始~当前位置-m+1的最大/最小值
class Solution {
public:long long maximumProduct(vector<int>& nums, int m) {//核心思路:枚举右,在子序列为m的前提下,采用不定长滑窗维护从开始~当前位置-m+1的最大/最小值long long buff=LLONG_MIN,zz=LLONG_MAX,ret=LLONG_MIN;int cnt=0,j=0;for(long long x:nums){cnt++;//当起点~当前元素满足>=m时,维护在起点~当前位置-m+1的最大/最小值if(cnt>=m){buff=max(buff,(long long)nums[j]);zz=min(zz,(long long)nums[j]);ret=max(max(ret,zz*x),buff*x);j++; //维护区间尾元素位置}}return ret;}
};