一、栈
(一)栈的思想
- 栈(有时称为“后进先出栈”)是一个项的有序集合,其中添加移除新项总发生在同一端。这一端通常称为“顶部”。与顶部对应的端称为“底部”。
- 栈的底部很重要,因为在栈中靠近底部的项是存储时间最长的。最近添加的项是最先会被移除的。这种排序原则有时被称为 LIFO,后进先出。它基于在集合内的时间长度做排序。较新的项靠近顶部,较旧的项靠近底部。
class Stack:
def __int__(self):
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)
def isEmpty(self):
return self.items == []
(二)代码
- Example 1
class Solution:
def trap(self, height: List[int]) -> int:
if len(height) <= 2:
return 0
ans,current,stack = 0,0,[]
while current < len(height):
while len(stack) != 0 and height[current] > height[stack[-1]]:
top = stack.pop()
if len(stack) == 0:
break
distance = current - stack[-1] -1
bounded_height = min(height[current],height[stack[-1]])-height[top]
ans = ans + distance * bounded_height
stack.append(current)
current = current+1
return ans
- Example 2
- 给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串 s ,判断字符串是否有效。
- 有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
class Solution:
def isValid(self, s: str) -> bool:
stack = []
for item in s:
if item == "(" or item == "[" or item == "{":
stack.append(item)
elif item == ")":
if len(stack) != 0 and stack[-1] == "(":
stack.pop()
else:
return False
elif item == "]":
if len(stack) != 0 and stack[-1] == "[":
stack.pop()
else:
return False
elif item == "}" :
if len(stack) != 0 and stack[-1] == "{":
stack.pop()
else:
return False
return len(stack) == 0
-
Example 3
- 具体做法是我们始终保持栈底元素为当前已经遍历过的元素中「最后一个没有被匹配的右括号的下标」,这样的做法主要是考虑了边界条件的处理,栈里其他元素维护左括号的下标:
- 对于遇到的每个‘(’,我们将它的下标放入栈中
对于遇到的每个‘)’,我们先弹出栈顶元素表示匹配了当前右括号:- 如果栈为空,说明当前的右括号为没有被匹配的右括号,我们将其下标放入栈中来更新我们之前提到的「最后一个没有被匹配的右括号的下标」
- 如果栈不为空,当前右括号的下标减去栈顶元素即为「以该右括号为结尾的最长有效括号的长度」
- 我们从前往后遍历字符串并更新答案即可。
- 需要注意的是,如果一开始栈为空,第一个字符为左括号的时候我们会将其放入栈中,这样就不满足提及的「最后一个没有被匹配的右括号的下标」,为了保持统一,我们在一开始的时候往栈中放入一个值为-1的元素。
class Solution:
def longestValidParentheses(self, s: str) -> int:
# 判断是不是空字符串
if not s:
return 0
res = 0
stack = [-1]
for i in range(len(s)):
if s[i] == "(":
# 把"("的index装进stack
stack.append(i)
else:
stack.pop()
if not stack:
# 如果stack是空的,就把")"的index装进stack
# 即把不合格的index放进stack
stack.append(i)
else:
res = max(res,i - stack[-1])
return res
二、队列
(一)队列的思想
- 队列是项的有序结合,其中添加新项的一端称为队尾,移除项的一端称为队首。当一个元素从队尾进入队列时,一直向队首移动,直到它成为下一个需要移除的元素为止。
- 最近添加的元素必须在队尾等待。集合中存活时间最长的元素在队首,这种排序成为 FIFO,先进先出,也被成为先到先得。
class Queue:
def __int__(self):
self.items = []
def isEmpty(self):
return len(self.items) == 0
def enqueue(self,item):
self.items.insert(0,item)
def dequeue(self):
return self.items.pop()
def size(self):
return len(self.items)
(二)双端队列(Deque)的思想
- deque(也称为双端队列)是与队列类似的项的有序集合。它有两个端部,首部和尾部,并且项在集合中保持不变。
- deque不同的地方是添加和删除项是非限制性的。可以在前面或后面添加新项。同样,可以从任一端移除现有项。在某种意义上,这种混合线性结构提供了单个数据结构中的栈和队列的所有能力。
class Deque:
def __int__(self):
self.items = []
def addFront(self,item):
self.items.insert(0,item)
def addRear(self,item):
self.items.append(item)
def removeFront(self):
self.items.pop(0)
def removeRear(self):
self.items.pop()
def isEmpty(self):
return len(self.items) == 0
def size(self):
return len(self.items)
(三) 代码
- 使用 deque 数据结构可以容易地解决经典回文问题。回文是一个字符串,读取首尾相同的字符,例如, radar toot madam 。
- 我们想构造一个算法输入一个字符串,并检查它是否是一个回文。
- 我们可以直接删除并比较首尾字符,只有当它们匹配时才继续。
- 如果可以持续匹配首尾字符,我们最终要么用完字符, 要么留出大小为 1 的deque,取决于原始字符串的长度是偶数还是奇数。
def palchecker(String):
Deque = []
for s in String:
Deque.append(s)
Judge = True
while len(Deque) > 1 and Judge:
left = Deque.pop(0)
right = Deque.pop()
if left != right:
Judge = False
return Judge
return Judge
print(palchecker("lsdkjfskf"))
print(palchecker("radar"))
三、列表
(一)列表的思想——ListNode
- 链表实现的基本构造块是节点。每个节点对象必须至少保存两个信息。首先,节点必须包含列表项本身。我们将这个称 为节点的数据字段。此外,每个节点必须保存对下一个节点的引用。
class Node:
def __int__(self,initData):
self.data = initData
self.next = None
def getData(self):
return self.data
def getNext(self):
return self.next
def setData(self,data):
self.data = data
def setNext(self,nextNode):
self.next = nextNode
- 无序列表将从一组节点构建,每个节点通过显式引用链接到下一个节点。只要我们知道在哪里找到第一个节点(包含第一个项),之后的每个项可以通过连续跟随下一个链接找到。考虑到这一点,UnorderedList 类必须保持对第一个节点的引用。Listing 2 显示了构造函数。注意,每个链表对象将维护对链表头部的单个引用。
class UnorderedList:
def __init__(self):
self.head = None
def isEmpty(self):
return self.head == None
def add(self,item):
temp = Node(item)
temp.setNext(self.head)
self.head = temp
def count(self):
current = self.head
num = 0
while current != None:
num = num + 1
current = current.getNext()
return num
def search(self,item):
current, isFind = self.head, False
while current != None and isFind == False:
if current.getData() == item:
isFind = True
else:
current = current.getNext()
return isFind
def remove(self,item):
current,previous,isRemove = self.head,None,False
while isRemove == False:
if current.getData() == Data:
isRemove = True
else:
previous = current
current = current.getNext()
if previous == None:
self.head = current.getNext()
else:
previous.setNext(current.getNext())
- 有序列表,我们必须记住项的相对位置是基于一些潜在的特性。
- 当我们考虑有序列表的操作时,我们应该注意,isEmpty和size方法可以与无序列表一样实现,因为它们只处理链表中的节点数量,而不考虑实际项值。同样, remove方法将正常工作,因为我们仍然需要找到该项,然后删除它。剩下的两个方法,search和add,将需要一些修改。
- 搜索无序列表需要我们一次遍历一个节点,直到找到我们正在寻找的节点或者没找到节点(None)。事实证明,相同的方法在有序列表也有效。然而,在项不在链表中的情况下,我们可以利用该顺序来尽快停止搜索。
class OrderList:
def __int__(self):
self.head = None
def isEmpty(self):
return self.head == None
def size(self):
current,num = self.head,0
while current != None:
num = num + 1
current = current.getNext()
return num
def remove(self,item):
current,previous,isRemove = self.head, None, False
while isRemove == False:
if current.getData() == item:
isRemove = True
else:
previous = current
current = current.getNext()
if previous == None:
self.head = current.getNext()
else:
previous.setNext(current.getNext())
def search(self,item):
current, isFind = self.head, False
while current != None and isFind == False:
if current.getData() == item:
isFind = True
else:
if item > current.getData():
break
else:
current = current.getNext()
return isFind
def add(self,item):
current, previous, Stop = self.head, None, False
while current != None and Stop == False:
if current.getData()>item:
Stop = True
else:
previous = current
current = current.getNext()
temp = Node(item)
if previous == None:
temp.setNext(self.head)
self.head = temp
else:
previous.setNext(temp)
temp.setNext(current)
(二)代码
- 给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
- 示例1:
- 输入:l1 = [2,4,3], l2 = [5,6,4]
- 输出:[7,0,8]
- 解释:342 + 465 = 807.
- 示例2:
- 输入:l1 = [0], l2 = [0]
- 输出:[0]
- 示例3:
- 输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
- 输出:[8,9,9,9,0,0,0,1]
- 示例1:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
res, left = ListNode(0), 0
re = res
while l1 != None or l2 != None:
x= l1.val if l1 else 0
y= l2.val if l2 else 0
s = x+y+left
left = s//10
re.next=ListNode(s%10)
re = re.next
if(l1!=None):l1=l1.next
if(l2!=None):l2=l2.next
if left != 0:
re.next = ListNode(1)
return res.next