1. 程式人生 > >python資料結構之棧、佇列與堆

python資料結構之棧、佇列與堆

目錄

  1. 棧與佇列的基礎知識
  2. 使用佇列實現棧 (LeetCode 225)
  3. 使用棧實現佇列 (LeetCode 232)
  4. 包含min函式的棧(LeetCode 155)
  5. 合法的出棧序列
  6. 堆的必備基礎知識
  7. 陣列中的第K大的數 (LeetCode 215)
  8. 尋找中位數(LeetCode 295)

1. 棧與佇列的基礎知識

  • 棧(stacks)是一種只能通過訪問其一端來實現資料儲存與檢索的線性資料結構,具有後進先出(last in first out,LIFO)的特徵

  • 佇列(queue)是一種具有先進先出特徵的線性資料結構,元素的增加只能在一端進行,元素的刪除只能在另一端進行。能夠增加元素的佇列一端稱為隊尾,可以刪除元素的佇列一端則稱為隊首。python庫from collections import deque

    可以實現,popleft()。

2. 使用佇列實現棧 (LeetCode 225 Implement Stack using Queues)

2.1題目

Implement the following operations of a stack using queues.

push(x) – Push element x onto stack.
pop() – Removes the element on top of the stack.
top() – Get the top element.
empty() – Return whether the stack is empty.
Notes:
You must use only standard operations of a queue – which means only push to back, peek/pop from front, size, and is empty operations are valid.
Depending on your language, queue may not be supported natively. You may simulate a queue by using a list or deque (double-ended queue), as long as you use only standard operations of a queue.
You may assume that all operations are valid (for example, no pop or top operations will be called on an empty stack).

2.2思路

棧是後進先出,佇列是先進先出,佇列在python中要使用collections.dequeue()
要用隊列表示棧,則在元素入棧時對棧元素的順序進行調整,將最後元素之前的元素按順序移動到最後一個元素的後面,使最後一個進入的元素位於佇列的前面。

2.3程式碼

class MyStack(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.stack = collections.deque([])


    def
push(self, x):
""" self.stack = [] Push element x onto stack. :type x: int :rtype: void """ self.stack.append(x) q = self.stack for i in range(len(q) - 1): q.append(q.popleft()) def pop(self): """ Removes the element on top of the stack and returns that element. :rtype: int """ return self.stack.popleft() def top(self): """ Get the top element. :rtype: int """ return self.stack[0] def empty(self): """ Returns whether the stack is empty. :rtype: bool """ if len(self.stack) == 0: return True else: return False

3. 使用棧實現佇列 (LeetCode 232)

3.1題目

Implement the following operations of a queue using stacks.

push(x) – Push element x to the back of queue.
pop() – Removes the element from in front of queue.
peek() – Get the front element.
empty() – Return whether the queue is empty.
Notes:
You must use only standard operations of a stack – which means only push to top, peek/pop from top, size, and is empty operations are valid.
Depending on your language, stack may not be supported natively. You may simulate a stack by using a list or deque (double-ended queue), as long as you use only standard operations of a stack.
You may assume that all operations are valid (for example, no pop or peek operations will be called on an empty queue).

3.2思路

棧是後進先出,佇列是先進先出
可以使用2個棧來表示,一個表示入棧,還有一個表示出棧,出棧的順序與入棧的順序相反

3.3程式碼

class MyQueue(object):

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.input = []
        self.output = []

    def push(self, x):
        """
        Push element x to the back of queue.
        :type x: int
        :rtype: void
        """
        self.input.append(x)

    def pop(self):
        """
        Removes the element from in front of queue and returns that element.
        :rtype: int
        """
        self.peek()
        return self.output.pop()


    def peek(self):
        """
        Get the front element.
        :rtype: int
        """
        if self.output == []:
            while self.input:
                self.output.append(self.input.pop())
        return self.output[-1]

    def empty(self):
        """
        Returns whether the queue is empty.
        :rtype: bool
        """
        return self.input == [] and self.output == []

4. 包含min函式的棧(LeetCode 155 Min Stack)

4.1題目

Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.

push(x) – Push element x onto stack.
pop() – Removes the element on top of the stack.
top() – Get the top element.
getMin() – Retrieve the minimum element in the stack.
Example:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> Returns -3.
minStack.pop();
minStack.top();      --> Returns 0.
minStack.getMin();   --> Returns -2.

4.2思路

使用2個列表,一個用於表示棧,用來壓入資料和彈出資料,還有一個表示最小數的列表minstack,當minstack==[]或者當前元素小於minstack的棧頂元素時,則將該元素壓入minstack,從而保證minstack的最後一個元素是當前所有元素中最小的。彈棧時注意棧頂元素與minstack的棧頂元素是否相等,若相等,則將兩個列表的棧頂元素都彈出,否則只彈出資料棧的棧頂元素

4.3程式碼

class MinStack(object):

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.stack = []
        self.minstack = []


    def push(self, x):
        """
        :type x: int
        :rtype: void
        """
        self.stack.append(x)
        if self.minstack == [] or x <= self.minstack[-1]:
            self.minstack.append(x)



    def pop(self):
        """
        :rtype: void
        """
        if self.stack != []:
            if self.stack[-1] == self.minstack[-1]:
                self.minstack.pop()
            self.stack.pop()


    def top(self):
        """
        :rtype: int
        """
        if self.stack != []:
            return self.stack[-1]
        else:
            return None


    def getMin(self):
        """
        :rtype: int
        """
        if self.minstack != []:            
            return self.minstack[-1]
        else:
            return None

5. 合法的出棧序列

5.1題目

輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否為該棧的彈出順序。假設壓入棧的所有數字均不相等。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列,但4,3,5,1,2就不可能是該壓棧序列的彈出序列。(注意:這兩個序列的長度是相等的)

5.2思路

新建立一個棧用於模仿棧的壓入和彈出,若彈出序列正確,則這個新建立的棧應該為空

5.3程式碼

Class Solution:
    def IsPopOrder(self, pushV, popV):
        if pushV == [] or popV == []:
            return False
        stack = []
        for i in pushV:
            stack.append(i)
            while len(stack) and stack[-1] == popV[0]:
                stack.pop()
                popV.pop(0)
        if stack != []:
            return False
        else:
            return True

6. 堆的必備基礎知識

二叉堆:是一棵特殊的完全二叉樹,其特點:

  • 二叉樹中的所有的父節點的值都不大於/不小於其子節點;
  • 根節點的值必定是所有節點中最小/最大的

將父節點的值不大於子節點且根節點值最小的稱為最小堆,反之稱為最大堆。堆是一種高階的資料結構,在python中有相應的模組deapq

7. 陣列中的第K大的數 (LeetCode 215 Kth Largest Element in an Array)

7.1題目

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
For example,
Given [3,2,1,5,6,4] and k = 2, return 5.

Note:
You may assume k is always valid, 1 ≤ k ≤ array’s length.**

7.2思路

思路1:先對陣列排序,再求解第k個元素
思路2:使用最小堆做,第k大的數即len(q)-k小的元素

7.3程式碼

#排序法
class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        nums.sort()
        return nums[-k]
#最小堆法
class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        heap = []
        for num in nums:
            heapq.heappush(heap, num)
        for i in range(len(nums) - k):
            heapq.heappop(heap)
        return heapq.heappop(heap)

8. 尋找中位數(LeetCode 295 Find Median from Data Stream)

8.1題目

Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.

Examples:
[2,3,4] , the median is 3

[2,3], the median is (2 + 3) / 2 = 2.5

Design a data structure that supports the following two operations:

void addNum(int num) - Add a integer number from the data stream to the data structure.
double findMedian() - Return the median of all elements so far.

8.2思路

維護兩個堆,一個是大頂堆,一個是小頂堆,使用python內建庫heapq。
這裡寫圖片描述
如上圖所示,每次新增元素時保證0<=len(maxheap)len(minheap)<=1,且max<=min
因為heap[0]表示的是堆中最小的元素,所以要使heap[0]表示的是堆中最大的元素,則將加入該堆的所有元素取負。新增元素時,首先將該元素取負加入maxheap中,然後對maxheap和minheap進行調整:如果maxheap中的最大元素比minheap中的最小元素要大或者len(maxheap)>len(minheap)+1,彈出maxheap中的最大元素加入minheap中;如果len(maxheap)<len(minheap),則將minheap中的最小元素加入maxheap中。
求中位數時,如果陣列長度為奇數,則返回max,是偶數,則返回(max+min)/2

8.3程式碼

from heapq import *
class MedianFinder(object):
    def __init__(self):
        """
        initialize your data structure here.
        """
        self.minHeap = []
        self.maxHeap = []

    def addNum(self, num):
        """
        :type num: int
        :rtype: void
        """
        heappush(self.maxHeap, -num)
        minTop = self.minHeap[0] if len(self.minHeap) else None
        maxTop = self.maxHeap[0] if len(self.maxHeap) else None
        if minTop < -maxTop or len(self.minHeap) + 1 < len(self.maxHeap):
            heappush(self.minHeap, -heappop(self.maxHeap))
        if len(self.maxHeap) < len(self.minHeap):
            heappush(self.maxHeap, -heappop(self.minHeap))
    def findMedian(self):
        """
        :rtype: float
        """
        if len(self.minHeap) < len(self.maxHeap):
            return -1.0 * self.maxHeap[0]
        else:
            return (self.minHeap[0] - self.maxHeap[0]) / 2.0