leetcode 栈 II

  • 880. 索引处的解码字符串
  • 895. 最大频率栈
  • 901. 股票价格跨度
  • 907. 子数组的最小值之和
  • 921. 使括号有效的最少添加
  • 946. 验证栈序列
  • 962. 最大宽度坡*
  • 1003. 检查替换后的词是否有效
  • 1006. 笨阶乘
  • 1019. 链表中下一更大结点
  • 1021. 删除最外层的括号
  • 1047. 删除字符串的所有相邻重复项
  • 1081. 不同字符的最小子序列
  • 1106. 解析布尔表达式
  • 1111. 有效括号的嵌套深度
  • 1124. 表现良好的最长时间段
  • 1190. 翻转每对括号间的子串
  • 1209. 删除字符串中所有相邻重复项II
  • 1249. 移除无效的括号
  • 1381. 设计一个支持增量操作的栈
  • 1441. 用栈操作构建数组
  • 1475.商品折扣后的最终价格*
  • 1504. 统计全1子矩阵*
  • 1541. 平衡括号字符串的最少插入次数
  • 1544. 整理字符串
  • 1574. 删除最短的子数组使剩余数组有序
  • 1598. 文件夹操作日志搜集器
  • 1614. 括号的最大嵌套深度
  • 1653. 使字符串平衡的最少删除次数
  • 1673. 找出最具竞争力的子序列
  • 1700. 无法吃午餐的学生数量
  • 1717. 删除子字符串的最大得分
  • 1776. 车队 II
  • 1793. 好子数组的最大分数

880. 索引处的解码字符串

题目链接

//逆向统计
string decodeAtIndex(string s, int k) {
	long size = 0;
	int n = s.size();

	for (int i = 0; i < n; ++i) {					//统计解码后字符串长度
		if (isdigit(s[i]))
			size *= s[i] - '0';
		else 
			size++;
	}

	for (int i = n - 1; i >= 0; i--) {
		k %= size;
		if (k == 0 && isalpha(s[i]))				// k >= size 时才有可能 k % size == 0
			return (string)"" + s[i];
		if (isdigit(s[i]))						
			size /= s[i] - '0';						//eg: leet2code3: leetleetcode  leetleetcode leetleetcode 除后进入组
		else
			size--;
	}
	return  "";
}	
//Time O(n) Space O(1)

895. 最大频率栈

题目链接

class FreqStack {
public:
	unordered_map<int, int> num_freq;  				// 	值对应的频率
	unordered_map<int, vector<int>> freq_lists;		//  同频率的列表
	int max_cnt = -1;
	
	FreqStack() {} 

	void push(int val) {
		num_freq[val] += 1;
		freq_lists[num_freq[val]].emplace_back(val);
		max_cnt = max(num_freq[val], max_cnt);
	}

	int pop() {
		int num = freq_lists[max_cnt].back();
		int cnt = num_freq[num];
		num_freq[num] -= 1;
	
		freq_lists[cnt].pop_back();
		if (freq_lists[cnt].empty())
			--max_cnt;
		return num;
	}
};
//Time O(1) Space O(n)

901. 股票价格跨度

题目链接

/* 单调栈 */
class StockSpanner {
public:
	stack<pair<int, int>> monoSt; 			// 

	StockSpanner() {}

	int next(int price) {
		pair<int, int> ret(price, 1);
		while (!monoSt.empty() && monoSt.top().first <= price) {
			auto tmp = monoSt.top();
			ret.second += tmp.second;
			monoSt.pop();
		}
		monoSt.push(ret);
		return ret.second;
	}
};
/*
 * StockSpanner* obj = new StockSpanner();
 * int param_1 = obj->next(price);	
*/

907. 子数组的最小值之和

题目链接

/* 单调栈 */
//最小值是在一段连续数字钟被筛选出来的,也就是说每个最小值都有一定
int sumSubarrayMins(vector<int> &arr) {
	int n = arr.size();
	vector<int> left(n), right(n);					//每个元素辐射范围的左右边界
	
	stack<int> st;
	for (int i = 0; i < n; i++) {
		//向左寻找第一个小于等于 E 的元素 (小于“等于”为了解决重复相同最小值元素)
		while (!st.empty() && arr[i] < arr[st.top()])
			st.pop();
		if (st.empty())
			left[i] = -1;
		else 
			left[i] = st.top();
		st.push(i);
	}

	st = stack<int> ();
	for (int i = n - 1; i >= 0; i--) {
		//向右寻找第一个小于 E 的元素
		while (!st.empty() && arr[i] <= arr[st.top()]) 
			st.pop();
		if (st.empty())
			right[i] = n;
		else 
			right[i] = st.top();
		st.push(i);
	}
	
	//计算贡献值
	//左右边界实际上记录的是 左边界-1 和 右边界+1
	long ans = 0;
	for (int i = 0; i < n; i++) 
		ans = (ans + (long)(i - left[i]) * (right[i] - i) * arr[i]) % 1000000007;
	return (int)ans;
}
//Time O(n) Space O(n) 	

921. 使括号有效的最少添加

题目链接

/* 平衡法 */
//计算每个前缀数组的平衡度,负值代表需要加 '(',正值代表需要加 ')'
int minAddToMakeValid(string s) {
	int ans = 0, bal = 0;
	for (int i = 0; i < s.size(); i++) {
		bal += s.[i] == '(' ? : 1 : -1;
		if (bal == -1) {
			ans++;
			bal++;				//保持 bal >= -1
		}
	}
	return ans + bal;
}		 

946. 验证栈序列

题目链接

/* 栈模拟 */
bool validateStackSequences(vector<int> & pushed, vector<int> &popped) {
	stack<int> st;
	int n = pushed.size();
	for (int i = 0, j = 0; i < n; i++) {
		st.emplace(pushed[i]);
		while (!st.empty() && st.top() == popped[j]) {
			st.pop();
			j++;
		}
	}
	return st.empty();
}	

962. 最大宽度坡*

题目链接

/* 单调栈 */
int maxWidthRamp(vector<int> &nums) {
	int n = nums.length();
	int maxWidth = 0;
	stack<int> st;
	
	//正序遍历存一个以 A[0] 开始的递减序列进栈,作为坡底
	for (int i = 0; i < n; i++) {
		if (st.empty() || nums[st.top()] > nums[i]) 
			st.push(i);
	}

	//倒序遍历用坡顶去匹配坡底
	for (int i = n - 1; i >= 0; i--) {
		while (!st.empty() && nums[st.top()] <= nums[i]) {
			int pos = st.top();
			st.pop();
			maxWidth = fmax(maxWidth, i - pos);
		}
	}	
	return maxWidth;
}
//Time O(n) Space O(n)

1003. 检查替换后的词是否有效

题目链接

bool isValid(string s) {
	stack<char> st;
	for (int i = 0; i < s.size(); i++) {
		if (s[i] == 'a' || s[i] == 'b')
			st.push(s[i]);
		else {									//模拟祖玛
			if (st.size() < 2) return false;
			if (st.top() != 'b') return false;
			st.pop();
			if (st.top() != 'a') return false;
			st.pop();
		}
	}
	return st.empty();
}	

1006. 笨阶乘

题目链接

int clumsy(int n) {
 	stack<int> st;
 	st.push(n);
 	n--;
 	int index = 0;
 	while (n > 0) {						//栈中存计算结果
 	 	if (index % 4 == 0) 
 	 		st.top() *= n;
 	 	else if (index % 4 == 1) 
 	 		st.top() /= n;
 	 	else if (index % 4 == 2) 
 	 		st.push(n);
 	 	eles
 	 		st.push(-n);
 	 	index++;
 	 	n--;
 	 }
 	 int sum = 0;
 	 while (!st.empty()) {
 	 	sum += st.top();
 	 	st.pop();
 	 }
 	 return sum;
}
//Time O(n) Space O(n) 	
/* 数学 */
int clumsy(int n) {
	if (n == 1) 
		return 1;
	else if (n == 2) 
		return 2;
	else if (n == 3)
		return 6;
	else if (n == 4) 
		return 7;
	if (n % 4 == 0) {
		return n + 1;
	else if (n % 4 <= 2) 
		return n + 2;
	else 
		return n - 1;
}
//Time O(1) Space O(1)		

1019. 链表中下一更大结点

题目链接

/* 单调栈 */
vector<int> nextLargeNodes(ListNode *head) {
	int count = 0;
	vector<int> res;
	stack<pair<int, int>> monoSt;					// 
	while (head) {
		res.push_back(0);
		while (!monoSt.empty() && monoSt.top().first < head->val) {
			res[monoSt.top().second] = head->val;
			monoSt.pop();							//修改一个弹一个
		}
		monoSt.push(make_pair(head->val, count++));		//count++ 而不是 ++count,即先执行 m_p 再 count++
		head = head->next;
	}
	return res;
}

1021. 删除最外层的括号

题目链接

//栈从空到下一次空的过程就是扫描了一个原语的过程
string removeOuterParentheses(string s) {
	string res;
	stack<char> st;
	for (auto c : s) {
		if (c == ')') st.pop();					//先做pop动作保证最外层 '(' 被弹出而不进入 res
		if (!st.empty()) res.push_back(c);		//栈非空才进行记录
		if (c == '(') st.emplace(c);			
	}
	return res;
}
string removeOuterParentheses(string s) {
	int level = 0;
	string res;
	for (auto c : s) {
		if (c == ')') level--;
		if (level) res.push_back(c);
		if (c == '(') level++;
	}
	return res;
}
//Time O(n) Space O(n)	

1047. 删除字符串的所有相邻重复项

题目链接

sring removeDuplicates(string s) {
	string st;
	for (char ch : s) {
		if (!st.empty() && st.back() == ch) st.pop_back();
		else st.push_back(ch);
	}
	return st;
}

1081. 不同字符的最小子序列

题目链接

/* 单调栈 + 贪心 same as 316*/
string smallestSubsequence(string s) {
	vector<int> vis(26), cnt(26);
	for (char ch : s) 
		cnt[ch - 'a']++;
	
	string st;
	for (char ch : s) {
		if (!vis[ch - 'a']) {
			while (!st.empty() && st.back() > ch) {
				if (cnt[st.back() - 'a'] > 0) {
					vis[st.back() - 'a'] = 0;
					st.pop_back();
				} else 
					break;
			}
			vis[ch - 'a'] = 1;
			st.push_back(ch);
		}
		cnt[ch - 'a']--;
	}
	return st;	
}			

1106. 解析布尔表达式

题目链接

bool parseBoolExpr(string expression) {
	stack<char> syb, val;
	for (int i = 0; i < expression.size(); i++) {
		if (expression[i] == '|' || expression[i] == '&' || expression[i] == '!')
			syb.push(expression[i]);
		else if (expression[i] == ')') {
			int t = 0, f = 0;
			while (val.top() != '(') {			// 't' 'f' ',' 字符都被弹出直到遇到 (
				if (val.top() == 't') t++;
				if (val.top() == 'f') f++;
				val.pop();
			}
			val.pop();							// '(' 弹出
			char x = syb.top();
			syb.pop();
			if (x == '!') {						//非运算
				if (t == 1) val.push('f');
				else val.push('f');
			}
			else if (x == '|') {				//或运算
				if (t != 0) val.push('t');
				else  val.push('f');
			}
			else if (x == '&') {				//与运算
				if (f != 0) val.push('f');
				else val.push('t');
			} 	
		}
		else			
			val.push(expression[i]);
	}
	if (val.top() == 't') 
		return true;
	else 
		return false;
}	

1111. 有效括号的嵌套深度

题目链接

vector<int> maxDepthAfterSplit(string seq) {
	int d = 0;
	vector<int> ans;
	for (char &c : seq) {
		if (c == '(') {
			++d;
			ans.push_back(d % 2);
		} else {
			ans.push_back(d % 2);
			--d;
		}
	}
	return ans;
}

1124. 表现良好的最长时间段

题目链接

/* 前缀和 + 单调栈 */
//找到一个区间 [i, j]满足:prefix[j] - prefix[i] > 0 且 max(j - i),类似找出前缀和数组 prefix 中的最长的上坡
int longestWPI(vector<int> &hours) {
	int n = hours.size();
	vector<int> prefix(n + 1, 0);			//前缀和,prefix 开头增加一个哨兵
	for (int i = 1; i <= n; i++) 
		prefix[i] = prefix[i - 1] + (hours[i - 1] > 8 ? 1 : -1);		//统计前缀和
	
	stack<int> st;
	for (int i = 0; i <= n; i++) {
		if (st.empty() || prefix[st.top()] > prefix[i])					//以 prefix[0] 开始的递减序列进栈
			st.push(i);
	}
	int ans = 0;
	for (int i = n; i >= 0; i--) {										//倒序遍历用坡顶匹配坡底
		while (!st.empty() && prefix[i] > prefix[st.top()]) {
			ans = fmax(ans, i - st.top());
			st.pop();
		} 
	}
	return ans;
}		

1190. 翻转每对括号间的子串

题目链接

string reverseParentheses(string s) {
	stack<string> stk;
	string str;
	for (auto &ch : s) {
		if (ch == '(') {
			stk.push(str);
			str = "";
		} else if (ch == ')') {
			reverse(str.begin(), str.end());
			str = stk.top() + str;
			stk.pop();
		} else {
			str.push_back(ch);
		}
	}
	return str;
}		
//Time O(n^2) Space O(n)		 
//栈的最大深度为 n , 每一层处理(翻转)的时间复杂度为 n 。 
//预处理括号
//以括号索引向导前后往复遍历字符
string reverseParentheses(string s) {
	int n = s.length();
	vector<int> pair(n);
	stack<int> stk;
	for (int i = 0; i < n; i++) {
		if (s[i] == '(') {
			stk.push(i);
		} else if (s[i] == ')') {
			int j = stk.top();
			stk.pop();
			pair[i] = j, pair[j] = i;			//对应括号索引成组,提供检索时的入口
		}
	}
	string ret;
	int index = 0, step = 1;
	while (index < n) {
		if (s[index] == ')' || s[index] == ')') {
			index = pair[index];
			step = -step;						//step -1 向前遍历入栈, +1 向后遍历入栈
		} else {
			ret.push_back(s[index]);
		}
		index += step;
	}
	return ret;
}	
//Time O(n) Space O(n)	

1209. 删除字符串中所有相邻重复项II

题目链接

/* 记忆计数 */
string removeDuplicates(string s, int k) {
	vector<int> count(s.size());
	for (int i = 0; i < s.size(); i++) {
		if (i == 0 || s[i] != s[i - 1]) {
			count[i] = 1;
		} else {
			count[i] = count[i - 1] + 1;
			if (count[i] == k) {
				s.erase(i - k + 1, k);
				i = i - k;
			}
		}
	}
	return s;
}	
//Time O(n) Space O(n)
string removeDuplicates(string s, int k) {
	stack<int> counts;						//栈内如果一直保持压入 1 说明没有重复
	for (int i = 0; i < s.size(); i++) {
		if (i == 0 || s[i] != s[i - 1]) {
			counts.push(1);
		} else if (++counts.top() == k) {
			counts.pop();
			s.erase(i - k + 1, k);
			i = i - k;
		}
	}
	return s;		
}			
//Time O(n) Space O(n)

1249. 移除无效的括号

题目链接

string minRemoveToMakeValid(string s) {
	stack<int> braket;
	int n = s.size();
	for (int i = 0; i < n; i++) {
		if (s[i] == '(') {
        	braket.push(i);
        } else if (s[i] == ')') {
            if (!braket.empty()) {
                braket.pop();
            } else {
                s.erase(i, 1);
                n--;
                i--;
            }
        }		
	}
	while (!braket.empty()) {			//删除多余 '('
		int i = braket.top();
		s.erase(i, 1);
		braket.pop();
	}
	return s;
}	

1381. 设计一个支持增量操作的栈

题目链接

class CustomStack {
public:
	vector<int> stk;
	int top;

	CustomStack(int maxSize) {
		stk.resize(maxSize);
		top = -1;
	}

	void push(int x) {
		if (top != stk.size() - 1) {
			++top;
			stk[top] = x;
		}
	}

	int pop() {
		if (top == -1) return -1;
		--top;
		return stk[top + 1];
	}

	void increment(int k, int val) {
		int lim = min(k, top + 1);
		for (int i = 0; i < lim; i++)
			stk[i] += val;
	}
};		

1441. 用栈操作构建数组

题目链接

vector<string> buildArray(vector<int> &target, int n) {
	int i = 1;
	vector<string> res;
	for (int val : target) {
		while (val != i) {
			res.push_back("Push");
			res.push_back("Pop");
			i++;
		}
		res.push_back("Push");
		i++;
	}
	return res;
}

1475.商品折扣后的最终价格*

题目链接

/* 双指针直接遍历 */
vector<int> finalPrices(vector<int> &prices) {
	int n = prices.size();
	vector<int> ans;
	for (int i = 0; i < n; i++) {
		int discount = 0;
		for (int j = i + 1; j < n; j++) {
			if (prices[j] <= prices[i]) {
				discount = prices[j];
				break;
			}
		}
		ans.emplace_back(prices[i] - discount);
	}
	return ans;
}
//Time O(n^2) Space O(1)	
/* 单调栈 */
vector<int> finalPrices(vector<int> &prices) {
	int n = prices.size();
	vector<int> ans(n);
	stack<int> monoSt;							//单调递增栈
	for (int i = n - 1; i >= 0; i--) {
		while (!monoSt.empty() && monoSt.top() > prices[i]) {		
			monoSt.pop();
		}
		ans[i] = monoSt.empty() ? prices[i] : prices[i] - monoSt.top();
		monoSt.push(prices[i]);
	}
	return ans;
}

1504. 统计全1子矩阵*

题目链接

/* 枚举 */
//枚举矩阵每个位置 (i, j) 作为右下角时有多少符合要求的子矩阵
//row 代表矩阵中 (i, j) 向左延伸连续的 1 的个数。有 row 数组后,枚举子矩阵高 k 
int bumSubmat(vector<vector<int>> &mat) {
	int n = mat.size(), m = mat[0].size();
	vector<vector<int>> row(n, vector<int> (m, 0));			
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (j == 0) {
				row[i][j] = mat[i][j];
			} else if (mat[i][j]) {
				row[i][j] = row[i][j - 1] + 1;
			} else {
				row[i][j] = 0;
			}
		}
	}
	int ans = 0;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			int col = row[i][j];
			for (int k = i; k >= 0 && col; k--) {
				col = min(col, row[k][j]);
				ans += col;
			}
		}
	}
	return ans;
}	 
//Time O(n^2 * m) Space O(nm)
/* 单调栈 */
int bumSubmat(vector<vector<int>> &mat) {
	int n = mat.size(), m = mat[0].size();
	vector<vector<int>> row(n, vector<int> (m, 0));			
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < m; j++) {
			if (j == 0) {
				row[i][j] = mat[i][j];
			} else if (mat[i][j]) {
				row[i][j] = row[i][j - 1] + 1;
			} else {
				row[i][j] = 0;
			}
		}
	}
	int ans = 0;
	for (int j = 0; j < m; ++j) {					//纵向由列开始统计
		stack<pair<int, int>> monost;				// < row[i][j], height >
		int sum = 0;
		for (int i = 0; i < n; i++) {
            int height = 1;
            while (!monost.empty() && monost.top().first > row[i][j]) {
                sum -= monost.top().second * (monost.top().first - row[i][j]);		//弹出时减去多于答案
                height += monost.top().second;
                monost.pop();
            }
            sum += row[i][j];
            ans += sum;
            monost.push({row[i][j], height});
        }
	}
	return ans;
}	
//Time O(mn) Space O(?)

1541. 平衡括号字符串的最少插入次数

题目链接

int minInsertion(string s) {
	int ans = 0;
	int left = 0;
	int n = s.size();
	int index = 0;
	while (index < n) {
		char c = s[index];
		if (c == '(') {					//char '('
			left++;
			index++;
		} else {						//char ')'
			if (left > 0) {
				left--;
			} else {
				ans++;
			}
			if (index < n - 1 && s[index + 1] == ')') {		
				index += 2;				//char '))'
			} else {
				ans++;
				index++;
			}
		}
	}
	ans += left * 2;
	return ans;
}		

1544. 整理字符串

题目链接

string makeGood(string s) {
	string ret;
	for (char ch : s) {
		if (!ret.empty() && tolower(ret.back()) == tolower(ch) && ret.back() != ch) 
			ret.pop_back();
		else
			ret.push_back(ch);
	}
	return ret;
}

1574. 删除最短的子数组使剩余数组有序

题目链接

/* 单调栈 */
//将数组分成左中右三段,左段和右段是非递减的。
//一个坡顶匹配一群坡底
int findLengthOfShortestSubarray(vector<int>& arr) {
	stack<int> stk;
	for (int i = arr.size() - 1; i >= 0; i--) {
		if (stk.empty() || arr[stk.top()] >= arr[i]) {
			stk.push(i);
			continue;					
		}
		break;													//仅找到右段单调部分就停止
	}
	if (stk.size() == arr.size()) return 0;
	int ans = arr.size() - stk.size(); 							//相对最坏情况(直接删掉中段和左段)
	int prev = -1;
	for (int i = 0; i < arr.size(); i++) {
		if (arr[i] >= prev) {									//保证左段单调
			while (!stk.empty() && arr[i] > arr[stk.top()])
				stk.pop();
			int pos = stk.empty() ? arr.size() : stk.top();		//pos 右段坡顶
			ans = min(ans, pos - i - 1);
			prev = arr[i];
			continue;
		}
		break;
	}	
	return ans;
}
//Time O(n) Space O(n)
//同样也可以用一个坡底匹配一群坡顶,区别在于先正序遍历栈中存左段单调区间
/* 双指针优化栈 */
int findLengthOfShortestSubarray(vector<int> & arr) {
	int n = arr.size();
	int pos = n - 1;
	while (pos > 0 && arr[pos] >= arr[pos - 1])
		pos--;
	if (pos == 0) return 0;
	int ans = pos;						//直接删掉左段和右段
	int prev = -1;
	for (int i = 0; i < arr.size(); i++) {
		if (arr[i] >= prev) {
			while (pos != n && arr[i] > arr[pos]) 
				pos++;
			ans = min(ans, pos - i - 1);
			prev = arr[i];
			continue;					//跳过当前循环的代码强迫开始下一次循环
		}
		break;							//循环立即终止,程序流将继续执行紧接循环的下一条语句
	}
	return ans;
}
//Time O(n) Space O(1)	

1598. 文件夹操作日志搜集器

题目链接

int minOperations(vector<string>& logs) {
	int depth = 0;
	for (auto & log : logs) {
		if (log == "./") {
			continue;
		} else if (log == "../") {
			if(depth > 0)
				depth--;
		} else {
			depth++;
		}
	}
	return depth;
}				

1614. 括号的最大嵌套深度

题目链接

int maxDepth(string s) {
	int ans = 0, size = 0;
	for (char ch : s) {
		if (ch == '(') {
			++size;
			ans = max(ans,size);
		} else if (ch == ')') {
			--size;
		}
	}
	return ans;
}

1653. 使字符串平衡的最少删除次数

题目链接

int minimumDeletions(string s) {
	int ans = 0;
	stack<char> stk;
	for (char ch : s) {
		if (ch == 'b') {
			stk.push(ch);
		} else {
			if (!stk.empty()) {
				ans++;				//不论是删除前面的 b 还是删除当前的 a, 都增加一次删除操作计数
				stk.pop();
			}
		}	
	}
	return ans;
}		
/* 指针优化 */
// {if ch = b; b++} {if ch = a && b > 0; ans++, b--} 
/* 动态规划 */
int minimumDeletions(string s) {
	int b = 0;
	vector<int> dp(n + 1, 0);
	for (char ch : s) {
		if (ch == 'b') {				//字符为 b,只要前 [0, i -1] 是平衡的 [0, i] 就是平衡的,故状态保持
			dp[i + 1] = dp[i];
			b++;
		} else {						//字符为 a,要么删除前面多余的 b, 要么删除这个 
			dp[i + 1] = min(dp[i] + 1, b);
		}
	}
	return dp[n];
}		
/* 滚动数组优化 */
// int ans = 0; ans = min(ans + 1, b);

1673. 找出最具竞争力的子序列

题目链接

/* 单调栈 + 贪心*/
//类似 leetcode.402
vector<int> mostCompetitive(vector<int> &nums, int k) {
	vector<int> stk;
	int cnt = nums.size() - k;    				//待删除的个数
	for (int & digit : nums) {
		while (!stk.empty() && stk.top() > digit && cnt) {
			stk.pop_back();
			cnt--;
		}
		stk.push_back(digit);
	}											//维护一个单调递增的栈
	for (; cnt > 0; cnt--) {
		stk.pop_back();							
	}											//栈内元素过多,从尾部开始弹
	return stk;
}

1700. 无法吃午餐的学生数量

题目链接

int countStudents(vector<int>& students, vector<int>& sandwiches) {
	int dp[2];
	int cnt = students.size();
	for (int i = 0; i < students.size(); i++) {
		dp[students[i]]++;
	}
	for (int i = 0; i < sandwiches.size(); i++) {
		if (dp[sandwiches[i]] > 0) {
			dp[sandwiches[i]]--;
			cnt--;
		} else 
			break;
	}
	return cnt;
}

1717. 删除子字符串的最大得分

题目链接

/* 贪心 */
//优先处理得分高的字符串,然后处理栈中剩余的低分子串
int maximumGain(string s, int x, int y) {			//ab 得 x 分, ba 得 y 分
 	stack<char> ba, ab;
 	int ret = 0;
 	if (x > y) {									//预处理,统一默认 ba 得 y 为高分
 		swap(x, y);
 		reverse(s.begin(), s.end());
 	}

	for (char c : s) {								//ba 高分
		if (c != 'a') {								//栈中弹出顺序实际为 ba 故先判断 a								
			ba.push(c);
		} else {									//新扫描到的字符为 a			
			if (!ba.empty() && ba.top() == 'b') {
				ba.pop();							//组成 ba
				ret += y;
			} else {
				ba.push(c);
			}
		}
	}
	while (!ba.empty()) {							//处理 ab
		char c = ba.top();
		if (c != 'a') {
			ab.push(c);
		} else {
			if (!ab.empty() && ab.top() == 'b') {
				ab.pop();
				ret += x;
			} else {
			 	ab.push(c);
			}
		}
		ba.pop();
	}
	return ret;
}				

1776. 车队 II

题目链接

vector<double> getCollisionTime(vector<vector<int>>& cars) {
	vector<double> ans(cars.size());
	stack<int> st;  						//单调增栈,栈顶序号代表的车的车速最快,栈底最慢
	for (int i = cars.size() - 1; i >= 0; i--) {
		while (!st.empty()) {
			if (cars[st.top()][1] >= cars[i][1]) {
				st.pop();					//栈顶车速太快了永远追不上,弹掉
			} else {						
				if (ans[st.top()] < 0) break;						//如果栈顶不会消失,则跳出循环执行计算相遇时间
				double dist = ans[st.top()] * (cars[i][1] - cars[st.top()][1];				//如果会消失,计算消失前能否追上
				if (dist > cars[st.top()][0] - cars[i][0]) break;							//若能,则跳出循环执行计算相遇时间
				else st.pop();																//若不能,则弹出
		}
		if (st.empty()) {
			ans[i] = -1;
		} else {
			//相遇时间点 = 相对距离 / 相对速度
			double time = double(cars[st.top()][0] - cars[i][0]) / double(cars[i][1] - cars[st.top()][1]);
			ans[i] = time;
		} 	

1793. 好子数组的最大分数

题目链接

/* 单调栈 */
//类似 84. 柱状图最大矩形面积
int maximumScore(vector<int>& nums, int k) {
	int n = nums.size();
	vector<int> left(n), right(n);
	
	//当前数字左侧最近的第一个比该数字较小元素
	stack<int> st;
	for (int i = 0; i < n; i++) {
		while (!st.empty() && nums[st.top()] >= nums[i])
			st.pop();
		left[i] = st.empty() ? -1 : st.top();
		st.push(i);
	}
	
	//当前数字右侧最近的第一个比该数字较小元素
	st = stack<int> ();
	for (int i = n - 1; i >= 0; i--) {
		while (!st.empty() && nums[st.top()] >= nums[i])
			st.pop();
		right[i] = st.empty() ? n : st.top();
		st.push(i);
	}  
	
	int ans = 0;
	for (int i = 0; i < n; i++) {
		if (left[i] < k && right[i] > k) 
			ans = max(ans, (right[i] - left[i] - 1) * nums[i]);
	}
	return ans;
}	 

你可能感兴趣的:(leetcode,leetcode,算法)