文章目录

  • 1.学习目标
    • 1.1 栈
    • 1.2 队列
    • 1.3 递归
    • 1.4 LeetCode练习题
  • 2.学习过程
    • 2.1 栈
    • 2.2 队列
    • 2.3 递归
    • 2.4 LeetCode练习题
  • 3.参考链接

任务2: 3~4天

1.学习目标

1.1 栈

用数组实现一个顺序栈
用链表实现一个链式栈
编程模拟实现一个浏览器的前进、后退功能

1.2 队列

用数组实现一个顺序队列
用链表实现一个链式队列
实现一个循环队列

1.3 递归

编程实现斐波那契数列求值 f(n)=f(n-1)+f(n-2)
编程实现求阶乘 n!
编程实现一组数据集合的全排列

1.4 LeetCode练习题


Valid Parentheses(有效的括号,第20题,难度:Easy)
英文版:Loading…
中文版:Loading…

Longest Valid Parentheses(最长有效的括号,第32题,难度,hard)
英文版:Loading…
中文版:Loading…

Evaluate Reverse Polish Notatio(逆波兰表达式求值,第150题,难度:Medium)
英文版:Loading…
中文版:Loading…

队列
Design Circular Deque(设计一个双端队列,第641题,难度:Medium)
英文版:Loading…
中文版:Loading…

Sliding Window Maximum(滑动窗口最大值,第239题,难度,Hard)
英文版:Loading…
中文版:Loading…

递归
Climbing Stairs(爬楼梯,第70题,难度:Easy)
英文版:Loading…
中文版:Loading…

2.学习过程

2.1 栈

首先应该明确栈的概念及特点,所谓栈,就是一种容器,其中添加移除新项总发生在同一端。这一端通常称为“顶部”。与顶部对应的端称为“底部”。
最重要特性:先进后出。这一特性让栈拥有反转元素顺序的功能。
2.1.1用数组实现一个顺序栈
栈作为一个先进后出的数据结构,具有压栈、弹栈、取栈顶元素、加入元素、判断为空以及获取栈中元素的方法。而为了实现这些功能,我们可以通过数组和链表来完成。Python的list及其操作可以提供与栈的使用方式有关的功能,可以使用list来实现栈。这里我们默认list末尾为栈顶。

class Stack:def __init__(self):self.items = []def isEmpty(self):return self.items == []def push(self, item):   # 进栈self.items.append(item)def pop(self):  #弹出return self.items.pop()def peek(self):  # 打印栈顶元素return self.items[len(self.items)-1]def size(self):return len(self.items)

2.1.2用链表实现一个链式栈
链式栈自然就以表头为栈顶

class ListNode:def __init__(self, elem, next=None):self.elem = elemself.next = nextclass LStack():def __init__(self):self._top = Nonedef isEmpty(self):return self._top is Nonedef push(self, elem):self._top = ListNode(elem, self._top)def pop(self):if self._top is None:raise ValueError('wrong in pop!')p = self._topself._top = p.nextreturn p.elemdef peek(self):if self._top is None:raise ValueError('wrong in peek!')return self._top.elemdef __repr__(self) -> str:cur = self._topnums = []while cur:nums.append(cur._data)cur = cur._nextreturn "--> ".join(f"{num}" for num in nums)if __name__ == '__main__':stack = LStack()for i in range(10):stack.push(i)print(stack)

采用数组实现栈和采用链表实现栈对比:
采用数组实现栈的优点:一个元素值占用一个存储空间;它的缺点为:如果初始化申请的存储空间太大,会造成空间的浪费,如果申请的存储空间太小,后期会经常需要扩充存储空间,扩充存储空间是个费时的操作,这样会造成性能的下降。
采用链表实现栈的优点是:使用灵活方便,只有在需要的时候才会申请空间,它的缺点为:除了要存储元素外,还需要额外的存储空间存储指针信息。
2.1.3编程模拟实现一个浏览器的前进、后退功能

class Browser():def __init__(self):self.x = LStack()  # 前进self.y = LStack()  # 后退def view(self, page):print('Viewing %s' % page, end='\n')self.x.push(page)def forward(self):if self.y.isEmpty():print( 'can not forward!')return top = self.y.pop()self.x.push(top)print('go to %s' % top, end='\n')def backward(self):if self.x.isEmpty():print('can not backward!')returntop = self.x.pop()self.y.push(top)print('back to %s' % top, end='\n')def can_forward(self):if self.y.isEmpty():return Falsereturn Truedef can_back(self):if self.x.isEmpty():return Falsereturn Trueif __name__ == '__main__':b = Browser()for i in ['a', 'b', 'c']:b.view(i)while b.can_back():b.backward()while b.can_forward():b.forward()b.forward()

2.2 队列

所谓队列,就是一种先进先出的数据结构

2.2.1 用数组实现一个顺序队列

下面给出了一种最简单的实现方式,用front来记录队列首元素的位置,用rear来记录队列尾元素往后一个位置。入队列的时候只需要将待入队列放入下标为rear位置,然后同时执行rear+,那么出队列就是front+。

class MyQueue(object):"""队列"""def __init__(self):self.items = []self.front = 0  # 队列头self.rear = 0   # 队列尾def is_empty(self):"""判断队列是否为空"""return self.items == self.reardef enQueue(self, item):"""进队列,从队尾加入"""self.items.append(item)self.rear += 1# self.items.insert(0,item)     # 从对头进def deQueue(self):"""出队列,从队头出"""if self.rear > self.front:self.front += 1else:print("队列已经为空")# return self.items.pop()   # 从对尾出def getFront(self):if self.is_empty():return Nonereturn self.items[self.front]def getBack(self):if self.is_empty():return Nonereturn self.items[self.rear-1]def size(self):"""返回大小"""return self.rear - self.front# return len(self.items)    # 看大小

2.2.2 用链表实现一个链式队列

采用链表实现队列的方法与实现栈的方法类似,分别用两个指针指向队列的首元素与尾元素,而用pHead来指向队列的首元素,用pEnd来指向队列的尾元素。

class LNode(object):def __init__(self,x):self.data = xself.next = Noneclass MyQueue(object):def __init__(self):"""分配头结点"""self.pHead = Noneself.pEnd = Nonedef is_empty(self):"""判断是否为空"""if self.pHead == None:return Truereturn Falsedef size(self):"""获取队列的大小"""size=0p = self.pHeadwhile p != None:# while p is not None:p = p.nextsize += 1return sizedef enQueue(self, element):"""入队列,从队尾加"""p = LNode(element)p.data = elementp.next = Noneif self.pHead == None:self.pHead = self.pEnd=pelse:self.pEnd.next = pself.pEnd = pdef deQueue(self):"""出队列,删除首元素"""if self.pHead == None:print("出队列失败,队列已经为空")self.pHead = self.pHead.nextif self.pHead == None:self.pEnd = Nonedef getFront(self):"""返回队列首元素"""if self.pHead == None:print("获取队列首元素失败,队列已经为空")return Nonereturn self.pHead.datadef getBack(self):"""返回队列尾元素"""if self.pEnd == None:print("获取队列尾元素失败,队列已经为空")return Nonereturn self.pEnd.data

和栈中的优缺点类似,但与栈不同的是,对于队列,用链表的方式比数组更好,因为指针空间在这里的发挥空间更大。
2.2.3 实现一个循环队列
前面说的顺序队列显然不够高效,如果我们要实现所有操作都是O(1)时间,可以再设置一个指针,记住队头的位置,当出队操作完成后,更新队头指针。
基于上述思想,同时为了防止内存空置消耗,可以采用循环队列的实现。

# coding=utf-8
# @author: kaiyuan
# blog: https://blog.csdn.net/Kaiyuan_sjtu
from itertools import chainclass CirQueue:def __init__(self, capacity):self._items = []self._capacity = capacity + 1self._head = 0self._rear = 0def enqueue(self, elem):if (self._rear + 1) % self._capacity == self._head:return Falseself._items.append(elem)self._rear = (self._rear + 1) % self._capacityreturn Truedef dequeue(self):if self._head != self._rear:item = self._items[self._head]self._head = (self._head + 1) % self._capacityreturn itemdef __repr__(self):if self._rear >= self._head:return " ".join(item for item in self._items[self._head: self._rear])else:return " ".join(item for item in chain(self._items[self._head:], self._items[:self._rear]))if __name__ == '__main__':cq = CirQueue(10)for i in range(10):cq.enqueue(str(i))print(cq)for i in range(5):cq.dequeue()print(cq)

2.3 递归

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

class Solution:def Fibonacci(self, n):a = [0,1]if n<=1:return a[n]else:for i in range(2,n+1):a.append(a[i-1]+a[i-2])return a[n]

2.3.2 编程实现求阶乘 n!

def factorial(x):result = 1for i in xrange(2, x + 1):result *= ireturn result

2.3.3 编程实现一组数据集合的全排列
举个例子,比如你要对a,b,c三个字符进行全排列,那么它的全排列有abc,acb,bac,bca,cba,cab这六种可能,你们想想你们是如何得出这六种可能的。没错!就是当指针指向第一个元素a时,它可以是其本身a(即和自己进行交换),还可以和b,c进行交换,故有3种可能,当第一个元素a确定以后,指针移向第二位置,第二个位置可以和其本身b及其后的元素c进行交换,又可以形成两种排列,当指针指向第三个元素c的时候,这个时候其后没有元素了,此时,则确定了一组排列,输出。但是每次输出后要把数组恢复为原来的样子。
简单来说,它的思想即为,确定第1位,对n-1位进行全排列,确定第二位,对n-2位进行全排列。。。显然,这是一种递归的思想。

def permutations(arr, position, end):if position == end:print(arr)else:for index in range(position, end):arr[index], arr[position] = arr[position], arr[index]permutations(arr, position+1, end)arr[index], arr[position] = arr[position], arr[index]
arr = ["a","b","c"]
permutations(arr, 0, len(arr))

2.4 LeetCode练习题

2.4.1 有效括号

class Solution(object):def isValid(self, s):""":type s: str:rtype: bool"""if s is None:return Falsen = len(s)if n % 2 == 1:return Falsestack = []left = '([{'right = ')]}'lookup = { ')':'(', ']':'[', '}':'{'}for v in s:if v in left:stack.append(v)if v in right:if not stack:return Falsep = stack.pop()if p != lookup[v]:return Falsereturn stack == []

2.3.2 逆波兰表达式求值

遍历tokens里面的值,对于不是操作符op的项直接加入到栈stack中,当遇到op时,从栈中取出两个进行操作然后将操作后得到的结果再加入到stack里即可,直到遍历结束,返回stack中的值即可
这里需要注意的是,在做除法的时候,题目要求是除了以后返回商的整数部分

class Solution:def evalRPN(self, tokens):""":type tokens: List[str]:rtype: int"""stack = []for token in tokens:if token not in '+-*/':stack.append(int(token))else:r, l = stack.pop(), stack.pop()if token == '+':stack.append(r + l)elif token == '-':stack.append(l - r)elif token == '*':stack.append(r * l)else:stack.append(int(l / r))return stack.pop()

2.4.3 爬楼梯

递归

class Solution(object):def climbStairs(self, n):""":type n: int:rtype: int"""if n == 0:return 0if n == 1:return 1if n == 2:return 2return self.climbStairs(n-1) + self.climbStairs(n-2)

循环

class Solution:def climbStairs(self, n):""":type n: int:rtype: int"""if n < 3:return n dp = [1] * (n+1)for i in range(2, n+1):dp[i] = dp[i-1] + dp[i-2]return dp[-1]

2.4.4 滑动窗口最大值

最直观的就是暴力,时间复杂度: O(Nk)
我们可以尝试用队列维护一个大小为k的容器,然后每次求最大值后弹出压入循环做

class Solution(object):def maxSlidingWindow(self, nums, k):""":type nums: List[int]:type k: int:rtype: List[int]"""if not nums or len(nums) == 0:return []queue = []res = []for i in range(k):queue.append(nums[i])n = len(nums)for i in range(k, n):res.append(max(queue))queue.pop(0)queue.append(nums[i])res.append(max(queue))return res

3.参考链接

  1. https://blog.csdn.net/Kaiyuan_sjtu/article/details/88074508
  2. http://www.xuzhenggen.com/2019/03/03/栈、队列和递归的实现与总结/
  3. https://blog.csdn.net/qq_31601743/article/details/82053201

Datawhale编程学习之栈和队列(2)相关推荐

  1. java栈和队列实现删除,数据结构学习--Java栈和队列

    栈:先进后出 队列:先进先出 都是数组存放,但是删除的时候不是删除了数组中的数据,而是使用增加游标标识的方式实现删除,"游标标识"加加或者减减完成删除操作,查看的时候,也不是直接查 ...

  2. 数据结构学习笔记——栈和队列

    4 栈与队列   栈是限定仅在表尾进行插入和删除操作的线性表.队列是只允许在一端进行插入操作.而在另一端进行删除操作的线性表. 4.1 栈的定义 栈(stack)是限定仅在表尾进行插入和删除操作的线性 ...

  3. C语言/C++编程学习:栈的代码实现之数组方案

    C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构.C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现 ...

  4. 408数据结构学习笔记——栈和队列的应用、特殊矩阵的压缩

    目录 1.栈在括号匹配中的应用​ 2.栈在表达式求值中的运用 2.1.中缀表达式转换后缀表达式 2.2.后缀表达式的计算方法 2.3.中缀表达式转换前缀表达式 2.4. 中缀表达式转后缀表达式(机算- ...

  5. 《数据结构》实验三:栈和队列实验 (实验报告)

    一.实验目的 巩固栈和队列数据结构,学会运用栈和队列. 1.回顾栈和队列的逻辑结构和受限操作特点,栈和队列的物理存储结构和常见操作. 2.学习运用栈和队列的知识来解决实际问题. 3.进一步巩固程序调试 ...

  6. 10.数据结构:栈和队列

    大家好,我王有志又回来啦.关注王有志,回复DSA获取数据结构和算法学习资源. 最近被全链路优化搞得焦头烂额,等抽出时间来和大家分享下我司正在做的"全面提速工程". 今天我们来学习线 ...

  7. 啊哈算法浅识栈与队列

    栈与队列 最近学习了栈与队列 文章目录 栈与队列 队列(先进先出) 1.定义 2.解密qq号 栈(后进先出) 1.定义 2.解密回文 总结 队列(先进先出) 1.定义 队列是一种特殊的线性结构它只允许 ...

  8. 【数据结构】栈和队列OJ练习(栈和队列相互实现+循环队列实现)

    目录 前言 1.用队列实现栈 2.用栈实现队列 3.循环队列 前言 前面在学习了栈和队列的实现之后,相信大家对栈和队列的结构和使用方式都有了一些理解. 下面我们就来进行一些练习,这这章的练习相对于原来 ...

  9. java栈编程题_Java实现栈和队列面试题

    面试的时候,栈和队列经常会成对出现来考察.本文包含栈和队列的如下考试内容: (1)栈的创建 (2)队列的创建 (3)两个栈实现一个队列 (4)两个队列实现一个栈 (5)设计含最小函数min()的栈,要 ...

  10. 《数据结构C语言版》——栈和队列详解(图文并茂),从零开始的学习

    哈喽!这里是一只派大鑫,不是派大星.本着基础不牢,地动山摇的学习态度,从基础的C语言语法讲到算法再到更高级的语法及框架的学习.更好地让同样热爱编程(或是应付期末考试 狗头.jpg)的大家能够在学习阶段 ...

最新文章

  1. 为什么在反向传播中感知器初始值不能为0_人工智能可以为我们做什么?世界皆可二分类...
  2. opencv_contrib编译失败解决方法
  3. 评估微型计算机的主要指标,微型计算机的工作过程和主要性能指标.doc
  4. 正确判断js数据类型 总结记录
  5. 计算机三级之嵌入式系统学习笔记7
  6. 网络工程师应该掌握的知识要点
  7. LeetCode Number of Digit One
  8. 如何删除旧的和未使用的Docker映像
  9. linux下运行jar
  10. 新鲜出炉的自主协同操作系统研讨会纪要
  11. 远程控制别人计算机,如何远程控制别人的电脑?手把手教你远程操控别人的电脑!...
  12. AI数学基础之:P、NP、NPC问题
  13. 全新2021款 Jlink隔离器,ARM仿真器隔离,Jlink,Nu-link,ULINK的隔离,Cortex-M系列隔离仿真
  14. 儒家学派有哪些代表人物?
  15. App上架各大应用市场的地址及操作方法
  16. 纽约州立大学石溪分校计算机专业排名,纽约州立大学石溪分校美国大学排名及专业排名汇总(USNEWS美国大学排名版)...
  17. 我问自己代言,甄嬛篇
  18. vue 组件开发 ---- rui-vue-poster 海报制作
  19. 树莓派3B+使用GPIO实现串口通信
  20. C语言编程>第一周 ⑧ 输入两个正整数m和n,求其最大公约数和最小公倍数。

热门文章

  1. 学习完windows网络编程第一章后做的UDPTest程序
  2. Filter和interceptor比较
  3. Java测试代码及原理
  4. 十条jQuery代码片段助力Web开发效率提升
  5. Win7服务器搭建实例教程:教你Win7如何搭建Web服务器【转载】
  6. PHP Filesystem
  7. 算法导论2-4习题解答(合并排序算法)
  8. 随笔(2)——未来智能穿戴:把计算机“织”进纤维里
  9. 来不及说再见,Kobe
  10. STL中vector介绍