栈(Stack)
定义
- 栈是一种容器,其中添加移除新项总发生在同一端。这一端通常称为“顶部”。与顶部对应的端称为“底部”。
- 最重要特性:先进后出。这一特性让栈拥有反转元素顺序的功能。如下图:
用数组实现一个顺序栈
- 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)
用链表实现一个链式栈
- 为什么需要链式栈?
主要考虑顺序表的两个特点:1)扩大存储需要一次高代价操作;2)顺序表需要完整的大块存储区。
- 链式栈自然就以表头为栈顶
class ListNode:
def __init__(self, elem, next=None):
self.elem = elem
self.next = next
class LStack():
def __init__(self):
self._top = None
def isEmpty(self):
return self._top is None
def push(self, elem):
self._top = ListNode(elem, self._top)
def pop(self):
if self._top is None:
raise ValueError('wrong in pop!')
p = self._top
self._top = p.next
return p.elem
def peek(self):
if self._top is None:
raise ValueError('wrong in peek!')
return self._top.elem
def __repr__(self) -> str:
cur = self._top
nums = []
while cur:
nums.append(cur._data)
cur = cur._next
return "--> ".join(f"{num}" for num in nums)
if __name__ == '__main__':
stack = LStack()
for i in range(10):
stack.push(i)
print(stack)
编程模拟实现一个浏览器的前进、后退功能
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!')
return
top = self.x.pop()
self.y.push(top)
print('back to %s' % top, end='\n')
def can_forward(self):
if self.y.isEmpty():
return False
return True
def can_back(self):
if self.x.isEmpty():
return False
return True
if __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()
Leetcode栗子
- 20.Valid Parentheses
http://note.youdao.com/noteshare?id=060ed93ca5145cdb9f9f000468584a5a&sub=B5F79C070F704F229BCC2D7B0503CE8F - 150.Evaluate Reverse Polish
http://note.youdao.com/noteshare?id=301aab49bd4670990a050fe707e525ec&sub=844D15A999444DB4A71C709CCD7FACBF
队列(Queue)
定义
- 队列也是一种容器,其中最重要的特性就是先进先出。如下图:
用链表实现一个链式队列
- 最简单的单链表实现的话只能完成O(1)时间复杂度的enqueue操作和O(N)时间复杂度的dequeue操作,所以基于单链表的实现不太高效
- 如果要实现首尾都是O(1)的话,我们可以尝试双向链表
用数组实现一个顺序队列
- 基于python的list实现顺序队列,最直接的实现方法入队采取append(),出队采取pop(0),这样就得到一个O(1)时间复杂度的enqueue操作和O(N)时间复杂度的dequeue操作。
实现循环队列
- 前面说的顺序队列显然不够高效,如果我们要实现所有操作都是O(1)时间,可以再设置一个指针,记住队头的位置,当出队操作完成后,更新队头指针。
- 基于上述思想,同时为了防止内存空置消耗,可以采用循环队列的实现。
# coding=utf-8
# @author: kaiyuan
# blog: https://blog.csdn.net/Kaiyuan_sjtu
from itertools import chain
class CirQueue:
def __init__(self, capacity):
self._items = []
self._capacity = capacity + 1
self._head = 0
self._rear = 0
def enqueue(self, elem):
if (self._rear + 1) % self._capacity == self._head:
return False
self._items.append(elem)
self._rear = (self._rear + 1) % self._capacity
return True
def dequeue(self):
if self._head != self._rear:
item = self._items[self._head]
self._head = (self._head + 1) % self._capacity
return item
def __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)
队列栗子
- 239.Sliding Window Maximum
http://note.youdao.com/noteshare?id=452a2230fcaeabe561f36388e2b433ed&sub=70A2634D64344B1F98E230294E2FEAC3
递归
- 递归的思路就是将问题分解成更小的子问题,知道得到一个足够小的问题可以被很简单的解决。通常涉及调用函数自身。
- 所有的递归算法必须服从三个重要的定律:
- 必须具有基本情况,即算法停止递归的条件;
- 必须改变其状态并向基本情况靠近,即每一步问题的规模都变小;
- 必须以递归方式调用自身
- 递归实例: