算法试题(Python实现)dfs、矩阵路径

目录

1. 分糖果问题(贪心思想)

2. 主持人调度(二)(贪心思想)

3. N皇后问题(递归)

4. 岛屿数量(dfs)

5. 设计LRU缓存结构(哈希表+双向链表)

6. 设计LFU缓存结构(双哈希表)

7. 螺旋矩阵(边界模拟法)

8. 顺时针旋转矩阵(倒置翻转法)

9. 不同路径的数目(一)

10. 矩阵最长递增路径(dfs+DP)

11. 矩阵的最小路径和

12. 编辑距离(一)

13. ​​​​​​​旋转数组(平移数组:三次翻转法)


1. 分糖果问题(贪心思想)

单独遍历两次,先从左往右遍历(右边大的+1),再从右往左遍历(左边大的+1)

class Solution:
    def candy(self , arr: List[int]) -> int:
        # 记录每个位置的糖果数,每个孩子为默认为1
        nums = [1] * len(arr)
        # 从左到右遍历
        for i in range(1, len(arr)):
            # 如果右边大,则该位置糖果数为左边基础上加一
            if arr[i-1] < arr[i]:
                nums[i] = nums[i-1] + 1

        res = nums[len(arr) - 1]
        # 从右到左遍历
        for i in range(len(arr)-2, -1, -1):
            # 如果左边大且糖果数小,则该位置糖果数为右边基础上加一
            if arr[i] > arr[i+1] and nums[i] <= nums[i+1]:
                nums[i] = nums[i+1] + 1
            res += nums[i]
        return res

2. 主持人调度(二)(贪心思想)

排序+遍历(新开始的节目大于等于上一轮结束的时间,主持人不变,否则主持人+1)

class Solution:
    def minmumNumberOfHost(self , n: int, startEnd: List[List[int]]) -> int:
        start = []
        end = []
        for i in range(n):
            start.append(startEnd[i][0])
            end.append(startEnd[i][1])
        start.sort()
        end.sort()
        res = 0
        j = 0
        for i in range(n):
            # 新开始的节目大于等于上一轮结束的时间,主持人不变
            if start[i] >= end[j]:
                j += 1
            else:
                # 主持人+1
                res += 1
        return res

3. N皇后问题(递归)

class Solution:
    # 判断皇后是否符合条件
    def isValid(self, pos: List[int], row: int, col: int):
        # 遍历记录过的行
        for i in range(row):
            if row == i or col == pos[i] or abs(row-i) == abs(col-pos[i]):
                return False
        return True
    
    # 递归查找皇后种类
    def recursion(self, n: int, row: int, pos: List[int], res: int):
        if row == n:
            res += 1
            return res
        for i in range(n):
            if self.isValid(pos, row, i):
                pos[row] = i
                res = self.recursion(n, row + 1, pos, res)
        return res
        
    def Nqueen(self , n: int) -> int:
        res = 0
        # 下标为行号,元素为列号,记录皇后位置
        pos = [0]*n
        # 递归
        result = self.recursion(n, 0, pos, res)
        return result

4. 岛屿数量(dfs)

class Solution:
    # 深度优先遍历
    def dfs(self, grid: List[List[chr]], i: int, j: int):
        n = len(grid)
        m = len(grid[0])
        grid[i][j] = '0'
        if i - 1 >= 0 and grid[i-1][j] == '1':
            self.dfs(grid, i-1, j)
        if i + 1 < n and grid[i+1][j] == '1':
            self.dfs(grid, i+1, j)
        if j - 1 >= 0 and grid[i][j-1] == '1':
            self.dfs(grid, i, j-1)
        if j + 1 < m and grid[i][j+1] == '1':
            self.dfs(grid, i, j+1)

    def solve(self , grid: List[List[str]]) -> int:
        n = len(grid)
        if n == 0: return 0
        m = len(grid[0])
        count = 0
        for i in range(n):
            for j in range(m):
                if grid[i][j] == '1':
                    count += 1
                    self.dfs(grid, i, j)
        return count

5. 设计LRU缓存结构(哈希表+双向链表)

使用数组实现

class Solution:
    def __init__(self, capacity: int):
        self.capacity = capacity
        self.q = []

    def get(self, key: int) -> int:
        flag = True
        for i in range(len(self.q)):
            if self.q[i][0] == key:
                res = self.q[i][1]
                self.q.append(self.q.pop(i))
                flag = False
                break
        return -1 if flag else res

    def set(self, key: int, value: int) -> None:
        flag = True
        hasKey = False
        if len(self.q) >= self.capacity:
            for i in range(len(self.q)):
                if self.q[i][0] == key:
                    self.q.pop(i)
                    flag = False
                    break
            if flag:
                self.q.pop(0)
        for i in range(len(self.q)):
            if self.q[i][0] == key:
                self.q[i][1] = value
                hasKey = True
        if not hasKey:
            self.q.append([key, value])
        return None

使用双向链表+双向链表实现。用哈希表的key值对应链表的节点。

# 构建双向链表结点
class Node:
    def __init__(self, key, value):
        self.key = key
        self.value = value
        self.pre = None
        self.next = None

class Solution:
    # 约定:链表尾的元素最新
    def __init__(self, capacity: int):
        self.capacity = capacity
        # 双向链表头尾
        self.head = Node(-1,-1)
        self.tail = Node(-1,-1)
        self.head.next = self.tail
        self.tail.pre = self.head
        # 哈希表记录Node
        self.map = dict()

    # 获得当前大小
    def getSize(self) -> int:
        cur = self.head.next
        res = 0
        while cur != self.tail:
            cur = cur.next
            res += 1
        return res

    # 表尾插入新元素
    def insert(self, node: Node):
        node.pre = self.tail.pre
        node.next = self.tail
        self.tail.pre.next = node
        self.tail.pre = node
        
    # 移至表尾
    def moveToTail(self, node: Node):
        node.pre.next = node.next
        node.next.pre = node.pre
        self.insert(node)
    
    # 移除表头元素
    def moveHead(self):
        self.map.pop(self.head.next.key)
        self.head.next.next.pre = self.head
        self.head.next = self.head.next.next
    
    def get(self, key: int) -> int:
        res = -1
        if key in self.map:
            res = self.map[key].value
            self.moveToTail(self.map[key])
        return res

    def set(self, key: int, value: int) -> None:
        if key in self.map:
            self.moveToTail(self.map[key])
            self.map[key].value = value
        else:
            if self.getSize() >= self.capacity:
                self.moveHead()
            node = Node(key, value)
            self.map[key] = node
            self.insert(node)

6. 设计LFU缓存结构(双哈希表)

import collections
class Node:
    def __init__(self, freq, key, val):
        self.freq = freq
        self.key = key
        self.val = val
        
class Solution:
    def __init__(self):
        #记录剩余空间
        self.size = 0
        #key到双向链表节点的哈希表
        self.mp = dict()
        #频率到链表的哈希表
        self.freq_mp = dict(collections.deque())
        #记录当前最小频次
        self.min_freq = 0
    
    #调用函数时更新频率或者val值
    def update(self, node: Node, key: int, value: int): 
        #找到频率
        freq = node.freq
        #原频率中删除该节点
        self.freq_mp[freq].remove(node) 
        #哈希表中该频率已无节点,直接删除
        if len(self.freq_mp[freq]) == 0: 
            self.freq_mp.pop(freq)
            #若当前频率为最小,最小频率加1
            if self.min_freq == freq: 
                self.min_freq += 1
        #插入频率加一的双向链表表头,链表中对应:freq key value
        node = Node(freq + 1, key, value)
        if freq + 1 not in self.freq_mp:
            self.freq_mp[freq + 1] = collections.deque()
        self.freq_mp[freq + 1].appendleft(node)
        self.mp[key] = self.freq_mp[freq + 1][0]
    
    #set操作函数
    def set(self, key:int, value: int):
        #在哈希表中找到key值
        if key in self.mp:
            #若是哈希表中有,则更新值与频率
            self.update(self.mp[key], key, value)
        else:
            #哈希表中没有,即链表中没有
            if self.size == 0:
                #满容量取频率最低且最早的删掉
                oldnode = self.freq_mp[self.min_freq].pop() 
                #频率哈希表的链表中删除
                if len(self.freq_mp[self.min_freq]) == 0:
                    self.freq_mp.pop(self.min_freq) 
                #链表哈希表中删除
                self.mp.pop(oldnode.key)
            #若有空闲则直接加入,容量减1
            else: 
                self.size -= 1
            #最小频率置为1
            self.min_freq = 1
            node = Node(1, key, value)
            if 1 not in self.freq_mp:
                self.freq_mp[1] = collections.deque()
            self.freq_mp[1].appendleft(node)
            #哈希表key值指向链表中该位置
            self.mp[key] = self.freq_mp[1][0]
            
    #get操作函数
    def get(self, key: int) -> int:
        res = -1
        #查找哈希表
        if key in self.mp:
            node = self.mp[key]
            #根据哈希表直接获取值
            res = node.val
            #更新频率 
            self.update(node, key, res)
        return res

    def LFU(self , operators: List[List[int]], k: int) -> List[int]:
        res = []
        #构建初始化连接
        #链表剩余大小
        self.size = k
        #遍历所有操作
        for i in range(len(operators)):
            op = operators[i]
            if op[0] == 1: 
                #set操作
                self.set(op[1], op[2])
            else:
                #get操作
                res.append(self.get(op[1]))
        return resnd(self.get(op[1]))
        return res

7. ​​​​​​​螺旋矩阵(边界模拟法)

class Solution:
    def spiralOrder(self , matrix: List[List[int]]) -> List[int]:
        res = []
        n = len(matrix)
        if n == 0: return res
        # 上下左右边界
        left = 0
        right = len(matrix[0]) - 1
        up = 0
        down = n - 1
        while left <= right and up <= down:
            # 上边界的从左到右
            for i in range(left, right + 1):
                res.append(matrix[up][i])
            # 上边界下移
            up += 1
            if up > down: break
            # 右边界的从上到下
            for i in range(up, down + 1):
                res.append(matrix[i][right])
            # 右边界左移
            right -= 1
            if left > right: break
            # 下边界的从右到左
            for i in range(right, left - 1, -1):
                res.append(matrix[down][i])
            # 下边界上移
            down -= 1
            if up > down: break
            # 左边界的从下到上
            for i in range(down, up - 1, -1):
                res.append(matrix[i][left])
            # 左边界右移
            left += 1
            if left > right:
                break
        return res

8. 顺时针旋转矩阵(倒置翻转法)

class Solution:
    def rotateMatrix(self , mat: List[List[int]], n: int) -> List[List[int]]:
        # 矩阵转置
        for i in range(n):
            for j in range(i):
                # 交换上三角与下三角对应的元素
                mat[i][j], mat[j][i] = mat[j][i], mat[i][j]
        # 每行翻转
        for i in range(n):
            mat[i].reverse()
        return mat

9. 不同路径的数目(一)

class Solution:
    def uniquePaths(self , m: int, n: int) -> int:
        dp = [[0] * (n+1) for i in range(m + 1)]
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if i == 1:
                    dp[i][j] = 1
                    continue
                if j == 1:
                    dp[i][j] = 1
                    continue
                dp[i][j] = dp[i-1][j] + dp[i][j-1]
        return dp[m][n]

10. 矩阵最长递增路径(dfs+DP)

class Solution:
    global dirs
    dirs = [[-1, 0], [1, 0], [0, -1], [0, 1]]
    global n, m
    # 深度优先搜索,返回最大单元格数
    def dfs(self, matrix: List[List[int]], dp: List[List[int]], i: int, j: int):
        if dp[i][j] != 0:
            return dp[i][j]
        dp[i][j] += 1
        for k in range(4):
            nexti = i + dirs[k][0]
            nextj = j + dirs[k][1]
            if nexti >= 0 and nexti < n and nextj >= 0 and nextj < m and matrix[nexti][nextj] > matrix[i][j]:
                dp[i][j] = max(dp[i][j], self.dfs(matrix, dp, nexti, nextj) + 1)
        return dp[i][j]
    def solve(self , matrix: List[List[int]]) -> int:
        global n, m
        if len(matrix) == 0 or len(matrix[0]) == 0:
            return 0
        res = 0
        n = len(matrix)
        m = len(matrix[0])
        dp = [[0 for col in range(m)] for row in range(n)]
        for i in range(n):
            for j in range(m):
                res = max(res, self.dfs(matrix, dp, i, j))
        return res

11. 矩阵的最小路径和

class Solution:
    def minPathSum(self, matrix: List[List[int]]) -> int:
        n = len(matrix)
        # 因为n,m均大于等于1
        m = len(matrix[0])
        # dp[i][j]表示以当前i,j位置为终点的最短路径长度
        dp = [[0] * (m + 1) for i in range(n + 1)]
        dp[0][0] = matrix[0][0]
        # 处理第一列
        for i in range(1, n):
            dp[i][0] = matrix[i][0] + dp[i - 1][0]
        # 处理第一行
        for j in range(1, m):
            dp[0][j] = matrix[0][j] + dp[0][j - 1]
        # 其他按照公式来
        for i in range(1, n):
            for j in range(1, m):
                if dp[i - 1][j] > dp[i][j - 1]:
                    dp[i][j] = matrix[i][j] + dp[i][j - 1]
                else:
                    dp[i][j] = matrix[i][j] + dp[i - 1][j]
        return dp[n - 1][m - 1]

12. 编辑距离(一)

class Solution:
    def editDistance(self, str1: str, str2: str) -> int:
        n1 = len(str1)
        n2 = len(str2)
        # dp[i][j]表示到str1[i]和str2[j]为止的子串需要的编辑距离
        dp = [[0] * (n2 + 1) for i in range(n1 + 1)]
        # 初始化边界
        for i in range(1, n1 + 1):
            dp[i][0] = dp[i - 1][0] + 1
        for i in range(1, n2 + 1):
            dp[0][i] = dp[0][i - 1] + 1
        # 遍历第一个字符串的每个位置
        for i in range(1, n1 + 1):
            # 对应第二个字符串每个位置
            for j in range(1, n2 + 1):
                # 若是字符相同,此处不用编辑
                if str1[i - 1] == str2[j - 1]:
                    # 直接等于二者前一个的距离
                    dp[i][j] = dp[i - 1][j - 1]
                else:
                    # 选取最小的距离加上此处编辑距离1
                    dp[i][j] = (
                        min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1
                    )
        return dp[n1][n2]

13. ​​​​​​​旋转数组(平移数组:三次翻转法)

class Solution:
    def solve(self , n: int, m: int, a: List[int]) -> List[int]:
        # 取余,因为每次长度为n的旋转数组相当于没有变化
        m = m % n
        # 第一次 逆转全部数组元素
        a.reverse()
        b = a[:m]
        # 第二次 逆转开头m个
        b.reverse()
        c = a[m:]
        # 第三次 只逆转结尾n-m个
        c.reverse()
        a[:m] = b
        a[m:] = c
        return a

猜你喜欢

转载自blog.csdn.net/qq_52057693/article/details/128882268
今日推荐