单调栈leetcode总结

单调栈模板

单调栈用来求出数组nums[i]中第一个大于(小于)。

stack<int> stk; //存放的是index 当然有时候可以是值 看情况
vector<int> bigger;
for(int i =0; i< nums.size(); i++)
{
	while(!stk.empty() && nums[stk.back()] < nums[i])
	{
		//这里可以加出栈条件 
		bigger[stk.back() ] = i;
		stk.pop();
		//此时栈是单调减的
	}
	
	//这里可以加入入站条件
	stk.push_back(i);
}

leetcode 316 去除重复字母

此题要求对字符串去除重复的字母,并且保持字符串的字典序。

int removeDuplicateLetters(string s)
{
	vector<int> num(26,0), vis(26,0);
	//num用来记录s中26个字母的数量
	for(auto ch: s)
	{
		num[ch-'a']++;
	}
	
	//vis用来记录栈中是否有第i个字母
	string stk;
	for(auto ch :s)
	{
		if(!vis[ch-'a']) //栈中不存在ch
		{
			while(!stk.empty()&& ch < stk.back() )
			{
				//保持字典序意味着我们要用单调递增的栈
				//一旦ch 小于栈尾会影响单调性 应该弹栈了
				//但是stk.back()不一定能弹栈 
				//只有stk.back()这个字符还有剩余的时候可以弹栈
				if(num[stk.back()] > 0)
				{
					vis[stk.back() -'a'] = 0; //栈中不在有栈尾这个元素
					stk.pop_back();
				}
				else{
					break; //注意要跳出循环 因为如果这时候back不能弹 back之前的都不能弹
				}
			}
			stk.push_back(ch);
			vis[ch-'a'] = 1;
		}
		//不论ch进不进栈 可用的ch都少了一个
		num[ch - 'a']--;
	}
	//遍历结束
	return stk;
}
  1. 去除重复字符这个“去除“是通过vis来控制的,当栈中存在ch的时候,就没有必要再向栈中加入ch。
  2. num保证栈中至少有一个ch

leetcode321 拼接最大数

这道题的基本思路就是 从nums1中选i个最大的数, 从 nums2中选择k-i个最大的数。然后将他们merge在一起。
整体的框架:

vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k)
{
	int n1 = nums1.size(), n2 = nums2.size();
	vector<int> res1(k,0),res2(k,0); //res1 res2分别存储nums1, nums2的最大的几个
	vector<int> res(k,0);
	for(int i = 0;i < =k; i++)
	{
		if(i <= n1 && (k-i) <= n2)//可选
		{
			maxL(nums1,i, res1);
			maxL(nums2,k-i,res2);
			mergevec(res1, res2, i,k-i); //合并
			if(biger(res2,res))
			{
				res = res2;
			}
		}
	}
	return res;
}

其中maxL函数用来寻找nums数组中最大的L个,这时候就需要用到单调栈。由于有长度L的限制,弹栈的时候需要判断一下剩下的元素是否够用。

void maxL(vector<int>& nums, int L, vector<int>& res)
{
	int n = nums.size(), top = -1;//此时直接用res数组当栈了
	std::fill(res.begin(), res.end(),0);
	for(int i =0; i < n; i++)
	{
		while(top >=0 && nums[i] > res[top])
		{
			//后面有更大的元素 需要弹栈
			//当前的栈仍旧需要L个元素 数组中还剩下 n-1-i+1 = n-i个元素
			//如果弹栈 需要的元素数量为L+1 数组中还剩 n-i个元素
			//如果弹栈 L+1 <= n-i
			if(L<n-i)
			{
				top--,L++;
			}
			else
			{break;} //一定break不然死循环 卡在栈尾了
		}
		if(L>0)//仍有需要的元素
		{
			res[++top] = nums[i];
			L--;
		}
	}
}

获取了nums1的i个最大的元素和nums2的k-i个最大个元素 ,需要将他们合并。我这个合并函数写的不太好,凑合能用。

void mergevec(vector<int>& nums1, vector<int>& nums2, int l1, int l2)
{
	if(l1== 0){return ;}//merge nums1 into num2
	if(l2 == 0){ nums2 = nums1;return;}
	int i = 0, j= 0,k= l1+l2;
	vector<int> temp(k,0);
	for(int t = 0; t<k;t++)
	{
		if(i>= l1)
		{
			temp[t] = nums2[j++];
			continue;
		}
		if(j >l2)
		{
			temp[t] = nums1[i++];
			continue;
		}
		if(nums1[i] >nums2[j])
		{
			temp[t] = nums1[i++];
		}
		else if(nums1[i] <nums2[j])
		{
			temp[t] = nums1[j++];
		}
		else//这里有一个等于的情况  
		{
			int p1 = i,p2= j;
			while(true)
			{
				if(p1 == l1)//nums2最终是大的那一个
				{
					temp[t] = nums2[j++];
					break;
				}
				if(p2 == l2)
				{
					temp[t] = nums1[i++];
				}
				 if(nums1[p1] < nums2[p2])
                  {
                       temp[t] = nums2[j++];
                       break;
                  }
                   if(nums1[p1] > nums2[p2])
                   {
                       temp[t] = nums1[i++];
                       break;
                   }
                   p1++,p2++;
			}
		}
		

	}
	nums2 = temp;
}

其实就是等于的状态下判断一下哪个后缀大一些,感觉用后面的bigger函数也能做,不过我没试。

判断数组之间大小的函数biger:

    bool biger(vector<int>& nums1, vector<int>& nums2)
    {
        int k = nums1.size();
        for(int i =0; i < k;i++)
        {
            if (nums1[i] > nums2[i])
            {
                return true;
            }
            else if(nums1[i] <nums2[i])
            {
                return false;
            }
        }
        return false;
    }

这样就解决了这个问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值