Hot100——图论

岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。

示例 1:

输入:grid = [
  ['1','1','1','1','0'],
  ['1','1','0','1','0'],
  ['1','1','0','0','0'],
  ['0','0','0','0','0']
]
输出:1

示例 2:

输入:grid = [
  ['1','1','0','0','0'],
  ['1','1','0','0','0'],
  ['0','0','1','0','0'],
  ['0','0','0','1','1']
]
输出:3

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 300
  • grid[i][j] 的值为 '0' 或 '1'

dfs

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:

        def dfs(grid, i, j):
            if i < 0 or i >= len(grid) or j < 0 or j >= len(grid[0]):
                return
            if grid[i][j] == '0':
                return
            grid[i][j] = '0'
            dfs(grid, i + 1, j)
            dfs(grid, i - 1, j)
            dfs(grid, i, j + 1)
            dfs(grid, i, j - 1)

        count = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] == '1':
                    dfs(grid, i, j)
                    count += 1
        return count

bfs

class Solution:
    def numIslands(self, grid: List[List[str]]) -> int:

        def bfs(grid, i, j):
            q = [[i, j]]
            while q:
                [i, j] = q.pop(0)
                if 0 <= i < len(grid) and 0 <= j < len(grid[0]) and grid[i][j] == '1':
                    grid[i][j] = 0
                    q += [[i + 1, j], [i - 1, j], [i, j + 1], [i, j - 1]]

        count = 0
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] == '1':
                    bfs(grid, i, j)
                    count += 1
        return count

腐烂的橘子

在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:

  • 值 0 代表空单元格;
  • 值 1 代表新鲜橘子;
  • 值 2 代表腐烂的橘子。

每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。

返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1 。

示例 1:

输入:grid = [[2,1,1],[1,1,0],[0,1,1]]
输出:4

示例 2:

输入:grid = [[2,1,1],[0,1,1],[1,0,1]]
输出:-1
解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个方向上。

示例 3:

输入:grid = [[0,2]]
输出:0
解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 10
  • grid[i][j] 仅为 01 或 2

bfs

bfs可以求最短路径问题,本题就是求腐烂橘子到新鲜橘子的最短路径。

不过和普通的bfs不同的是,q的初始值不是放进一个点,而是很多点,因为不同位置的腐烂橘子会同时开始污染周围的新鲜橘子,都是同时进行的。

所以最开始是把数组中所有腐烂橘子放进队列q,作为第0层的节点,每次遍历的时候也要一层一层的把q中每个腐烂橘子的上下左右(注意边界判断)都遍历一遍。

由于存在无法被污染的橘子,所以最开始计算一下新鲜橘子的数量。bfs中。每遍历到一个新鲜橘子,新鲜橘子的数量就减1。如果最后bfs结束后新鲜橘子数量不为0,则说明有橘子无法被污染。

class Solution:
    def orangesRotting(self, grid: List[List[int]]) -> int:
        count = 0 #新鲜橘子的数量
        q = deque()
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if grid[i][j] == 1:
                    count += 1
                elif grid[i][j] == 2:
                    q.append([i, j])

        minute = 0
        while q and count:
            minute += 1 #分钟一定要在这里+1
            n = len(q) #这里提前记录q的长度,这是当前层的,不然后面q.append()len(q)一直在变
            for k in range(n): #bfs记录层数的时候需要这样的for循环
                [i, j] = q.popleft()
                if i - 1 >= 0 and grid[i - 1][j] == 1:
                    grid[i - 1][j] = 2
                    q.append([i - 1, j])
                    count -= 1
                if i + 1 < len(grid) and grid[i + 1][j] == 1:
                    grid[i + 1][j] = 2
                    q.append([i + 1, j])
                    count -= 1
                if j - 1 >= 0 and grid[i][j - 1] == 1:
                    grid[i][j - 1] = 2
                    q.append([i, j - 1])
                    count -= 1
                if j + 1 < len(grid[0]) and grid[i][j + 1] == 1:
                    grid[i][j + 1] = 2
                    q.append([i, j + 1])
                    count -= 1

        if count > 0:
            return -1
        else:
            return minute     

课程表

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程  bi 。

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。

示例 1:

输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。

示例 2:

输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
输出:false
解释:总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。

提示:

  • 1 <= numCourses <= 2000
  • 0 <= prerequisites.length <= 5000
  • prerequisites[i].length == 2
  • 0 <= ai, bi < numCourses
  • prerequisites[i] 中的所有课程对 互不相同

bfs拓扑排序

参考大佬解题思路:

综上:每门课的入度需要记录;课程之间的依赖关系也需要记录,即知道当前选课会减少哪些课程的入度。

初始入度用数组去记录,课程之间的依赖关系用哈希表记录(key是前序课程号,value是依赖于该前序课程的课程号)

bfs结束时,如果仍存在课程的入度不是0,则完成不了所有课

class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        indegree = [0] * numCourses #记录入度
        adj = defaultdict(list) #记录课程间依赖关系

        #更新入度和依赖关系
        for cur, pre in prerequisites:
            indegree[cur] += 1
            adj[pre].append(cur)

        #把入度为0的课程放入队列
        q = deque()
        for i in range(numCourses):
            if indegree[i] == 0:
                q.append(i)

        #开始bfs
        while q:
            pre = q.popleft()  #入度为0的课程逐个出队列
            numCourses -= 1 #未修读的课程数量减1
            for cur in adj[pre]:
                indegree[cur] -= 1 #依赖pre的课程入度减1
                if indegree[cur] == 0:
                    q.append(cur)

        return numCourses == 0

实现Trie(前缀树)

Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补全和拼写检查。

请你实现 Trie 类:

  • Trie() 初始化前缀树对象。
  • void insert(String word) 向前缀树中插入字符串 word 。
  • boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
  • boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。

示例:

输入
["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
输出
[null, null, true, false, true, null, true]

解释
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple");   // 返回 True
trie.search("app");     // 返回 False
trie.startsWith("app"); // 返回 True
trie.insert("app");
trie.search("app");     // 返回 True

提示:

  • 1 <= word.length, prefix.length <= 2000
  • word 和 prefix 仅由小写英文字母组成
  • insertsearch 和 startsWith 调用次数 总计 不超过 3 * 104 次

字典树(Trie树)

本题:二叉树变成二十六叉树

class Trie:

    def __init__(self):
        self.children = [None] * 26
        self.end = False

    def insert(self, word: str) -> None:
        node = self
        for ch in word:
            ch = ord(ch) - 97
            if not node.children[ch]:
                node.children[ch] = Trie()
            node = node.children[ch]
        node.end = True

    def search(self, word: str) -> bool:
        node = self
        for ch in word:
            ch = ord(ch) - 97
            if not node.children[ch]:
                return False
            node = node.children[ch]
        return node.end

    def startsWith(self, prefix: str) -> bool:
        node = self
        for ch in prefix:
            ch = ord(ch) - 97
            if not node.children[ch]:
                return False
            node = node.children[ch]
        return True


# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)

### 力扣热门100题列表 力扣(LeetCode)上的热门题目通常是指那些被广泛讨论、高频面试或者具有较高难度的题目。这些题目涵盖了数据结构和算法的核心知识点,适合用来提升编程能力和解决实际问题的能力。 以下是基于社区反馈整理的部分 **LeetCode Hot 100 Problems List**: #### 数组与字符串 1. Two Sum (两数之和)[^1] 2. Longest Substring Without Repeating Characters (无重复字符的最长子串)[^2] 3. Median of Two Sorted Arrays (两个有序数组的中位数)[^1] 4. Container With Most Water (盛最多水的容器)[^2] #### 链表 5. Reverse Linked List (反转链表) 6. Merge Two Sorted Lists (合并两个有序链表) 7. Remove Nth Node From End of List (删除倒数第N个节点) 8. Linked List Cycle II (环形链表II) #### 堆栈与队列 9. Valid Parentheses (有效的括号) 10. Min Stack (最小栈) 11. Sliding Window Maximum (滑动窗口最大值)[^2] #### 树与二叉树 12. Binary Tree Inorder Traversal (二叉树的中序遍历) 13. Validate Binary Search Tree (验证二叉搜索树) 14. Same Tree (相同的树) 15. Serialize and Deserialize Binary Tree (序列化与反序列化二叉树) #### 图论 16. Number of Islands (岛屿数量) 17. Course Schedule (课程表) 18. Clone Graph (克隆图) #### 排序与搜索 19. Find First and Last Position of Element in Sorted Array (在排序数组中查找元素的第一个和最后一个位置) 20. Search a 2D Matrix (二维矩阵搜索) 21. K Closest Points to Origin (最接近原点的K个点) #### 动态规划 22. Climbing Stairs (爬楼梯) 23. House Robber (打家劫舍)[^1] 24. Coin Change (零钱兑换) 25. Unique Paths (不同路径) #### 贪心算法 26. Jump Game (跳跃游戏)[^1] 27. Non-overlapping Intervals (无重叠区间) 28. Best Time to Buy and Sell Stock (买卖股票的最佳时机)[^1] #### 字符串匹配与处理 29. Implement strStr() (实现strStr()) 30. Longest Consecutive Sequence (最长连续序列) 31. Group Anagrams (分组异位词) --- ### 示例代码片段 以下是一个关于动态规划的经典例子——`Climbing Stairs` 的 Python 实现: ```python class Solution: def climbStairs(self, n: int) -> int: if n == 1 or n == 2: return n dp = [0] * (n + 1) dp[1], dp[2] = 1, 2 for i in range(3, n + 1): dp[i] = dp[i - 1] + dp[i - 2] return dp[n] ``` 上述代码通过动态规划的方式解决了 `Climbing Stairs` 问题,时间复杂度为 \(O(n)\),空间复杂度同样为 \(O(n)\)[^1]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值