20. Valid Parentheses 有效的配对
https://leetcode.com/problems/valid-parentheses/
题目:如果一个字符串只包含‘(’,‘)、’{‘、’}‘、’[‘和’]‘,则确定输入字符串是否有效。打开括号必须由相同类型的括号关闭,则输入字符串是有效的。开括号必须按照正确的顺序关闭。注意,空字符串也被认为是有效的。
思路:新建一个栈,遍历输入字符串,如果当前字符为左半边括号,则将其压入栈中;如果当前字符为右半边括号且栈为空,则直接返回false;如果当前字符为右半边括号且栈不为空,则取出栈顶元素,若为对应的左半边括号,则继续循环,反之返回false。
32. Longest Valid Parentheses 最长有效配对
https://leetcode.com/problems/longest-valid-parentheses/
题目:给定一个只包含字符‘(’和‘)’的字符串,查找最长的有效(格式良好)括号子字符串的长度。
思路:
①使用Stack栈
②DP动态规划
class Solution { public int longestValidParentheses(String s) { // using Stack Stack<Integer> st = new Stack<>(); int result = 0; st.push(-1); for(int i = 0; i < s.length(); i++) { if(s.charAt(i) == ')' && st.size() > 1 && s.charAt(st.peek()) == '(') { st.pop(); result = Math.max(result, i - st.peek()); } else { st.push(i); } } return result; } }
class Solution { public int longestValidParentheses(String s) { // using DP int[] dp = new int[s.length()]; int result = 0, leftCount = 0; for(int i = 0; i < s.length(); i++) { if(s.charAt(i) == '(') { leftCount++; } else if(leftCount > 0) { dp[i] = dp[i - 1] + 2; dp[i] += (i - dp[i]) > 0 ? dp[i - dp[i]] : 0; result = Math.max(result, dp[i]); leftCount--; } } return result; } }
单调栈:单调栈分为单调递增栈和单调递减栈,单调递增栈即栈内元素保持单调递增的栈,同理单调递减栈即栈内元素保持单调递减的栈。
范式:
单调递增栈
for(int i = 0; i < T.size(); i++){ while(! stk.empty() && stk.top() > T[i]){ stk.pop(); } stk.push(A[i]); }
单调递减栈
for(int i = T.size() - 1; i >= 0; i--){ while(! stk.empty() && T[i] >= stk.top()){ stk.pop(); } stk.push(i); }
单调栈的作用:
可以以 O(1) 的时间复杂度得知某个位置左右两侧比他大(或小)的数的位置,当你需要高效率获取某个位置左右两侧比他大(或小)的数的位置的的时候就可以用到单调栈。
求解数组中元素右边第一个比它小的元素的下标,从前往后,构造单调递增栈;求解数组中元素左边第一个比它大的元素的下标,从后往前,构造单调递增栈。
求解数组中元素右边第一个比它大的元素的下标,从前往后,构造单调递减栈;求解数组中元素左边第一个比它小的元素的下标,从后往前,构造单调递减栈。
42. Trapping Rain Water 装雨水
https://leetcode.com/problems/trapping-rain-water/
题目:如果n个非负整数表示一个标高图,其中每个杆的宽度为1,则计算雨后它能装多少水。
思路:使用单调递减栈,存入递减的边界,当遍历到大于栈顶元素的数字时,就可能产生可以装水的地方。当可能产生能装水的地方时,我们先弹出栈顶,即当前最低点,然后再次弹出栈顶,即左边界,右边界为当前遍历到的数字;比较左右边界,取较小值为水的边界;然后此较小值减去最低点,乘以左右边界间的距离就是此处的装水量了。栈中存放的是坐标。
class Solution { public int trap(int[] height) { if(height.length < 2) return 0; Stack<Integer> stack = new Stack<Integer>(); int res = 0, i = 0; while(i < height.length) { if(stack.empty() || height[i] < height[stack.peek()]) { stack.push(i++); } else { int t = stack.pop(); // 记录最小值 if(stack.empty()) continue; // 边界中的较小值减去最小值 * 两个边界之间的距离 res += (Math.min(height[i], height[stack.peek()]) - height[t])*(i - stack.peek() - 1); } } return res; } }
84. Largest Rectangle in Histogram 直方图中的最大矩形
https://leetcode.com/problems/largest-rectangle-in-histogram/
题目:给定n个非负整数表示直方图的条高,其中每条的宽度为1,则在直方图中找出最大矩形的面积。
思路:使用递增栈,按从高板子到低板子的顺序处理,先处理最高的板子,然后再处理旁边矮一些的板子。当遇到大于栈顶元素的数字时进栈,当遇到小的数字时,取出栈顶元素进行处理。在计算矩形面积时,先取出栈顶元素,即最高的板子,然后就可以计算长度为1的矩形面积了,接着取下一块板子,此时按长度为2来计算矩形面积,以此类推,直到数字大于栈顶元素为止,再次进栈。为了使得最后一块板子也被处理,需要在高度数组最后面加上一个0,这样原先的最后一个板子也可以被处理了。
class Solution { public int largestRectangleArea(int[] heights) { int n = heights.length; if(n == 1) return heights[0]; int[] height = new int[n+1]; for(int i = 0; i < n; i++) { height[i] = heights[i]; } height[n] = 0; Stack<Integer> stack = new Stack<Integer>(); int i = 0, res = 0; while(i < n+1) { if(stack.empty() || height[i] > height[stack.peek()]) { stack.push(i ++); } else { int t = stack.pop(); // 最高点 res = Math.max(res, height[t] * (stack.empty() ? i : i - stack.peek() - 1)); } } return res; } }
149. Max Points on a Line 直线上最大的点
https://leetcode.com/problems/max-points-on-a-line/
题目:给定二维平面上的n个点,求出位于同一直线上最大的点。(暴力方法/细节实现)
思路:
150. Evaluate Reverse Polish Notation 求解逆波兰表示法的式子
https://leetcode.com/problems/evaluate-reverse-polish-notation/
题目:用反向波兰表示法计算算术表达式的值。有效运算符是+,-,*,/。每个操作数可以是一个整数,也可以是另一个表达式。注:两个整数之间的除数应截断为零。给定的RPN表达式始终有效。这意味着表达式将始终计算为一个结果,并且不会被零运算除以任何值。
思路: