数据结构与算法分类练习--栈 队列 堆

LIFO: last-in, first-out 后进先出。两种操作:PUSH--压入;POP--弹出。

python中可以使用list来实现栈。PUSH操作相当于list.append(x),POP操作相当于list.pop()。

队列

FIFO: first-in, first-out 先进先出。队列有队头和队尾,当一个元素入队时,被放在队尾的位置;而出队的元素则总是在队头的那个。两种操作:ENQUEUE--入队;DEQUEUE--出队。

python中对队列这种数据结构进行了模块化,可以使用collections.deque来实现队列。deque.append()相当于ENQUEUE, deque.popleft()相当于DEQUEUE,而deque.pop()则是从队尾弹出一个元素。

队列有一种变体叫做“优先队列”(Priority Queue)。优先队列的出队(Dequeue)操作和队列一样。但在优先队列的内部,元素的次序却是由“优先级”来决定:高优先级的元素排在队首,而低优先级的元素则排在后面。这样,优先队列的入队(Enqueue)需要将元素根据优先级尽量排到队列前面。一个实现优先队列的经典方法便是采用二叉堆(Binary Heap)。二叉堆能将优先队列的入队和出队复杂度都保持在O(logn)。

堆是一种特殊的树形数据结构,每个节点都有一个值,通常我们所说的堆的数据结构指的是完全二叉树。堆的特点是根节点的值最大(或者最小),而且根节点的两个孩子也能与孩子节点组成子树,亦然称之为堆。 堆分为两种,大根堆和小根堆是一颗每一个节点的键值都不小于(大于)其孩子节点的键值的树。

Python中也对堆这种数据结构进行了模块化,可以通过调用heapq模块来建立堆这种数据结构,同时heapq模块也提供了相应的方法来对堆做操作。

heap = [] #创建了一个空堆 

heappush(heap,item) #往堆中插入一条新的值 

item = heappop(heap) #从堆中弹出最小值 

item = heap[0] #查看堆中最小值,不弹出 

heapify(x) #以线性时间将一个列表转化为堆 

item = heapreplace(heap,val) #弹出返回最小值,并将val插入堆中。

Implement 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.

用栈的先进后出的特性来模拟出队列的先进先出,使用了两个栈A和B,其中新进栈的都先缓存在A中,要pop和peek的时候,才将A中所有元素移到B中操作.

class MyQueue(object):
    def __init__(self):
        self.A, self.B = [], []
    def push(self, x):
        self.A.append(x)
    def pop(self):
        self.peek()
        return self.B.pop()
    def peek(self):
        if not self.B:
            while self.A:
                self.B.append(self.A.pop())
        return self.B[-1]
    def empty(self):
        return not self.A and not self.B

Implement 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.

常规情况下需要两个队列,其中一个队列用来放最后加进来的数,模拟栈顶元素。剩下所有的数都按顺序放入另一个队列中。但在python中可以调用deque模块方便的实现栈操作。

class MyStack(object):
    def __init__(self):
        self.q = collections.deque()
    def push(self, x):
        self.q.append(x)
    def pop(self):
        return self.q.pop()
    def top(self):
        return self.q[-1]
    def empty(self):
        return not self.q

Min Stack

● 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.

使用一个栈和一个整型变量min来记录当前最小值,压入栈的数值是实际数值减去min,如果进栈的数字小于当前最小值,则将min更新为当前数字。在出栈操作时,将栈顶元素移出栈即可,如果该元素小于0,则更新最小值。

class MinStack(object):
    def __init__(self):
    	"""
        push 3 5 2 -1
        min  3 3 2 -1
        []   0 2 -1-3  push-p_min(上个最小值)
        """
        self.min = 0
        self.stack = []
    def push(self, x):
        if not self.stack:
            self.stack.append(0)
            self.min = x
        else:
            self.stack.append(x - self.min)
            if x < self.min:
                self.min = x
    def pop(self):
        x = self.stack.pop()
        if x < 0:
            # p_min = push - [] = self.min - x
            self.min = self.min - x    
    def top(self):
        # not self.stack.pop
        x = self.stack[-1]
        if x > 0:
            return x + self.min
        else:
            return self.min
    def getMin(self):
        return self.min

Basic Calculator

The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negativeintegers and empty spaces .

使用两个栈分别保存操作符和操作数,当遇到“(”时,弹出数值和运算符进行计算。

class Solution(object):
    def calculate(self, s):
        """
        :type s: str
        :rtype: int
        """
        operators, operands = [], []
        operand = ""
        for i in reversed(range(len(s))):
            if s[i].isdigit():
                operand += s[i]
                if i == 0 or not s[i-1].isdigit():
                    operands.append(int(operand[::-1]))
                    operand = ""
            elif s[i] == ')' or s[i] == "+" or s[i] == "-":
                operators.append(s[i])
            elif s[i] == "(":
                while operators[-1] != ")":
                    self.compute(operands, operators)
                operators.pop()
                
        while operators:
            self.compute(operands, operators)
        return operands[-1]
    
    def compute(self, operands, operators):
        digiA, digiB = operands.pop(), operands.pop()
        oper = operators.pop()
        if oper == "+":
            operands.append(digiA + digiB)
        if oper == "-":
            operands.append(digiA - digiB)

Kth Largest Element in an Array

参考快速排序的思想,每次都要先找一个中枢点Pivot,然后遍历其他所有的数字,像这道题从大往小排的话,就把小于中枢点的数字放到左半边,把大于中枢点的放在右半边,这样中枢点是整个数组中第几大的数字就确定了,左右两部分的无序并无影响。然后求出中枢点的位置,如果不是k-1,则更新左右边界继续查找。

from random import randint
class Solution(object):
    def findKthLargest(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        left, right = 0, len(nums)-1
        while left <= right:
            pivot_id = randint(left, right)
            new_pivot_id = self.partition_pivot(left, right, pivot_id, nums)
            if new_pivot_id == k - 1:
                return nums[new_pivot_id]
            elif new_pivot_id < k - 1:
                left = new_pivot_id + 1
            else:
                right = new_pivot_id - 1
                
    def partition_pivot(self, left, right, pivot_id, num):
        num[right], num[pivot_id] = num[pivot_id], num[right]
        new_pivot_id = left
        for i in range(left, right):
            if num[i] > num[right]:
                num[i], num[new_pivot_id] = num[new_pivot_id], num[i]
                new_pivot_id += 1
        num[right], num[new_pivot_id] = num[new_pivot_id], num[right]
        return new_pivot_id

Find Median from Data Stream

Examples:

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

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

使用大小堆来解决问题,其中大堆保存右半段较大的数字,小堆保存左半段较小的数组。由于堆的保存方式是由大到小,我们希望大堆里面的数据是从小到大,这样取第一个来计算中位数方便。我们可以在存到大堆里时先把数取反再存,这样由大到小存下来的顺序就是实际上我们想要的从小到大的顺序。当大堆和小堆中的数字一样多时,我们取出大堆小堆的首元素求平均值,当小堆元素多时,取小堆首元素为中位数。

from heapq import heappush, heappop
class MedianFinder(object):
    def __init__(self):
        """
        initialize your data structure here.
        """
        self.max_heap, self.min_heap = [], [] # 小的部分 大的部分
    def addNum(self, num):
        """
        :type num: int
        :rtype: void
        """
        if not self.max_heap or num > -self.max_heap[0]:
            heappush(self.min_heap, num)
            if len(self.min_heap) > len(self.max_heap) + 1:
                heappush(self.max_heap, -heappop(self.min_heap))
        else:
            heappush(self.max_heap, -num)
            if len(self.max_heap) > len(self.min_heap):
                heappush(self.min_heap, -heappop(self.max_heap))
    def findMedian(self):
        """
        :rtype: float
        """
        return (-self.max_heap[0] + self.min_heap[0]) / 2.0 if len(self.min_heap) == len(self.max_heap) else self.min_heap[0]

猜你喜欢

转载自blog.csdn.net/ZJL0105/article/details/81212710