2024.6.29刷题记录

目录

一、22. 括号生成

1.dfs-枚举填左括号还是右括号

2.dfs-枚举下一个左括号的位置

二、26. 删除有序数组中的重复项

1.模拟

2.双指针

三、27. 移除元素

1.双指针

2.双指针优化

四、28. 找出字符串中第一个匹配项的下标

1.直接暴力匹配

2.kmp算法

五、842. 排列数字 - AcWing题库

dfs

 六、AcWing 843. n-皇后问题 - AcWing

dfs

七、844. 走迷宫 - AcWing题库

bfs

八、845. 八数码 - AcWing题库

bfs


一、22. 括号生成

1.dfs-枚举填左括号还是右括号

我想到了用dfs,但是边界写错了。来自灵神题解(. - 力扣(LeetCode))。

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        # dfs
        # 枚举填左括号还是右括号
        m = 2 * n
        ans = []
        path = ['' for _ in range(m)]
        def dfs(i: int, n_left: int) -> None:
            if i == m:
                ans.append(''.join(path))
                return
            if n_left < n:  # 可以填左括号
                path[i] = '('
                dfs(i + 1, n_left + 1)
            if i - n_left < n_left: # 可以填右括号
                # 右括号 < 左括号
                path[i] = ')'
                dfs(i + 1, n_left)
        dfs(0, 0)
        return ans

2.dfs-枚举下一个左括号的位置

来自灵神题解。

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        # dfs
        # 枚举下一个左括号的位置
        ans = []
        path = []   # 储存左括号的下标
        # balance = 左括号个数 - 右括号个数
        def dfs(i: int, balance: int) -> None:
            if len(path) == n:  # 左括号个数为n
                s = [')' for _ in range(2 * n)]
                for j in path:
                    s[j] = '('
                ans.append(''.join(s))
                return
            for n_right in range(balance + 1):
                # n_right在i后面添加的右括号个数
                path.append(i + n_right)
                # 填的右括号的后面一位即为左括号的位置
                dfs(i + n_right + 1, balance + 1 - n_right)
                path.pop()  # 注意pop,回溯
        dfs(0, 0)
        return ans

二、26. 删除有序数组中的重复项

1.模拟

当时没读懂题,原来是只考虑前k个数。

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        # 模拟
        n = len(nums)
        if n < 1: return 0
        ans = [nums[0]]
        cnt = 1
        pre = nums[0]
        for x in nums[1:]:
            if x != pre:
                ans.append(x)
                cnt += 1
                pre = x
        nums[:] = ans
        return cnt

2.双指针

来自题解(. - 力扣(LeetCode))。

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        # 双指针
        '''
        注意这里只考虑前k个数,nums 的其余元素与 nums 的大小不重要
        '''
        n = len(nums)
        if n == 0: return 0
        left, right = 0, 1
        while right < n:
            if nums[left] != nums[right]:
                left += 1
                # if left < right: nums[left] = nums[right]
                nums[left] = nums[right]
            right += 1
        return left + 1

三、27. 移除元素

1.双指针

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 双指针
        n = len(nums)
        left, right = -1, 0
        while right < n:
            if nums[right] != val:
                left += 1
                nums[left] = nums[right]
            right += 1
        return left + 1

2.双指针优化

思路来自官方题解(. - 力扣(LeetCode)),代码自写。return处只能使用right + 1,当最后位置left==right时,经过内层whle,right和left之间还有一个数;当数组全为val时,right=-1,left = 1,综上right+1处即为答案。

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 双指针优化
        # 可改变元素顺序,首尾双指针
        left, right = 0, len(nums) - 1
        while left <= right:
            # 闭区间
            if nums[left] == val:
                while nums[left] == val and left <= right:
                    nums[left] = nums[right]
                    right -= 1
            left += 1
        return right + 1

官方题解写法:

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        # 双指针优化
        # 可改变元素顺序,首尾双指针
        left, right = 0, len(nums) - 1
        while left <= right:
            # 闭区间
            if nums[left] == val:
                nums[left] = nums[right]
                right -= 1
            else:
                left += 1
        return left     # 这里使用left和right+1均可

四、28. 找出字符串中第一个匹配项的下标

1.直接暴力匹配

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        # 直接暴力匹配
        # 数据量不大
        n, m = len(haystack), len(needle)
        for i in range(0, n - m + 1):
            k, j = i, 0
            while j < m and haystack[k] == needle[j]:
                k += 1
                j += 1
            if j == m: return i
        return -1

2.kmp算法

class Solution:
    def build_next(self, patt: str) -> List[int]:
        # 构建next数组
        n = len(patt)
        if n == 0: return []
        res_next = [0] * n
        prefix_len = 0
        i = 1   # 第一个肯定为0,从1开始
        while i < n:
            if patt[i] == patt[prefix_len]:
                prefix_len += 1     # 先加一
                res_next[i] = prefix_len
                i += 1
            elif prefix_len == 0:
                    i += 1
            else:
                # 找到前一位的next值,跳转
                prefix_len = res_next[prefix_len - 1]
        return res_next
    
    def strStr(self, haystack: str, needle: str) -> int:
        # kmp算法
        nxt = self.build_next(needle)
        i, n = 0, len(haystack)     # 主串
        j, m = 0, len(needle)       # 子串
        while i < n:
            if haystack[i] == needle[j]:
                i += 1
                j += 1
            elif j > 0:
                j = nxt[j - 1]
            else:
                i += 1
            
            # 注意返回起始位置,此时的i在匹配串末尾
            if j == m: return i - j
        return -1

五、842. 排列数字 - AcWing题库

dfs

n = int(input())
flag = [0 for _ in range(n + 1)]    # 记录是否被选,0没选,1选
flag[0] = 1     # 不包括数字0
path = [0 for _ in range(n)]

def dfs(i: int) -> None:
    if i == n:
        # 到达边界
        for x in path:
            print(x, end = ' ')
        print()
        return 
    
    for j, x in enumerate(flag):
        if not x:
            path[i] = j     # 下标代表元素
            flag[j] = 1
            dfs(i + 1)
            flag[j] = 0

dfs(0)

 六、AcWing 843. n-皇后问题 - AcWing

dfs

不会,来自题解(AcWing 843. n-皇后问题--图解+代码注释 - AcWing)。注意其中斜线的表示方法。

n = int(input())
map = [['.' for _ in range(n)] for _ in range(n)]
col = [0 for _ in range(n)]     # 列标记
dg = [0 for _ in range(n * 2)]      # 左上到右下对角线,注意是2n
udg = [0 for _ in range(n * 2)]     # 左下到右上对角线

def dfs(i: int) -> None:
    # i表示行数
    if i == n:
        # 输出map
        for i in range(n):
            for j in range(n):
                print(map[i][j], end = '')
            print()     # 输出换行符
        print()     # 输出间隔空行
        return
    
    for j in range(n):
        if not col[j] and not dg[n - i + j] and not udg[i + j]:
            # 可以放置
            col[j] = dg[n - i + j] = udg[i + j] = 1
            map[i][j] = 'Q'
            dfs(i + 1)
            # 回
            col[j] = dg[n - i + j] = udg[i + j] = 0
            map[i][j] = '.'

dfs(0)

七、844. 走迷宫 - AcWing题库

bfs

不会,来自题解(AcWing 844.走迷宫 - AcWing --- AcWing 844. 走迷宫 - AcWing)。

# 最少移动次数->bfs
from collections import deque
def dfs() -> int:
    dx = [-1, 1, 0, 0]
    dy = [0, 0, 1, -1]
    
    q = deque([])
    q.append([0, 0])    # 起点入队
    mark[0][0] = 0
    while q:
        cur = q.popleft()
        for i in range(4):
            # 四个方向
            x = cur[0] + dx[i]
            y = cur[1] + dy[i]
            if 0 <= x < n and 0 <= y < m and not maze[x][y] and mark[x][y] == -1:
                # 可走且没被走过
                mark[x][y] = mark[cur[0]][cur[1]] + 1
                q.append([x, y])    # 新节点入队
    return mark[-1][-1]
    
if __name__ == '__main__':
    n, m = map(int, input().split())
    maze = [list(map(int, input().split())) for _ in range(n)]
    mark = [[-1 for _ in range(m)] for _ in range(n)]    # 记录到达(i, j)点的最少移动次数
    
    print(dfs())

八、845. 八数码 - AcWing题库

bfs

不会,来自题解(AcWing 845型。八数码 - AcWing --- AcWing 845. 八数码 - AcWing)。这道题的关键是:

1.使用字符串存储状态

2.使用字典来存储状态之间的距离

3.每一次更新状态后需要还原

# from sys import *
from collections import *
def dfs(start: str) -> int:
    # 使用字符串存储状态
    END = '12345678x'
    q = deque([])
    # mark = {}
    mark = defaultdict(lambda:0)
    
    q.append(start)
    mark[start] = 0
    
    dx = [0, 0, 1, -1]
    dy = [-1, 1, 0, 0]
    while q:
        cur = q.popleft()
        if cur == END: return mark[cur]
        
        # 寻找一维位置
        for idx, x in enumerate(cur):
            if x == 'x':
                break
            
        x, y = idx // 3, idx % 3
        for i in range(4):
            a, b = x + dx[i], y + dy[i]
            temp_state = list(cur)      # 还原状态
            if 0 <= a < 3 and 0 <= b < 3:
                temp_state[a * 3 + b], temp_state[idx] = temp_state[idx], temp_state[a * 3 + b]
                s = ''.join(temp_state)
                if s not in mark:
                    mark[s] = mark[cur] + 1
                    q.append(s)
    return -1

if __name__ == '__main__':
    start = ''.join(input().split())
    # start = stdin.readline().replace(" ", "").replace("\n", "")
    print(dfs(start))

感谢你看到这里!一起加油吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值