一、單調棧定義
- 單調遞增棧:數據出棧的序列爲單調遞增序列(比站內元素小就入棧,否則將棧中比當前元素小的元素彈出後再入棧)
- 單調遞減棧:數據出棧的序列爲單調遞減序列(比站內元素大就入棧,否則將棧中比當前元素大的元素彈出後再入棧)
二、題目
(一)視野總和
【題目】
描敘:有 n 個人站隊,所有的人全部向右看,個子高的可以看到個子低的髮型,給出每個人的身高,問所有人能看到其他人發現總和是多少。
輸入:4 3 7 1
輸出:2
輸入:20,10,5,7,15,8,6
輸出:11
思路:每次入棧的時候,即棧頂元素大於入棧元素的時候,sum加上當前棧內元素個數。
/**
* 視野總和
*描敘:有 n 個人站隊,所有的人全部向右看,個子高的可以看到個子低的髮型,
* 給出每個人的身高,問所有人能看到其他人發現總和是多少。
*
* 輸入:4 3 7 1
* 輸出:2
*
* 每次入棧的時候,即棧頂元素大於入棧元素的時候,總和加上當前棧內元素個數
* */
public int sightSum(int[] nums) {
if (nums == null || nums.length==0) return 0;
Stack<Integer> stack = new Stack<>();
int i,sum;
sum = 0;
for (i=0; i<nums.length; i++) {
// 棧爲空的時候,sum不變,只是加入元素
if (stack.empty()) {
stack.add(nums[i]);
} else {
// 棧不爲空,同時棧頂小於入棧元素
while (!stack.empty() && stack.peek()<nums[i]) {
stack.pop();
}
sum += stack.size();
stack.add(nums[i]);
}
}
return sum;
}
public static void main(String[] args) {
int[] a = {20,10,5,7,15,8,6};
System.out.println(new MonotonousStack().sightSum(a));
}
(二)下一個更大元素
【題目】
給定兩個沒有重複元素的數組 nums1 和 nums2 ,其中 nums1 是 nums2 的子集。找到 nums1 中每個元素在 nums2 中的下一個比其大的值。
nums1 中數字 x 的下一個更大元素是指 x 在 nums2 中對應位置的右邊的第一個比 x 大的元素。如果不存在,對應位置輸出 - 1。
【代碼】
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
if (nums1.length == 0 || nums2.length == 0)
return new int[0];
Stack<Integer> stack = new Stack<>();
HashMap<Integer,Integer> map = new HashMap<>();
int i;
stack.add(nums2[0]);
for (i=0; i<nums2.length; i++) {
if (stack.peek()<nums2[i]) {
while (!stack.empty() && stack.peek()<nums2[i]) {
map.put(stack.peek(),nums2[i]);
stack.pop();
}
}
stack.add(nums2[i]);
}
int[] res = new int[nums1.length];
for (i=0; i<nums1.length; i++) {
if (map.containsKey(nums1[i])) {
res[i] = map.get(nums1[i]);
} else {
res[i] = -1;
}
}
return res;
}
【思路】
我們可以忽略數組 nums1,先對將 nums2 中的每一個元素,求出其下一個更大的元素。隨後對於將這些答案放入哈希映射(HashMap)中,再遍歷數組 nums1,並直接找出答案。對於 nums2,我們可以使用單調棧來解決這個問題。