【刷题2025】数据结构初级(栈+双端队列+链表+树)

# 自定义一个数据类型
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) 栈和队列的基础理论

【刷题2025】数据结构初级(栈+双端队列+链表+树)_第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)解压报文

''&#

你可能感兴趣的:(数据结构,链表)