栈
单调栈就是指栈中的元素必须是按照升序排列的栈,或者是降序排列的栈。升序排列的栈称为递增栈,降序排列的栈称为递减栈.
合法字符串
-
字符串中只有字符'('和')'。合法字符串需要括号可以配对。
比如:输入:"()" 输出:true
解释:(),()(),(())是合法的。)(,()(,(()是非法的。
boolean isValid(String s);
/**
* 字符串中只有字符'('和')'。合法字符串需要括号可以配对。比如:输入:"()" 输出:true
* 解释:(),()(),(())是合法的。)(,()(,(()是非法的。
* 时间复杂度 O(n) 空间复杂度 O(n)
*/
private static boolean isValid(String s) {
if (null == s || s.length() == 0 || s.length() % 2 != 0) {
return false;
}
Stack<Character> stack = new Stack<Character>();
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (stack.isEmpty()) {
stack.push(chars[i]);
continue;
}
if ('(' == stack.peek() && ')' == chars[i]) {
stack.pop();
} else {
stack.push(chars[i]);
}
}
return stack.isEmpty();
}
优化: 进栈的数据都是 (, 栈中元素都相同时,实际上没有必要使用栈,只需要记录栈中元素个数。
/**
* 时间复杂度O(N) 空间复杂度O(1)
*/
private static boolean isValid1(String s) {
if (null == s || s.length() == 0 || s.length() % 2 != 0) {
return false;
}
char[] chars = s.toCharArray();
int num = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == '(') {
num++;
} else {
if (num <= 0) {
return false;
}
num--;
}
}
return num == 0;
}
变种: 给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。有效字符串需满足:
- 左括号必须用相同类型的右括号闭合
- 左括号必须以正确的顺序闭合
- 注意空字符串可被认为是有效字符串
private static boolean isValidC(String s) {
if (null == s || s.length() == 0 || s.length() % 2 != 0) {
return false;
}
Stack<Character> stack = new Stack<Character>();
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (' ' == chars[i]) {
return false;
}
if ('(' == chars[i] || '{' == chars[i] || '[' == chars[i]) {
stack.push(chars[i]);
continue;
}
if (stack.isEmpty()) {
return false;
}
if (')' == chars[i]) {
if ('(' == stack.peek()) {
stack.pop();
} else {
return false;
}
}
if ('}' == chars[i]) {
if ('{' == stack.peek()) {
stack.pop();
} else {
return false;
}
}
if (']' == chars[i]) {
if ('[' == stack.peek()) {
stack.pop();
} else {
return false;
}
}
}
return stack.isEmpty();
}
-
在水中有许多鱼,可以认为这些鱼停放在 x 轴上。再给定两个数组 Size,Dir,Size[i] 表示第 i 条鱼的大小,Dir[i] 表示鱼的方向 (0 表示向左游,1 表示向右游)。这两个数组分别表示鱼的大小和游动的方向,并且两个数组的长度相等。鱼的行为符合以下几个条件:
- 所有的鱼都同时开始游动,每次按照鱼的方向,都游动一个单位距离;
- 当方向相对时,大鱼会吃掉小鱼;
- 鱼的大小都不一样。
输入:Size = [4, 2, 5, 3, 1], Dir = [1, 1, 0, 0, 0]
输出:3
int solution(int[] size, int[] dir)
/**
* 时间复杂度 O(n) 空间复杂度O(N)
*/
private static int solution(int[] size, int[] dir) {
if (size.length <= 1 || dir.length <= 1 || size.length != dir.length) {
return size.length;
}
Stack<Integer> stack = new Stack<Integer>();
for (int i = 0; i < size.length; i++) {
boolean hasEat = false;
while (!stack.isEmpty() && dir[stack.peek()] == 1 && dir[i] == 0) {
if (size[stack.peek()] > size[i]) {
hasEat = false;
break;
}
stack.pop();
}
if (!hasEat) {
stack.push(i);
}
}
return stack.size();
}
-
一个整数数组 A,找到每个元素:右边第一个比我小的下标位置,没有则用 -1 表示。
输入:[5, 2]
输出:[1, -1]
int[] findRightSmall(int[] arr)
/**
* 思路 一个数总是想与左边比它大的数进行匹配,匹配到了之后,小的数会消除掉大的数。
*
* 时间复杂度 O(N) 空间福再度 O(N)
* 数组中右边第一个比我小的元素的位置,求解用递增栈。
*
*/
private static int[] findRightSmall(int[] arr) {
int[] resultArr = new int[arr.length];
Stack<Integer> stack = new Stack<Integer>();
for (int i = 0; i < arr.length; i++) {
while(!stack.isEmpty() && arr[stack.peek()] > arr[i]){
resultArr[stack.pop()] = i;
}
stack.push(i);
}
while(!stack.isEmpty()){
resultArr[stack.pop()] =-1;
}
return resultArr;
}
-
给定一个正整数数组和 k,要求依次取出 k 个数,输出其中数组的一个子序列,需要满足:1. 长度为 k;2.字典序最小。
输入:nums = [3,5,2,6], k = 2
输出:[2,6]
private static int[] findSmallSeq(int[] arr, int k){
int[] result = new int[k];
Stack<Integer> stack = new Stack<Integer>();
for(int i=0; i<arr.length; i++){
int leftNum = arr.length - i;
while( !stack.empty() && stack.size()+ leftNum > k && stack.peek()> arr[i]){
stack.pop();
}
stack.push(arr[i]);
}
while(stack.size() > k){
stack.pop();
}
for(int i=k-1; i>=0; i--){
result[i] = stack.peek();
stack.pop();
}
return result;
}
-
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。
输入: [2,1,5,6,2,3]
输出: 10
/**
* 需要找到左边第一个比A[i]小的数, leftPos, 也需要找到右边第一个比A[i]小的数。rightPos
*/
private static int largestRectangleArea1(int[] arr){
int[] leftSmall = findLeftSmall(arr);
int[] rightSmall = findRightSmall(arr);
int result =0;
for (int i = 0; i < arr.length; i++) {
int leftPos = leftSmall[i];
int rightPos = rightSmall[i] == -1 ? arr.length: rightSmall[i];
int width = rightPos - leftPos -1;
result = Math.max(result, width * arr[i]);
}
return result;
}
/**
* 查询左边小于的数
*/
private static int[] findLeftSmall(int [] arr){
int[] resultArr = new int[arr.length];
Stack<Integer> stack = new Stack<Integer>();
for (int i = arr.length-1; i > 0; i--) {
while(!stack.isEmpty() && arr[stack.peek()] > arr[i]){
resultArr[stack.pop()] = i;
}
stack.push(i);
}
while(!stack.isEmpty()){
resultArr[stack.pop()] =-1;
}
return resultArr;
}
/**
* 查询右边小于的数
*/
private static int[] findRightSmall(int[] arr) {
int[] resultArr = new int[arr.length];
Stack<Integer> stack = new Stack<Integer>();
for (int i = 0; i < arr.length; i++) {
while(!stack.isEmpty() && arr[stack.peek()] > arr[i]){
resultArr[stack.pop()] = i;
}
stack.push(i);
}
while(!stack.isEmpty()){
resultArr[stack.pop()] =-1;
}
return resultArr;
}
public int largestRectangleArea(int[] A) {
final int N = A == null ? 0 : A.length;
int top = 0;
int[] s = new int[N];
int ans = 0;
for (int i = 0; i <= N; i++) {
final int x = i == N ? -1 : A[i];
while (top > 0 && A[s[top - 1]] > x) {
final int height = A[s[--top]];
final int rightPos = i;
final int leftPos = top > 0 ? s[top - 1] : -1;
final int width = rightPos - leftPos - 1;
final int area = height * width;
ans = Math.max(ans, area);
}
s[top++] = i;
}
return ans;
}