說明
- 輸入n個無序整數
輸出 每個數之後第一個比他大的數,要求時間o(n)
示例:
1,-1,2,3
輸出:
2 2 3
解決思路:棧+棧底指針
邏輯:
棧中存儲元素位置索引
int bottom=0;// 初始化棧底索引
分析:
注意時間複雜度是o(n) 說明是只需要遍歷一次,如果沒這個限制,會自然而然想到兩層循環遍歷
解決方式:棧+棧底指針
輸入:input[]
輸入第i個元素
- 棧爲空,i=入棧, bottom =i
- 輸入>棧底元素,那麼棧中需要全部出棧(始終保持棧底是最大元素),執行1
- 輸入<=棧底元素,不能直接入棧,(因爲可能棧頂元素比較小,那麼新元素就是棧頂元素的後面的第一個比他大的元素)
3.1 輸入<= 棧頂元素 ,直接入棧
3.2 輸入> 棧頂元素,出棧,再入棧 (3.1,3.2 保證元素從棧底->棧頂保持非減順序)(入棧前注意是否需要更新bottom指針) - 輸入遍歷完,棧中還剩餘的元素則是不能找見之後比他大的元素
java代碼實現:
將輸出的序列放在了新的數組之中(也可以修改原數組)
/**
* @author wangwei
* @date 2019/3/7 14:03
* @classDescription 輸入是一個無無序數組
* 輸出:每個元素的之後一個第一個比自己大的元素
* 要求o(n) 的時間複雜度
*/
public class FindFirstBiggerAfterSelf {
public int [] solution(int[] input) {
if(null==input||0==input.length){
return null ;
}
Stack<Integer> stack = new Stack<>();
int bottom = 0; // 初始化棧底指針
int [] result=new int[input.length];// 記錄搜索結果
for (int i = 0; i < input.length; i++) {
//1. 棧空
if (stack.isEmpty()) {
bottom = i;
stack.push(i);
continue;
}
// 棧底是棧中最大元素
// 假設棧中是 3 1
// 輸入是 2 3>2 入棧 ,但是2大於棧頂的1 ,也就是說 2 是1 後面第一個比他大的數
// 這是應該將1彈出,2壓入
// 棧: 3 2
// 輸入 4 3<4 彈棧(清空棧) 4入棧
// 棧: 4
//2. 棧底元素大於等於輸入
if (input[bottom] >= input[i]) {
// 需要判斷棧頂是否也是比新元素大
// 棧頂較小,說明新元素是棧頂元素的後面的第一個比他大的元素
if (input[stack.peek()] < input[i]) {
result[stack.pop()] = input[i];
}
// 這裏保證了 棧中元素是: 棧底->棧頂 是由大到小的順序
if (stack.isEmpty()) {
bottom = i;// 更新棧底指針
}
stack.push(i);
continue;
}
//3. 輸入元素大於棧底,那麼全部彈棧
while (!stack.isEmpty()) {
result[stack.pop()] = input[i];
}
bottom = i;
stack.push(i);
}
// 4 .處理沒找到之後的比他大的位置,此時索引應該還在棧中
while (!stack.isEmpty()){
result[stack.pop()]=Integer.MIN_VALUE;
}
return result;
}
public static void main(String[] args) {
int[] input = RandomUtil.randomInts(1, 20, 10);
RandomUtil.printArray(input);
System.out.println("------------------------");
int [] result=new FindFirstBiggerAfterSelf().solution(input);
RandomUtil.printArray(result);
}
}
測試:第一行是輸入,分割線後是輸出