一、題目內容
設計一個支持 push,pop,top 操作,並能在常數時間內檢索到最小元素的棧。
- push(x) – 將元素 x 推入棧中。
- pop() – 刪除棧頂的元素。
- top() – 獲取棧頂元素。
- getMin() – 檢索棧中的最小元素。
示例:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
二、解題思路
解題思路一(維護一個有序的鏈表)
- 1.實現棧效果可以使用Stack類型來完成
- 2.實現“在常數時間內檢索到最小元素的棧”可以維護一個[有序雙向鏈表(升序)]
-
a.棧中Push新元素就插入到[有序雙向鏈表(升序)]中【時間複雜度O(n)】 b.查詢最小元素就直接把[有序雙向鏈表(升序)]第一個元素返回【時間複雜度O(1)】 c.刪除棧頂元素就把刪除的那個元素,在[有序雙向鏈表(升序)]中刪除【時間複雜度O(1)】
代碼實現
public class MinStack
{
/*
* 1.實現棧效果可以使用Stack<T>類型來完成
* 2.實現“在常數時間內檢索到最小元素的棧”可以維護一個[有序雙向鏈表(升序)],
* a.棧中Push新元素就插入到[有序雙向鏈表(升序)]中【時間複雜度O(n)】
* b.查詢最小元素就直接把[有序雙向鏈表(升序)]第一個元素返回【時間複雜度O(1)】
* c.刪除棧頂元素就把刪除的那個元素,在[有序雙向鏈表(升序)]中刪除【時間複雜度O(1)】
*/
public MinStack()
{
_stack = new Stack<LinkedListNode>();
}
/// <summary>
/// 棧
/// </summary>
private readonly Stack<LinkedListNode> _stack;
/// <summary>
/// 第一個元素【最小元素】
/// </summary>
private LinkedListNode _top;
/// <summary>
/// 向雙向鏈表插入一個元素
/// </summary>
/// <param name="node">插入的節點【一定是乾淨的節點 Left = null && Right = null】</param>
private void AddLinkedListNode(LinkedListNode node)
{
//判斷_top 是否爲null
if (_top == null)
{
//如果爲null就賦值當前節點爲top【結束】
_top = node;
return;
}
//判斷_top節點是否大於當前節點
if (_top.Value > node.Value)
{
//如果大於,將當前節點和_top節點互換位置,並關聯【結束】
node.Right = _top;
_top.Left = node;
_top = node;
return;
}
//循環查詢從_top節點開始查詢,下個節點是否爲null或者大於等於當前節點
var upNode = _top;
while (upNode.Right != null && upNode.Right.Value < node.Value)
{
upNode = upNode.Right;
}
//如果爲null就將上一個節點下和當前節點關聯
if (upNode.Right == null)
{
upNode.Right = node;
node.Left = upNode;
}
//如果大於就將上一個節點和下一個節點中插入當前節點【結束】
else
{
node.Left = upNode;
node.Right = upNode.Right;
upNode.Right.Left = node;
upNode.Right = node;
}
}
/// <summary>
/// 雙向鏈表移除一個元素
/// </summary>
/// <param name="node">移除的節點</param>
private void RemoveLinkedListNode(LinkedListNode node)
{
//當前節點是否有left
if (node.Left == null)
{
//沒有就將當前節點的子節點賦值爲_top,並將當前節點和右節點斷開連接【返回】
//判斷右節點是否爲null,如果爲null就不需要斷開連接
_top = node.Right;
if (node.Right != null)
node.Right.Left = null;
}
else
{
//讓左邊節點和右邊節點連接
node.Left.Right = node.Right;
if (node.Right != null)
node.Right.Left = node.Left;
}
}
/// <summary>
/// 將元素 x 推入棧中。
/// </summary>
public void Push(int x)
{
var node = new LinkedListNode(x);
//棧中Push新元素就插入到[有序雙向鏈表(升序)]中【時間複雜度O(n)】
AddLinkedListNode(node);
//將元素加入棧
_stack.Push(node);
}
/// <summary>
/// 刪除棧頂的元素。
/// </summary>
public void Pop()
{
//取出並移除棧頂元素
var node = _stack.Pop();
//刪除棧頂元素就把刪除的那個元素,在[有序雙向鏈表(升序)]中刪除【時間複雜度O(1)】
RemoveLinkedListNode(node);
}
/// <summary>
/// 獲取棧頂元素。
/// </summary>
public int Top()
{
//取出棧頂元素,並返回其值
return _stack.Peek().Value;
}
/// <summary>
/// 檢索棧中的最小元素。
/// </summary>
public int GetMin()
{
if (_top == null) return 0;
//查詢最小元素就直接把[有序雙向鏈表(升序)]第一個元素返回【時間複雜度O(1)】
return _top.Value;
}
/// <summary>
/// 雙向鏈表節點
/// </summary>
public class LinkedListNode
{
public LinkedListNode(int value)
{
Value = value;
}
/// <summary>
/// 左節點
/// </summary>
public LinkedListNode Left { get; set; }
/// <summary>
/// 右節點
/// </summary>
public LinkedListNode Right { get; set; }
/// <summary>
/// 值
/// </summary>
public int Value { get; set; }
public override string ToString()
{
return Value.ToString();
}
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.Push(x);
* obj.Pop();
* int param_3 = obj.Top();
* int param_4 = obj.GetMin();
*/
解題思路二(維護一個最小值)
- 1.實現棧效果可以使用Stack類型來完成
- 2.實現“在常數時間內檢索到最小元素的棧”直接維護一個[最小值變量]
-
a.Push新值時更新下最小值【時間複雜度O(1)】 b.Pop刪除棧頂的元素時,更新最小值【時間複雜度O(n)】 c.GetMin 檢索棧中的最小元素,就返回[最小值變量]【時間複雜度O(1)】
代碼實現
public class MinStack
{
/*
* 1.實現棧效果可以使用Stack<T>類型來完成
* 2.實現“在常數時間內檢索到最小元素的棧”直接維護一個[最小值變量]
* a.Push新值時更新下最小值【時間複雜度O(1)】
* b.Pop刪除棧頂的元素時,更新最小值【時間複雜度O(n)】
* c.GetMin 檢索棧中的最小元素,就返回[最小值變量]【時間複雜度O(1)】
*/
public MinStack()
{
_stack = new Stack<int>();
}
/// <summary>
/// 棧
/// </summary>
private readonly Stack<int> _stack;
/// <summary>
/// 存儲最小值
/// </summary>
private int _min = int.MaxValue;
/// <summary>
/// 將元素 x 推入棧中。
/// </summary>
public void Push(int x)
{
//將元素加入棧
_stack.Push(x);
_min = Math.Min(_min, x);
}
/// <summary>
/// 刪除棧頂的元素。
/// </summary>
public void Pop()
{
//取出並移除棧頂元素
var x = _stack.Pop();
//判斷移除的值是否爲最小值,如果不是就不需要更新最小值
if (x == _min)
{
//更新最小值
_min = _stack.Any() ? _stack.Min() : int.MaxValue;
}
}
/// <summary>
/// 獲取棧頂元素。
/// </summary>
public int Top()
{
//取出棧頂元素
return _stack.Peek();
}
/// <summary>
/// 檢索棧中的最小元素。
/// </summary>
public int GetMin()
{
return _min;
}
}
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.Push(x);
* obj.Pop();
* int param_3 = obj.Top();
* int param_4 = obj.GetMin();
*/