python数据结构实现(二)

一:栈

1. 用数组实现一个顺序栈

class ArrayStack:
    '''
    顺序栈,栈顶指针指向的是栈顶元素
    '''
    def __init__(self, capacity=20):    # 默认栈容量为20
        self.capacity = capacity
        self.data = [None] * self.capacity
        self.top = -1
        self.size = 0
        
    def push(self, value):
        '''
        元素进栈
        '''
        if self.top == self.capacity - 1:
            raise Exception('push failed: stack is full')
        else:
            self.top += 1
            self.data[self.top] = value
            self.size += 1
        
    def pop(self):
        '''
        元素出栈,并返回该元素
        '''
        if self.top == -1:
            raise Exception('pop failed: the stack is empty')
        else:
            elem = self.data[self.top]
            self.top -= 1
            self.size -= 1
            return elem
    
    def isEmpty(self):
        '''判断栈是否为空'''
        return self.top == -1
    
    def isFull(self):
        '''判断是否为满栈'''
        return self.top == self.capacity - 1

2. 用链表实现一个链式栈

class ListNode:
    def __init__(self, value, pnext=None):
        self.data = value
        self.next = pnext

class LinkedlistStack:
    '''链栈'''
    def __init__(self):
        self.head = ListNode(None)
        self.size = 0
    
    def push(self, value):
        '''元素入栈:前插结点'''
        node = ListNode(value)
        node.next = self.head.next
        self.head.next = node
        self.size += 1
        
    def pop(self):
        '''元素出栈并返回'''
        if self.isEmpty():
            raise Exception('pop failed: the stack is empty')
        else:
            p = self.head.next
            self.head.next = p.next
            self.size -= 1
        return p
        
    def isEmpty(self):
        return self.size == 0
    
stack = LinkedlistStack()
stack.push(3)
stack.push(4)
stack.push(5)
stack.push(6)
q = stack.pop()

3.编程模拟实现一个浏览器的前进、后退功能

class ListNode:
    '''链表结点'''
    def __init__(self, value, pnext=None):
        self.data = value
        self.next = pnext

class LinkedlistStack:
    '''链栈'''
    def __init__(self):
        self.head = ListNode(None)
        self.size = 0
    
    def push(self, value):
        '''元素入栈:前插结点'''
        node = ListNode(value)
        node.next = self.head.next
        self.head.next = node
        self.size += 1
        
    def pop(self):
        '''元素出栈并返回'''
        if self.isEmpty():
            raise Exception('pop failed: the stack is empty')
        else:
            p = self.head.next
            self.head.next = p.next
            self.size -= 1
        return p
        
    def isEmpty(self):
        if self.size == 0:
            return True
        else:
            return False

class Simulation:
    '''
    模仿浏览器的前进后退
    用两个链栈currentStack和helperStack来存储浏览的网页地址
    currentStack的栈顶元素为当前浏览的网页地址
    '''
    def __init__(self, mainPage):                 # mainPage为浏览器主页网址
        self.currentStack = LinkedlistStack()
        self.helperStack = LinkedlistStack()
        self.currentStack.push(mainPage)
    
    def show(self):
        '''显示当前网址的网页内容'''
        website = self.currentStack.head.next.data
        print('Showing the content of the current website:%s' % website)
        
    def goNew(self, newWebsite):
        '''访问之前未访问过的新网址'''
        self.currentStack.push(newWebsite)
        self.helperStack.head.next = None        # 当浏览了新网址,就不能再进行前进操作,故清空helperStack
        
    def goFoward(self, nextWebsite):
        if self.helperStack.isEmpty():
            return None                         # 当helperStack为空栈时,无法进行GoForward操作
        else:
            p = self.helperStack.pop()
            self.currentStack.push(p)
            self.show()
    
    def goBack(self, preWebsite):
        if self.currentStack.size == 1:
            return None                         # 当currentStack只有一个网址时,无法进行GoBack操作
        else:
            p = self.currentStack.pop()
            self.helperStack.push(p)
            self.show()

4. leetcode相关习题

(1). Valid Parentheses(有效的括号)

用栈结构实现

class Solution:
    def isValid(self, s: str) -> bool:
        stack = [None] * len(s)
        top = -1
        for _ in s:
            if _ == '(':
                top += 1
                stack[top] = _
            elif _ == '[':
                top += 1
                stack[top] = _
            elif _ == '{':
                top += 1
                stack[top] = _
            elif _ == ')':
                if stack[top] != '(':
                    return False
                else:
                    top -= 1
            elif _ == ']':
                if stack[top] != '[':
                    return False
                else:
                    top -= 1
            elif _ == '}':
                if stack[top] != '{':
                    return False
                else:
                    top -= 1
        return top == -1

(2). Longest Valid Parentheses(最长有效的括号)

class Solution:
    def longestValidParentheses(self, s: str) -> int:
        '''
        遍历字符串,设置一个judge数组,将符合条件的左右括号在judge数组中的对应位置上置为True
        遍历judge数组,求出最大连续True的长度
        '''
        stack, judge = [], [0] * len(s)
        for index, parentthese in enumerate(s):
            if parentthese == '(':
                stack.append(index)
            else:
                if stack:
                    judge[index] = judge[stack.pop()] = True
                    
        maxnum = count = 0
        for n in judge:
            if n:
                count += 1
            else:
                maxnum = max(maxnum, count)
                count = 0
        return max(maxnum, count)      # 若以合法括号的')'结尾的情况,此时的值在最后一次的count里

(3). Evaluate Reverse Polish Notatio(逆波兰表达式求值)

class Solution:
    def evalRPN(self, tokens):
        stack = [None] * len(tokens); top = -1
        operators = ['+', '-', '*', '/']
        for token in tokens:
            if token in operators:
                if top == -1:
                    return 
                else:
                    num1 = stack[top]; top -= 1
                    print(num1)
                    num2 = stack[top]; top -= 1
                    result = Solution.operation(num1, num2, token)
                    top += 1; stack[top] = result
            else:
                top += 1; stack[top] = int(token)
        return stack[0]
        
    def operation(num1, num2, op):
        if op == '+':
            return num2 + num1
        elif op == '-':
            return num2 - num1
        elif op == '*':
                return num2 * num1
        else:
            if num1 != 0:
                return int(num2 / num1)   # 若用//则除负数时结果会出错,如7 // -3python的结果为-3,而我们要求的值为-2

二:队列

1. 用数组实现一个顺序队列

class Queue:
    '''
    数组实现顺序队列,头尾指针初始时都为0
    头指针指向队头元素,尾指针指向队尾元素的下一个位置
    当头尾指针指向同一处时,队空
    '''
    def __init__(self, capacity=20):
        self.capacity = capacity
        self.size = 0
        self.front = 0
        self.rear = 0
        self.data = [None] * self.capacity
        
    def enqueue(self, value):
        '''入队'''
        if self.queueFull():
            raise Exception('Enqueue failed: Queue is full')
        else:
            self.data[self.rear] = value
            self.rear += 1
            self.size += 1
    
    def dequeue(self):
        '''出队并返回出队元素'''
        if self.queueEmpty():
            raise Exception('Dequeue failed: Queue is empty')
        else:
            x = self.data[self.front]
            self.front += 1
            self.size -= 1
        return x
    
    def queueEmpty(self):
        return self.size == 0
    
    def queueFull(self):
        return self.size == self.capacity

2. 用python实现一个链式队列

class ListNode:
    def __init__(self, value, pnext=None):
        self.data = value
        self.next = pnext
        
class LinkedlistQueue:
    '''
    链表实现带头结点的链队
    头指针始终指向头结点,尾指针指向队尾元素
    当头指针和尾指针都指向头结点时表示队空
    '''
    def __init__(self, headNode):
        self.front = self.rear = headNode
        self.size = 0
    
    def isEmpty(self):
        return self.rear == self.front
    
    def enqueue(self, value):
        '''入队'''
        node = ListNode(value)
        self.rear.next = node
        self.rear = node
        self.size += 1
        
    def dequeue(self):
        '''出队并返回出队元素,分别考虑链队只有一个结点和队空的情况'''
        if self.size == 1:         # 只有一个结点,出队后头尾指针都指向头结点
            x = self.rear.data
            self.rear = self.front
            self.front.next = None
            self.size -= 1
            return x
        elif self.size == 0:
            raise Exception('Dequeue failed: Queue is empty')
        else:
            x = self.front.next
            self.front.next = x.next
            self.size -= 1
            return x.data

3. 用python实现一个循环队列

class RecyQueue:
    '''
    顺序结构循环队列
    头指针指向队头元素,尾指针指向队尾元素的下一个位置
    牺牲一个空间位置用于区分队空队满
    队空:front == rear
    队满:(rear + 1) % capacity == front
    '''
    def __init__(self, capacity=20):
        self.capacity = capacity
        self.data = [None] * self.capacity
        self.front = self.rear = 0
        
    def isEmpty(self):
        return self.front == self.rear
    
    def isFull(self):
        return (self.rear + 1) % self.capacity == self.front
    
    def enqueue(self, value):
        if self.isFull():
            raise Exception('Enqueue failed: Queue is full')
        else:
            self.data[self.rear] = value
            self.rear = (self.rear + 1) % self.capacity
            
    def dequeue(self):
        if self.isEmpty():
            raise Exception('Dequeue failed: Queue is empty')
        else:
            x = self.data[self.front]
            self.front = (self.front + 1) % self.capacity
            return x

4.LeetCode练习题

(1). Design Circular Deque(设计一个双端队列)

class MyCircularDeque:
	'''
	采用循环队列实现双端队列
	队头指针指向队头元素
	队尾指针指向队尾元素的下一个位置
	增加一个size变量统计队列的有效元素,利用全部的存储空间
	'''
    def __init__(self, k: int):
        """
        Initialize your data structure here. Set the size of the deque to be k.
        """
        self.capacity = k
        self.data = [None] * self.capacity
        self.size = 0
        self.front = self.rear = 0

    def insertFront(self, value: int) -> bool:
        """
        Adds an item at the front of Deque. Return true if the operation is successful.
        """
        if not self.isFull():
            self.front = (self.front - 1) % self.capacity     # 队头入队,减一
            self.data[self.front] = value
            self.size += 1
            return True
        else:
            return False

    def insertLast(self, value: int) -> bool:
        """
        Adds an item at the rear of Deque. Return true if the operation is successful.
        """
        if not self.isFull():
            self.data[self.rear] = value
            self.rear = (self.rear + 1) % self.capacity 
            self.size += 1
            return True
        else:
            return False

    def deleteFront(self) -> bool:
        """
        Deletes an item from the front of Deque. Return true if the operation is successful.
        """
        if not self.isEmpty():
            self.front = (self.front + 1) % self.capacity
            self.size -= 1
            return True
        else:
            return False

    def deleteLast(self) -> bool:
        """
        Deletes an item from the rear of Deque. Return true if the operation is successful.
        """
        if not self.isEmpty():
            self.rear = (self.rear - 1) % self.capacity 
            self.size -= 1
            return True
        else:
            return False

    def getFront(self) -> int:
        """
        Get the front item from the deque.
        """
        if not self.isEmpty():
            return self.data[self.front]
        else:
            return -1

    def getRear(self) -> int:
        """
        Get the last item from the deque.
        """
        if not self.isEmpty():
            return self.data[(self.rear-1)%self.capacity]
        else:
            return -1

    def isEmpty(self) -> bool:
        """
        Checks whether the circular deque is empty or not.
        """
        return self.size == 0

    def isFull(self) -> bool:
        """
        Checks whether the circular deque is full or not.
        """
        return self.size == self.capacity


# Your MyCircularDeque object will be instantiated and called as such:
# obj = MyCircularDeque(k)
# param_1 = obj.insertFront(value)
# param_2 = obj.insertLast(value)
# param_3 = obj.deleteFront()
# param_4 = obj.deleteLast()
# param_5 = obj.getFront()
# param_6 = obj.getRear()
# param_7 = obj.isEmpty()
# param_8 = obj.isFull()

(2). Sliding Window Maximum(滑动窗口最大值)

class Solution:
    def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        if nums:
            if k == 1:
                return nums
            else:
                a = 0; result = []
                length = len(nums) 
                currWindow = nums[:k]
                maxnum = max(currWindow)   # 第一个窗口的最大值
                a += 1
                result.append(maxnum)

                while a+k-1 < length:
                    currWindow = nums[a:a+k]
                    if nums[a-1] != maxnum:          # 若出队的元素不是最大值,则比较新进元素与当前最大值(当然同一个窗口中可能有多个最大值,只是一定程度上减少计算量)
                        if currWindow[-1] > maxnum:
                            maxnum = currWindow[-1]
                    else:                # 若最大值出队,则重新求得当前窗口的最大值
                        maxnum = max(currWindow)
                    result.append(maxnum)
                    a += 1
                return result
        else:
            return []   

三. 递归

1. 编程实现斐波那契数列求值 f(n)=f(n-1)+f(n-2)

def Fibonacci(n):
    '''递归求斐波那契数列的第n个值'''
    a = b = 1
    if n == 0 or n == 1:
        return 1
    else:
        return Fibonacci(n-1) + Fibonacci(n-2)

2. 编程实现求阶乘 n!

def factorial(n):
    if n == 0 or n == 1:
        return 1
    else:
        return n * factorial(n-1)

3. 编程实现一组数据集合的全排列

def perm(nums, end):
    '''生成nums[0]到nums[end]的全排列'''
    if end == 0:
        for num in nums:
            print(num,end=' ')
        print('\n')
    else:
        for i in range(end+1):
            nums[i], nums[end] = nums[end], nums[i]   
            perm(nums, end-1)
            nums[i], nums[end] = nums[end], nums[i]   # 恢复数组

perm([1,2,3],2)

4. LeetCode练习题

(1) Climbing Stairs(爬楼梯)

由于递归函数重复计算量很大,在LeetCode上直接用递归思路的话会超时,好在python的小‘trick’确实多。这里采用了python的缓存机制,将递归函数的计算结果都存储起来,之后直接调用即可。
@lru_cache(num) :num为存储的数量,默认为128

from functools import lru_cache
class Solution:
    @lru_cache(10**8)
    def climbStairs(self, n: int) -> int:
        if n == 1:
            return 1
        elif n == 2:
            return 2
        else:
            return self.climbStairs(n-1) + self.climbStairs(n-2)   # 分别对应第一步选择走一步和走两步的情况

猜你喜欢

转载自blog.csdn.net/shichensuyu/article/details/90181375