# 自定义一个数据类型
class Stack:
def __init__(self):
self.stack = []
def push(self, item):
"""入栈"""
self.stack.append(item)
def pop(self):
"""出栈"""
if not self.is_empty():
return self.stack.pop()
else:
raise IndexError("栈为空,无法执行出栈操作")
def peek(self):
"""查看栈顶元素"""
if not self.is_empty():
return self.stack[-1]
else:
raise IndexError("栈为空,无法查看栈顶元素")
def is_empty(self):
"""判断栈是否为空"""
return len(self.stack) == 0
def size(self):
"""返回栈的大小"""
return len(self.stack)
def __str__(self):
return str(self.stack)
# 使用自定义栈类
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
print("当前栈:", stack) # 输出: 当前栈: [1, 2, 3]
print("栈顶元素:", stack.peek()) # 输出: 栈顶元素: 3
print("出栈元素:", stack.pop()) # 输出: 出栈元素: 3
print("当前栈:", stack) # 输出: 当前栈: [1, 2]
1.栈
(1) 栈和队列的基础理论

# 栈的常用操作
list.append() # 入栈
list.pop() # 出栈
list[-1] # 查看栈顶元素
len(list) # 判断栈是否为空
# 使用collections.deque实现栈降低操作时间复杂度
from collections import deque
# 初始化一个空栈
stack = deque()
# 入栈操作
stack.append(1) # 栈: [1]
stack.append(2) # 栈: [1, 2]
stack.append(3) # 栈: [1, 2, 3]
# 查看栈顶元素
top_element = stack[-1]
# 出栈操作
popped_element = stack.pop() # 弹出 3
# 判断栈是否为空
is_empty = not stack
(2)栈经典题目
①括号匹配
'''
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
'''
# 方法一,仅使用栈,更省空间
class Solution:
def isValid(self, s: str) -> bool:
stack = []
for item in s:
if item == '(':
stack.append(')')
elif item == '[':
stack.append(']')
elif item == '{':
stack.append('}')
elif not stack or stack[-1] != item:
return False
else:
stack.pop()
return True if not stack else False
# 方法二,使用字典
class Solution:
def isValid(self, s: str) -> bool:
stack = []
mapping = {
'(': ')',
'[': ']',
'{': '}'
}
for item in s:
if item in mapping.keys():
stack.append(mapping[item])
elif not stack or stack[-1] != item:
return False
else:
stack.pop()
return True if not stack else False
②字符串去重
'''
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
'''
# 方法一,使用栈
class Solution:
def removeDuplicates(self, s: str) -> str:
res = list()
for item in s:
if res and res[-1] == item:
res.pop()
else:
res.append(item)
return "".join(res) # 字符串拼接
# 方法二,使用双指针模拟栈,如果不让用栈可以作为备选方法。
class Solution:
def removeDuplicates(self, s: str) -> str:
res = list(s)
slow = fast = 0
length = len(res)
while fast < length:
# 如果一样直接换,不一样会把后面的填在slow的位置
res[slow] = res[fast]
# 如果发现和前一个一样,就退一格指针
if slow > 0 and res[slow] == res[slow - 1]:
slow -= 1
else:
slow += 1
fast += 1
return ''.join(res[0: slow])
③逆波兰表达式
(3)斗地主之顺子
'''
在斗地主扑克牌游戏中, 扑克牌由小到大的顺序为:3,4,5,6,7,8,9,10,J,Q,K,A,2,玩家可以出的扑克牌阵型有:单张、对子、顺子、飞机、炸弹等。
其中顺子的出牌规则为:由至少5张由小到大连续递增的扑克牌组成,且不能包含2。
例如:{3,4,5,6,7}、{3,4,5,6,7,8,9,10,J,Q,K,A}都是有效的顺子;而{J,Q,K,A,2}、 {2,3,4,5,6}、{3,4,5,6}、{3,4,5,6,8}等都不是顺子。
给定一个包含13张牌的数组,如果有满足出牌规则的顺子,请输出顺子。
如果存在多个顺子,请每行输出一个顺子,且需要按顺子的第一张牌的大小(必须从小到大)依次输出。
如果没有满足出牌规则的顺子,请输出No。
'''
card_arr = list(input().split())
dic = {"J":11, "Q":12, "K":13, "A":14, 11:"J", 12:"Q", 13:"K", 14:"A"}
card = []
for c in card_arr:
if c in dic:
card.append(dic[c])
else:
card.append(int(c))
card.sort()
def solve():
ans = []
used = [0 for _ in range(len(card))]
for l in range(len(card)-4):
if card[l] == 2:
continue
if used[l] == 1:
continue
a = dfs(l, used)
if a != -1:
ans.append(a)
for c in a:
used[c] = 1
if not ans:
print("No")
for a in ans:
for i in range(len(a)):
a[i] = card[a[i]]
if a[i] in dic:
a[i] = dic[a[i]]
else:
a[i] = str(a[i])
print(" ".join(a))
return
def dfs(l, used):
res = [l]
r = l
nextcard = card[l]+1
pre = card[l]
while r < len(card)-1:
if card[r+1] == pre or used[r+1] == 1:
r += 1
continue
if card[r+1] == nextcard:
r += 1
res.append(r)
nextcard = card[r]+1
pre = card[r]
else:
break
if len(res) < 5:
return -1
return res
solve()
# 另外一种解法:
# 遍历每一张牌,判断该张牌是否可以接在别的顺子后面,如果不能自己独立成为一个新顺子的开头
# 输入获取
cards = ['2', '9', 'J', '2', '3', '4', 'K', 'A', '7', '9', 'A', '5', '6']
# 将牌面映射为数字
def card2Num(card):
if card == "J":
return 11
elif card == "Q":
return 12
elif card == "K":
return 13
elif card == "A":
return 14
elif card == "2":
return 16
else:
return int(card)
# 算法入口
def getResult():
# 牌大小升序
cards.sort(key=lambda x: card2Num(x))
# 记录顺子
straights = []
for card in cards:
j = 0
while j < len(straights):
if card2Num(card) - card2Num(straights[j][-1]) == 1:
# 如果card牌面比顺子最后一张牌面大1,则可以拼接到该顺子尾部
straights[j].append(card)
break
j += 1
# 如果card无法拼接到已有顺子的尾部, 则重新建立一个顺子, 该顺子以card开头
if j == len(straights):
straights.append([card])
# 过滤出符合要求(牌数量>=5)的顺子
straights = list(filter(lambda x: len(x) >= 5, straights))
if len(straights) == 0:
# 如果没有满足出牌规则的顺子,请输出No
return "No"
else:
return "\n".join(map(lambda straight: " ".join(straight), straights))
# 输出打印
print(getResult())
(4)最长连续方波信号
'''
输入一串方波信号,求取最长的完全连续交替方波信号,并将其输出,如果有相同长度的交替方波信号,输出任一即可,方波信号高位用1标识,低位用0标识
说明:
一个完整的信号一定以0开始然后以0结尾,即010是一个完整信号,但101,1010,0101不是
输入的一串方波信号是由一个或多个完整信号组成
两个相邻信号之间可能有0个或多个低位,如0110010,011000010
同一个信号中可以有连续的高位,如01110101011110001010,前14位是一个具有连续高位的信号
完全连续交替方波是指10交替,如01010是完全连续交替方波,0110不是
'''
# 好累赘的解题思路
signal = list(map(int, input()))
def solve():
sig = [0, 0]
for i in range(1, len(signal)):
if signal[i] == 1:
l = i - 1
break
r = l + 1
flag = 1
pre = 0
while r < len(signal):
# 该信号结束
if pre == 0 and signal[r] == 0:
if flag:
if sig[1] - sig[0] < r - l:
sig[0] = l
sig[1] = r
flag = 1
pre = 0
while r < len(signal) and signal[r] == 0:
r += 1
l = r - 1
# 该信号违规
elif pre == 1 and signal[r] == 1:
pre = signal[r]
r += 1
flag = 0
# 正常遍历
else:
pre = signal[r]
r += 1
if r == len(signal):
if flag:
if sig[1] - sig[0] < r - l:
sig[0] = l
sig[1] = r
if sig == [0, 0]:
return -1
else:
return "".join(map(str, signal[sig[0]:sig[1]]))
print(solve())
# 怎么就没想起来用正则表达式!!!
import re
s = input() + "0"
ans = ""
reg = re.compile("^(01)+0$")
l, r = 0, 1
while r < len(s):
if s[r - 1] == '0' and s[r] == '0':
sub = s[l:r]
if reg.match(sub) and len(sub) > len(ans):
ans = sub
l = r
r += 1
print("-1" if len(ans) == 0 else ans)
(5)解压报文
''