1. 程式人生 > >面試題:支援O(1)時間內完成pop,push和max的棧

面試題:支援O(1)時間內完成pop,push和max的棧

一個支援O(1)時間內完成pop,push和max的棧

這是一個面試題,跟同事交流得到的。解法十分巧妙,值得學習。更詳細的可以參看::imap部落格

問題描述

要求設計一個棧,支援pop,push和max三種操作,每種操作都是O(1)時間的。

問題分析

一般的棧,本身的pop和push的操作就是O(1)的,可以考慮使用一個變數來儲存最大值。問題在於,如果這個最大值被pop出去,這個變數就需要重新計算。如果通過遍歷一遍來求出,則需要O(n)的時間,達不到要求。此外,任何想通過一個排好序的序列來解決最大值的pop問題的方案,都有一個致命缺點,就是每次push的時候,需要進行插入。

實現一:藉助第二個棧

這個方案是基於這樣一個事實:如果push的元素小於最大值,則當前棧的最大值不會發生變化。舉個例子:

輸入序列為2,1,0,5,4,3,6

當push和pop1和0時,棧的最大值不變,為2。但當進一步輸入5,由於5大於2,則5就是當前棧的最大值。繼續push進來或者pop出去4和3,5都是最大值。當5被pop出去的時候,2又變成最大值了。所以只要用一個棧來儲存2和5就行了。每當push一個數,如果大於最大值棧的棧頂元素,則同時加入最大值棧。每當pop一個數時,如果跟最大值相等,就同樣彈出。

程式碼如下:

package com.twabs.prac;

public class NStack1 {
	private int[] stack = new int[100];
	private int[] maxs = new int[100];
	private int top = 0;
	private int mtop = 0;
	
	public void push(int el) {
		if (el >= maxs[mtop]) {
			maxs[++mtop] = el;
		}
		
		stack[++top] = el;
	}
	
	public int pop() {
		if (top <= 0) return -1;
		
		if (stack[top] == maxs[mtop]) {
			mtop--;
		}
		
		return stack[top--];
	}
	
	public int max() {
		return maxs[mtop];
	}
}

實現二:使用一個變數

使用第二個棧的主要原因在於我們需要在pop出最大值的時候,將第二大的值變成新的最大值。進一步考慮實現一的基礎事實,新push的元素小於當前最大值,則最大值不變;否則最大值發生變化。在pop出元素的時候,這條事實也是成立的。關鍵在於最大值發生變化的時候,如何恢復次最大值?大小關係可以通過差值來進行儲存,只要在pop和push的時候計算就行。

那差值能否幫助我們恢復次最大值呢?答案是肯定的。假設現在棧裡面有n-1個元素,第n個元素進來時,我們再棧裡面存貯的是(Sn - MAX(Sn-1,Sn-2,...,S1))。如果是正的,表明新的元素是新的最大值。這樣在pop的時候,如果棧頂是正的,那麼用當前最大值減去棧頂元素就可以得到新的最大值!如果是負數,則最大值不變。

這個想法的確很天才,可以將實現的空間複雜度降低到常熟級別。

程式碼如下:

package com.twabs.prac;

public class NStack2 {
	private int[] stack = new int[100];
	private int top = 0;
	private int max = 0;
	
	public void push(int el) {
		stack[++top] = el - max;
		
		if (el > max) {
			max = el;
		}
	}
	
	public int pop() {
		int t = stack[top] + max;
		
		if (stack[top] > 0) {
			t = max;
			max -= stack[top--];
		} else {
			top--;
		}
		
		return t;
	}
	
	public int max() {
		return max;
	}
}

基本操作的威力

這個問題也生動的展示了,為了在資料結構中支援一種基本操作,資料結構本身所進行的改變和調整,同時這種改變和調整極大提高了基本操作的演算法效率。

相關推薦

試題支援O(1)時間完成pop,pushmax

一個支援O(1)時間內完成pop,push和max的棧 這是一個面試題,跟同事交流得到的。解法十分巧妙,值得學習。更詳細的可以參看::imap部落格 問題描述 要求設計一個棧,支援pop,push和max三種操作,每種操作都是O(1)時間的。 問題分析 一般的棧

試題】在O(1)時間複雜度刪除連結串列節點

題目描述 給定一個單鏈表中的表頭和一個等待被刪除的節點(非表頭或表尾)。請在在O(1)時間複雜度刪除該連結串列節點。並在刪除該節點後,返回表頭。 樣例 給定 1->2->3->4,和節點 3,返回 1->2->4。 解題

試題18(一)O(1)時間刪除鏈表結點

else mil ptr font 復雜度 節點 else if 開始 nes // 面試題18(一):在O(1)時間刪除鏈表結點 // 題目:給定單向鏈表的頭指針和一個結點指針,定義一個函數在O(1)時間刪除該 // 結點。鏈表結點與函數的定義如下: // struct

劍指offer刪除連結串列的節點---在O(1)時間刪除連結串列節點

/** * 題目:(在O(1)時間內刪除連結串列節點) * 給定單鏈表的頭指標和節點指標,定義一個函式在O(1)時間內刪除節點。 * 解題思路: * 把下一個節點的內容複製到要刪除的節點上覆蓋原有的內容,再把下一個節點刪除。 *

劍指Offer試題11.列印1到最大的n位數

一、題目:列印1到最大的n位數 題目:輸入數字n,按順序打印出從1最大的n位十進位制數。比如輸入3,則打印出1、2、3一直到最大的3位數即999。 二、不同的解法 2.1 不假思索的解法   最容易想到的辦法是先求出最大的n位數,然後用一個迴圈從1開始逐個列印: static v

O(1)時間刪除連結串列節點

#include<iostream> using namespace std; struct ListNode { int data; ListNode* pNext; }; //構造連結串列 ListNode* InsertNode(ListNode* &pHead,int da

python字串試題找出一個字串中第一個字母最後一個字元是第一次重複,中間沒有重複且最長的子串

1.給出任意一個字串,列印一個最長子串字串及其長度,如果有相同長度的子字串,都要一起打印出來,該子字串滿足以下條件, 第一個字母和最後一個字元是第一次重複 這個子字串的中間字母沒有重複 這個子字串是滿足條件裡面的最長的 如: adsasadmasd 中滿足條件的是dmasd   im

java試題spring中的BeanFactory與ApplicationContext的作用區別?

          2. ApplicationContext除了提供上述BeanFactory所能提供的功能之外,還提供了更完整的框架功能:                  a. 國際化支援                        b. 資源訪問:Resource rs = ctx. getR

劍指Offer試題12.在O(1)時間刪除連結串列結點

一、題目:在O(1)時間刪除連結串列結點 題目:給定單向連結串列的頭指標和一個結點指標,定義一個函式在O(1)時間刪除該結點。   原文采用的是C/C++,這裡採用C#,節點定義如下: public class Node<T> { // 資料域

騰訊試題模板實現一個,要求Push(入),Pop(出),Max(返回最大值的操作)的時間複雜度為O(1)

解題思路:要用模板實現亂序入棧的陣列每次pop()出棧都能得到當前棧中Max的最大值,就必須在push()入棧時進行維護操作,使的每次入棧的元素都能夠找到合適的位置並push(),每次push()操作完成後棧中的元素都能夠按從棧頂到棧底從大到小排列即可。這就需要寫一個不同於常

O(1)時間刪除連結串列結點——試題13《劍指offer》

題目:給定單向連結串列得頭指標和一個節點指標,定義一個函式在O(1)時間刪除該結點。連結串列結點與函式的定義如下: struct ListNode { int m_nValue; ListNode* m_pNext; }; void DeleteNode(ListNode**

java算法試題遞歸算法題2 第1個人10,第2個比第1個人大2歲,依次遞推,請用遞歸方式計算出第8個人多大?

else oid 算法題 body println 算法 ring swift java算法 package com.swift; public class Digui_Return { public static void main(String[] arg

試題怎麼讓盒子在盒子居中

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> #

轉載JAVA企業試題精選 Java基礎 1-10

JAVA企業面試題精選 第一部分 Java基礎 1.1.你認為Java與其他(你所瞭解的)語言相比,有什麼優點和缺點? 參考答案:     首先,Java與C/C++相比。Java語言是一種完全的面嚮物件語言,雖

試題計算1-100的質數的個數

package day1; import java.util.Arrays; public class Homework { public static void main(String[] arg

C#試題判斷一個數的二進位制位的某一位是否是1

判斷一個數的二進位制位的某一位是否是1. 程式碼如下: bool IsThirdBitOne(int num,int n){       //使用ToString()方法,轉換成二進位制,第二個引數只能是,2,8,16;       string s=Convert.

華為試題1分2分5分的硬幣,組成1角,共有多少種組合。 Java原始碼

public class Jiaofen {  public static void main(String args[])  {      int i,j,k;      int n=0;      for(i=0;i<3;i++)  //五分的硬幣最多2個      {          for(j

劍指Offer試題9.二進位制中1的個數

一、題目:二進位制中1的個數 題目:請實現一個函式,輸入一個整數,輸出該數二進位制表示中1的個數。例如把9表示成二進位制是1001,有2位是1。因此如果輸入9,該函式輸出2。 二、可能引起死迴圈的解法   一個基本的思路:先判斷整數二進位制表示中最右邊一位是不是1。接著把輸入的整數右移一位,此時

劍指Offer試題1.實現Singleton模式

說來慚愧,自己在畢業之前就該好好看看《劍指Offer》這本書的,但是各種原因就是沒看,也因此錯過了很多機會,後悔莫及。但是後悔是沒用的,現在趁還有餘力,把這本書好好看一遍,並通過C#通通實現一遍,並記錄在我的部落格中,作為學習筆記。 一、題目:實現Singleton模式 題目:設計一個類,我們只能

19. 中興試題輸入兩個整數nm, 從數列1,2,...,n中任意選擇幾個數,使其等於m, 要求編寫程式輸出所有的組合

2010年中興面試題程式設計求解:輸入兩個整數 n 和 m,從數列1,2,3.......n中隨意取幾個數, 使其和等於 m ,要求將其中所有的可能組合列出來. 分析: 可以使用遞迴思想, 從第n個數開始找其組合, 1)包括n的所有組合 2)不包括n的所有組合 把所有組