/*动态规划*/// dp[i] :以下标 i 字符结尾的最长有效括号的长度。intlongestValidParentheses(string s){int ans =0, n = s.length();
vector<int>dp(n,0);for(int i =1; i < n; i++){//i 从 1 开始计数是因为 i = 0 时无论 '(' 还是 ')' 都有 dp[0] = 0if(s[i]==')'){if(s[i -1]=='(')
dp[i]=(i >=2? dp[i -2]:0)+2;elseif(i - dp[i -1]>0&& s[i - dp[i -1]-1]=='(')
dp[i]= dp[i -1]+((i - dp[i -1])>=2? dp[i - dp[i -1]-2]:0)+2;
ans =max(ans, dp[i]);}return ans;}//Time O(n) Space O(n)
/*栈*/intlongestValidParentheses(string s){int ans =0;
stack<int> stk;//入栈的是字符下标
stk.push(-1);//防止第一个字符为 ')' 而使得 pop() 操作空栈 for(int i =0; i < s.length(); i++){if(s[i]=='(')
stk.push(i);else{
stk.pop();if(stk.empty())
stk.push(i);//多余的 ')' 压入栈中,自此以前字符无法再出栈else
ans =max(ans, i - stk.top());}}return ans;}//Time O(n) Space O(n)
/*不需额外空间,两个计数器*/intlongestValidParentheses(string s){int left =0, right =0, ans =0;for(int i =0; i < s.length(); i++){if(s[i]=='(')
left++;else
right++;if(left = right)
ans =max(ans,2* right);elseif(left < right)
left = right =0;}
left = right =0;for(int i =(int)s.length()-1; i >=0; i--){if(s[i]=='(')
left++;else
right++;if(left == right)
ans =max(ans,2* left);elseif(left > right)
left = right =0;}return ans;}
双指针:由于 i 处能接的雨水量由 leftMax[i] 和 rightMax[i] 中的最小值决定,于是使用双指针和两个变量代替两个数组。
/*动态规划*///正向遍历得到下标 i 及其左侧位置最大高度,反向遍历得到下标 i 及其右侧最大高度。//leftMax[0] = height[0]//rightMax[n-1] = height[n-1]// 1<= i <= n-1, leftMax[i] = max(leftMax[i-1], height[i])// 0<= i <= n-2, rightMax[i] = max(rightMax[i+1], height[i])inttrap(vector<int>&height){int n = height.size();if(n ==0)return0;
vector<int>leftMax(n);
leftMax[0]= height[0];for(int i =1; i < n; i++)
leftMax[i]=max(leftMax[i-1], height[i]);
vector<int>rightMax(n);
rightMax[n -1]= height[n -1];for(int i = n -2; i >=0;--i)
rightMax[i]=max(rightMax[i +1], height[i]);int ans =0;for(int i =0; i < n;++i)
ans +=min(leftMax[i], rightMax[i])- height[i];return ans;}//Time O(n) Space O(n)
/*单调栈*///栈中元素永远保持递减,直到有更高的元素进入后开始弹出inttrap(vector<int>&height){int ans =0, n = height.size();
stack<int> stk;for(int i =0; i < n; i++){while(!stk.empty()&& height[i]> height[stk.top()]){int top = stk.top();
stk.pop();if(stk.empty()break;int left = stk.top();int currWidth = i - left -1;int currHeight =min(height[left], height[i])- height[top];
ans += currWidth * currHeight;}
stk.push(i);}return ans;}//Time O(n) Space O(n)
/*双指针*///双指针相向而行inttrap(vector<int>&height){int ans =0;int left =0, right = height.size()-1;int leftMax =0, rightMax =0;while(left <right){
leftMax =max(leftMax, height[left]);
rightMax =max(rightMax, height[right]);if(height[left]< height[right]){
ans += leftMax - height[left];++left;}else{
ans += rightMax - height[right];--right;}}return ans;}
/*暴力*///枚举宽intlargestRectangleArea(vector<int>&height){int ans =0;for(int left =0; left < height.size(); left++){int minHeight = INT_MAX;for(int right = left; right < height.size(); right++){
minHeight =min(minHeight, height[right]);
ans =max(ans,(right - left +1)* minHeight);}}return ans;}//枚举高,intlargestRectangleArea(vector<int>&height){int ans =0;for(int mid =0; mid < n; mid++){int height = height[mid];int left = mid, right = mid;while(left -1>=0&& height[left -1]>= height)--left;while(right +1< height.size()&& height[right +1]>= height)++right;
ans =max(ans,(right - left +1)* height);}return ans;}
/*单调栈*///如何求出一根柱子左右两侧且最近的小于其高度的柱子//对于两根柱子 j0 和 j1(j0 在 j1 左侧且 j0 高于 j1)那么在后面的柱子 i 向左找小于其高度的柱子时,j1 会‘挡住’ j0, j0 就不会作为答案intlargestRectangleArea(vector<int>&height){int n = height.size();
vector<int>left(n),right(n);
stack<int> mono_stack;for(int i =0; i < n; i++){while(!mono_stack.empty()&& height[mono_stack.top()]>= height[i])//进来一个更低的矩形,开始出栈
mono_stack.pop();
left[i]=(mono_stack.empty()?-1: mono_stack.top());
mono_stack.push(i);}
mono_stack =stack<int>();for(int i = n -1; i >=0; i--){while(!mono_stack.empty()&& height[mono_stack.top()]>= height[i])
mono_stack.pop();
right[i]=(mono_stack.empty()? n : mono_stack.top());
mono_stack.push(i);}int ans =0;for(int i =0; i < n; i++)
ans =max(ans,(right[i]- left[i]-1)* height[i]);return ans;}//Time O(n) Space O(n)
/*单调栈 + 常数优化*///对位置 i 进行入栈操作时确定了它的左边界。对位置 i 进行出栈操作时可以确定它的右边界//遍历结束后栈中剩余的位置对应的右边界就是位置为 n 的哨兵。对此可以一次出栈后更新右边界或初始化时直接置所有元素为 n 。intlargestRectangleArea(vector<int>& height){int n = height.size();
vector<int>left(n),right(n, n);
stack<int> mono_stack;for(int i =0; i < n; i++){while(!mono_stack.empty()&& height[mono_stack.top()]>= height[i]){
right[mono_stack.top()]= i;
mono_stack.pop();}
left[i]=(mono_stack.empty()?-1: mono_stack.top());
mono_stack.push(i);}int ans =0;for(int i =0; i < n; i++)
ans =max(ans,(right[i]- left[i]-1)* height[i]);return ans;}//Time O(n) Space O(n)
/*暴力*///intmaximalRectangle(vector<vector<char>>&matrix){int m = matrix.size(), n = matrix[0].size();if(m ==0)return0;
vector<vector<int>>left(m,vector<int>(n,0));//二维数组记录每个元素左边连续 1 的数量for(int i =0; i < m; i++)for(int j =0; j < n; j++)if(matrix[i][j]=='1')
left[i][j]=(j ==0?0: left[i][j-1])+1;//对于任意一个点枚举以该点为右下角的全 1 矩阵int ret =0;for(int i =0; i < m; i++){for(int j =0; j < n; j++){if(matrix[i][j]=='0')continue;int width = left[i][j];int area = width;//纵向观察该元素列方向上最大矩阵面积,类似Pro84for(int k = i -1; k >=0; k--){
width =min(width, left[k][j]);
area =max(area,(i - k +1)* width);}
ret =max(ret, area);}}return ret;}//Time O(n * m^2) Space O(mn)
/*单调栈*/intmaximalRectangle(vector<vector<char>>&matrix){int m = matrix.size();if(m ==0)return0;int n = matrix[0].size();
vector<vector<int>>left(m,vector<int>(n,0));for(int i =0; i < m; i++)for(int j =0; j < n; j++)if(matrix[i][j]=='1')
left[i][j]=(j ==0?0: lef[i][j-1])+1;//对于每一列,纵向使用基于柱状图的方法int ret =0;for(int j =0; j < n; j++){
vector<int>up(m,0),down(m,0);
stack<int> stk;for(int i =0; i < m; i++){while(!stk.empty()&& left[stk.top()][j]>= left[i][j])
stk.pop();
up[i]= stk.empty()?-1: stk.top();
stk.push(i);}
stk =stack<int>();for(int i = m -1; i >=0; i--){while(!stk.empty()&& left[stk.top()][j]>= left[i][j])
stk.pop();
down[i]= stk.empty()? m : stk.top();
stk.push(i);}for(int i =0; i < m; i++){int height = down[i]- up[i]-1;int area = height * left[i][j];
ret =max(ret, area);}}return ret;}//Time O(mn) Space O(mn)
/*栈*/intcalculate(string s){
vector<int> stk;//向量模拟栈 其内存操作数char preSign ='+';//记录数字前的符号,初始化第一个数之前的符号视为 +int num =0;int n = s.length();for(int i =0; i < n;++i){if(isdigit(s[i]))
num = num *10+int(s[i]-'0');//高位数if(!isdigit(s[i])&& s[i]!=' '|| i == n -1){switch(preSign){//根据 preSign 决定计算方式case'+':
stk.push_back(num);break;case'-':
stk.push_back(-num);break;case'*':
stk.back()*= num;break;case'/':
stk.back()/= num;break;}
preSign = s[i];//记录当下符号作为下一数字的前置符号
num =0;//归零}}returnaccumulate(stk.begin(), stk.end(),0);//求和}
/**
* // This is the interface that allows for creating nested lists.
* // You should not implement it, or speculate about its implementation
* class NestedInteger {
* public:
* // Return true if this NestedInteger holds a single integer, rather than a nested list.
* bool isInteger() const;
*
* // Return the single integer that this NestedInteger holds, if it holds a single integer
* // The result is undefined if this NestedInteger holds a nested list
* int getInteger() const;
*
* // Return the nested list that this NestedInteger holds, if it holds a nested list
* // The result is undefined if this NestedInteger holds a single integer
* const vector<NestedInteger> &getList() const;
* };
*//**
* Your NestedIterator object will be instantiated and called as such:
* NestedIterator i(nestedList);
* while (i.hasNext()) cout << i.next();
*/
/* 深度优先搜索 *///嵌套的整形列表是一个树形结构,树上的叶子结点对应一个整数,非叶结点对应一个列表//在树上深度优先搜索的顺序就是迭代器遍历的顺序classNestedIterator{private:
vector<int> vals;
vector<int>::iterator cur;voiddfs(const vector<NestedInteger>&nestedList){for(auto&nest : nestedList){if(nest.isInteger())
vals.push_back(nest.getInteger());elsedfs(nest.getList());}}public:NestedIterator(vector<NestedInteger>&nestedList){dfs(nestedList);
cur = vals.begin();}//initialize Time O(n)intnext(){return*cur++;}//O(1)boolhasNext(){return cur != vals.end();}//O(1) };
/**
* // This is the interface that allows for creating nested lists.
* // You should not implement it, or speculate about its implementation
* class NestedInteger {
* public:
* // Constructor initializes an empty nested list.
* NestedInteger();
*
* // Constructor initializes a single integer.
* NestedInteger(int value);
*
* // Return true if this NestedInteger holds a single integer, rather than a nested list.
* bool isInteger() const;
*
* // Return the single integer that this NestedInteger holds, if it holds a single integer
* // The result is undefined if this NestedInteger holds a nested list
* int getInteger() const;
*
* // Set this NestedInteger to hold a single integer.
* void setInteger(int value);
*
* // Set this NestedInteger to hold a nested list and adds a nested integer to it.
* void add(const NestedInteger &ni);
*
* // Return the nested list that this NestedInteger holds, if it holds a nested list
* // The result is undefined if this NestedInteger holds a single integer
* const vector<NestedInteger> &getList() const;
* };
*/
/*深度优先搜索*///NestedInteger 是通过递归定义的,因此也可以用递归解析int index =0;
NestedInteger deserialize(string s){if(s[index]=='['){//代表待解析的是一个列表
index++;
NestedInteger ni;while(s[index]!=']'){
ni.add(deserialize(s));//进入下层递归if(s[index]==',')
index++;}
index++;return ni;//返回 NestedInteger 实例}else{bool negative =false;if(s[index]=='-'){
negative =true;
index++;}int num =0;while(index < s.size()&&isdigit(s[index])){
num = num *10+ s[index]-'0';
index++;}if(negative)
num *=1;returnNestedInteger(num);}}//Time O(n) Space O(n)
/*栈*/
NestedInteger deserialize(string s){if(s[0]!='[')returnNestedInteger(stoi(s));
stack<NestedInteger> stk;int num =0;bool negative =false;for(int i =0; i < s.size(); i++){char c = s[i];if(c =='-')
negative =true;elseif(isdigit(c))
num = num *10+ c -'0';elseif(c =='[')
stk.emplace(NestedInteger());//新的 NestedInteger 实例需要入栈elseif(c ==','|| c ==']'){// ',' ']' 表示一个数字或 NestedInteger 实例结束,需要将其加入栈顶的 NestedInteger 实例if(isdigit(s[i -1])){if(negative)
num *=-1;
stk.top().add(NestedInteger(num));}
num =0;
negative =false;//还原标记if(c ==']'&& stk.size()>1){
NestedInteger ni = stk.top();//栈顶保存的是最后一个子 NestedInteger 实例 eg:[456]
stk.pop();//需要弹出该子实例
stk.top().add(ni);//并将此子实例加入其父实例中 eg: [123,[456]]}}}return stk.top();}//Time O(n) Space O(n)
/*栈操作*/
string getDigits(string &s, size_t &ptr){
string ret ="";while(isdigit(s[ptr]))
ret.push_back(s[ptr++]);return ret;}
string getString(vector<string>&v){
string ret;for(constauto&s : v)
ret += s;return ret;}
string decodeString(string s){
vector<string> stk;
size_t ptr =0;while(ptr < s.size()){char cur = s[ptr];if(isdigit(cur)){
string digits =getDigits(s, ptr);//解析出多个数位
stk.push_back(digits);//并入栈}elseif(isalpha(cur)|| cur =='['){
stk.push_back(string(1, s[ptr++]));//当前字符为字母或左括号直接入栈}else{++ptr;
vector<string> sub;//准备承接子串while(stk.back()!="["){//当前字符为右括号
sub.push_back(stk.back());//压入sub子串栈
stk.pop_back();//stk弹栈}reverse(sub.begin(), sub.end());//翻转出栈顺序
stk.pop_back();//左括号出栈int repTime =stoi(stk.back());//此时栈顶为个数
stk.pop_back();
string t, o =getStirng(sub);while(repTime--) t += o;//拼接构造字符串
stk.push_back(t);//构造好的字符串重新入栈}}returngetString(stk);}//Time O(S) Space O(S) S for decoded strlen
/*递归*/classSolution{public:
string src;
size_t ptr;intgetDigits(){int ret =0;while(ptr < src.size()&&isdigit(src[ptr])){
ret = ret *10+ src[ptr++]-'0';return ret;}
string getString(){if(ptr == src.size()|| src[ptr]==']'){return"";//空串或右括号则返回上层char cur = src[ptr];int repTime =1;if(isdigit(cur)){
repTime =getDigits();//解析 digit++ptr;//过滤左括号
string str =getString();//解析 string++ptr;//过滤右括号while(repTime--) ret += str;//构造字符串}elseif(isalpha(cur)){
ret =string(1, src[ptr++]);//解析 char}return ret +getString();}
string decodeString(string s) P
src = s;
ptr =0;returngetString();}};//Time O(S) Space O(s) S for decoded strlen, s for original strlen
/*暴力*/
vector<int>nextGreaterElement(vector<int>&nums1, vector<int>&nums2){int m = nums1.size(), n = nums2.size();
vector<int>res(m);for(int i =0; i < m; i++){int j =0;while(j < n && nums2[j]!= nums1[i])
j++;int k = j +1;while(k < n && nums2[k]< nums2[j])
k++;
res[i]= k < n ? nums2[k]:-1;}return res;}//Time O(mn) Space O(1)
/* 单调栈 + 哈希表 */
vector<int>nextGreaterElement(vector<int>&nums1, vector<int>&nums2){
unordered_map<int,int> hashmap;
stack<int> stk;//栈底到栈顶元素递减for(int i = nums2.size()-1; i >=0;--i){//倒序遍历int num = nums2[i];while(!stk.empty()&& num >= stk.top())//大数新进则弹栈
stk.pop();
hashmap[num]= stk.empty()?-1: stk.top();
stk.push(num);}
vector<int>res(nums1.size());for(int i =0; i < nums1.size(); i++)
res[i]= hashmap[nums1[i]];return res;}
/* 排序 */intfindUnsortedSubarray(vector<int>&nums){if(is_sorted(nums.begin(), nums.end()))return0;
vector<int>numsSorted(nums);//复制sort(numsSorted.begin(), numsSorted.end());int left =0, right = nums.size()-1;while(nums[left]== numsSorted[left]){
left++;while(nums[right]== numsSorted[right])
right--;return right - left +1;}//Time O(nlogn) Space O(n)
/* 一次遍历 *///左段中段右段,找到中段的左右边界intfindUnsortedSubarray(vector<int>&nums){int n = nums.size();int minn = INT_MAX, maxn = INT_MIN;int begin =-1, end =-1;for(int i =0; i < n; i++){if(nums[i]>= maxn)
maxn = nums[i];else
end = i;//中段右侧边界if(nums[n - i -1]<= minn)
minn = nums[n - i -1];else
begin = n - i -1;//中段左边界}return end ==-1?0: end - begin +1;//end = -1 原本有序情况 }
/* 暴力 */intmaxChunksToSorted(vector<int>& arr){int ans =0, max =0;for(int i =0; i < arr.size(); i++){
max =fmax(max, arr[i]);if(max == i) ans++;}return ans;}
/* 栈 */intscoreOfParentheses(string s){
stack<int> st;
st.push(0);for(char c : s){if(c =='(')
st.push(0);//当前深度增加else{int v = st.top();//当前深度得分
st.pop();int w = st.top();
st.pop();
st.push(w +fmax(2* v,1));}}return st.top();}//Time O(n) Space O(n)
/* 统计核心数目 */intscoreOfParentheses(string s){int ans =0, bal =0;for(int i =0; i < s.size(); i++){if(s[i]=='(')
bal++;else{
bal--;if(s[i -1]=='(')//只有()会对字符串 s 贡献实质的分数
ans +=1<< bal;}}return ans;}//Time O(n) Space O(1)