一般很多的if语句判断可以用while循环来代替
这样能使得代码更规范些,不然那么多的if语句太丑了,会多出来很多的大括号,看得人很不爽
例如:
while (!stack.isEmpty() && height[stack.peek()] < height[i]) {
}
这个语句是先判断栈不是空的,然后在栈不是空的情况下再判断后面那个条件。如果是用if语句,那就要写两个if语句了,这样写的太丑了,多出来那么多的大括号,看得人很不舒服。。。。而且这里只需要判断多个条件中的一种情况,不需要把每种情况都考虑进去,因此,写if语句就不需要了
和计算、表达式相关的问题,一般都会使用栈来解决
栈在用pop()这个API的时候,一定要看栈是否为空
下面的这行代码写的很6,值得学习
if(stack.isEmpty()||c!=stack.pop())return false;
数组作为哈希表时
一般是把字符数组的值作为数组的索引,字符数组中字符的索引作为数组的值,这样得到的数组,数组中的值就是字符数组中这个字符出现的最后的索引,也就是把字符数组和自己定义的数组,把各自的索引和值交替赋值。这种数组哈希的方法也是个固定套路,值得记一下
char[] charArray = s.toCharArray();
// 记录每个字符出现的最后一个位置
int[] lastIndex = new int[26];
// 数组哈希表
for (int i = 0; i < len; i++) {
// 把字符数组中元素的值作为lastIndex的索引
// 把字符数组中元素的索引作为lastIndex的值
// 也就是把字符数组和自己定义的数组,把各自的索引和值交替赋值
lastIndex[charArray[i] - 'a'] = i;
}
单调栈
保证入栈的时候,每次都是元素递增或者递减的顺序往栈里面push,如果push的时候不单调了,那么就要弹出栈顶的元素了,然后就要相应的操作了
记得,在入栈的时候,到底是递增入栈还是递减入栈,你只需要举个例子就行了,如果是递增入栈,然后碰到一个比栈顶元素小的元素,这时肯定就不能入栈了,这时你判断一下,看看能不能处理一下代码,如果不能,那么你肯定就不能递增的入栈了
// 需要循环遍历
// 可以先将长度变为2倍,到时候遍历的时候
// 如果i超过了数组长度n,就可以将i取余,就可以了,就又是从头到尾了
// 这种做法实在是太妙了,佩服佩服佩服!!!
for (int i = 0; i < n*2; i++){
// 将数组取余,就是保证i超过长度之后,又是从头开始遍历
int num = nums[i % n];
while(!stack.isEmpty() && num > nums[stack.peek()]){
res[stack.pop()] = num;
}
if(i < n) stack.push(i);
}
return res;
单调栈是怎么用得出神入化的
public int findUnsortedSubarray(int[] nums) {
Stack<Integer> stack = new Stack<Integer>();
int l = nums.length, r = 0;
for (int i = 0; i < nums.length; i++) {
while (!stack.isEmpty() && nums[stack.peek()] > nums[i])
l = Math.min(l, stack.pop());
stack.push(i);
}
stack.clear();
for (int i = nums.length - 1; i >= 0; i--) {
while (!stack.isEmpty() && nums[stack.peek()] < nums[i])
r = Math.max(r, stack.pop());
stack.push(i);
}
return r - l > 0 ? r - l + 1 : 0;
}
两次用到单调栈,分别找出无序数组的左边界与右边界,是不是很6,这个单调栈用的实在是太妙了,妙到毫巅…
这个方法背后的想法仍然是选择排序。我们需要找到无序子数组中最小元素和最大元素分别对应的正确位置,来求得我们想要的无序子数组的边界。
为了达到这一目的,此方法中,我们使用 栈 。我们从头遍历 nums数组,如果遇到的数字大小一直是升序的,我们就不断把对应的下标压入栈中,这么做的目的是因为这些元素在目前都是处于正确的位置上。一旦我们遇到前面的数比后面的数大,也就是 nums[j] 比栈顶元素小,我们可以知道 nums[j]一定不在正确的位置上。
为了找到 nums[j] 的正确位置,我们要不断将栈顶元素弹出,直到栈顶元素比 nums[j] 小,我们假设栈顶元素对应的下标为 k,那么我们知道 nums[j] 的正确位置下标应该是 k + 1。
我们重复这一过程并遍历完整个数组,这样我们可以找到最小的 k, 它也是无序子数组的左边界。
类似的,我们逆序遍历一遍 nums数组来找到无序子数组的右边界。这一次我们将降序的元素压入栈中,如果遇到一个升序的元素,我们像上面所述的方法一样不断将栈顶元素弹出,直到找到一个更大的元素,以此找到无序子数组的右边界。
我们可以看下图作为参考。我们观察到上升还是下降决定了相对顺序,我们还可以观察到指针 b 在下标 0 后面标记着无序子数组的左边界,指针 a 在下标 7 前面标记着无序子数组的右边界。