代码随想录算法训练营第五十四天|110.字符串接龙 、105.有向图的完全可达性 、106.岛屿的周长

110. 字符串接龙

def find_min_steps(beginStr, endStr, strSet):
    from collections import deque

    # 初始化队列,将开始字符串加入队列
    queue = deque([beginStr])
    # 初始化访问字典,记录字符串到开始字符串的步数
    visit_map = {beginStr: 1}

    while queue:
        word = queue.popleft()
        path = visit_map[word]

        # 对当前字符串的每个字符进行遍历
        for i in range(len(word)):
            # 遍历26个字母
            for j in range(26):
                # 替换当前字符
                new_word = word[:i] + chr(ord('a') + j) + word[i + 1:]
                # 如果新字符串与结束字符串相同
                if new_word == endStr:
                    print(path + 1)
                    return
                # 如果新字符串在集合中且未被访问过
                if new_word in strSet and new_word not in visit_map:
                    # 记录新字符串的步数,并加入队列
                    visit_map[new_word] = path + 1
                    queue.append(new_word)

    # 如果没有找到路径,输出0
    print(0)

def main():
    n = int(input().strip())
    beginStr, endStr = input().strip().split()
    strSet = set()
    for _ in range(n):
        strSet.add(input().strip())

    find_min_steps(beginStr, endStr, strSet)

if __name__ == "__main__":
    main()
  1. 使用 deque(双端队列)作为队列实现,将开始字符串加入队列。

  2. 使用 visit_map 字典记录每个字符串到开始字符串的最短步数。

  3. 当队列不为空时,执行循环。每次从队列中取出一个字符串,并获取其对应的步数。

  4. 遍历当前字符串的每个字符,然后遍历26个字母,尝试用每个字母替换当前位置的字符,生成新的字符串 new_word

  5. 如果 new_word 与结束字符串 endStr 相同,说明找到了最短路径,打印步数并结束函数。

  6. 如果 new_word 在字符串集合 strSet 中且未被访问过(不在 visit_map 中),则将其加入 visit_map 并将其加入队列。

  7. 如果循环结束后没有找到路径,则打印0。

  8. main 函数读取输入,初始化开始字符串、结束字符串和字符串集合 strSet

  9. 调用 find_min_steps 函数执行搜索。

105. 有向图的完全可达性

def dfs(graph, key, visited):
    # 如果已经访问过该节点,则直接返回
    if visited[key]:
        return
    visited[key] = True  # 标记当前节点为已访问
    # 遍历当前节点的所有邻接节点
    for neighbor in graph[key]:
        dfs(graph, neighbor, visited)  # 递归地进行深度优先搜索

def main():
    n, m = map(int, input().split())
    graph = [list() for _ in range(n + 1)]  # 使用列表的列表表示邻接表
    while m:
        s, t = map(int, input().split())
        graph[s].append(t)  # 构建图的邻接表,表示 s 到 t 的连接
        m -= 1

    visited = [False] * (n + 1)  # 初始化访问记录列表
    dfs(graph, 1, visited)  # 从节点 1 开始深度优先搜索

    # 检查是否所有节点都访问到了
    if False in visited[1:]:  # 从第二个元素开始检查,因为第一个元素默认为False
        print(-1)
    else:
        print(1)

if __name__ == "__main__":
    main()
  1. dfs 函数是一个递归函数,用于执行深度优先搜索(DFS)。它接受邻接表 graph、当前节点 key 和一个访问记录列表 visited

  2. 如果当前节点已经被访问过(visited[key]True),则直接返回,这是DFS的剪枝操作,避免循环。

  3. 将当前节点标记为已访问,并遍历当前节点的所有邻接节点。

  4. 对每个邻接节点,递归调用 dfs 函数,继续深度优先搜索。

  5. main 函数首先读取节点数 n 和边数 m

  6. 初始化邻接表 graph,使用列表的列表结构表示,长度为 n + 1(因为节点编号从1开始)。

  7. 通过循环读取每条边的信息,并构建图的邻接表。

  8. 初始化访问记录列表 visited,长度为 n + 1,所有元素初始为 False

  9. 调用 dfs 函数,从节点 1 开始执行深度优先搜索。

  10. 搜索完成后,检查 visited 列表,如果存在未访问的节点(False),则输出 -1 表示图中有未被访问的节点;否则,输出 1 表示所有节点都被访问到了。

106. 岛屿的周长

def main():
    n, m = map(int, input().split())  # 读取行数和列数
    grid = []  # 初始化网格列表
    for _ in range(n):
        grid.append(list(map(int, input().split())))  # 读取每行的陆地数据

    sum_ = 0  # 陆地数量
    cover = 0  # 相邻数量
    for i in range(n):  # 遍历每一行
        for j in range(m):  # 遍历每一列
            if grid[i][j] == 1:  # 检查当前位置是否是陆地
                sum_ += 1  # 统计总的陆地数量
                # 统计上边相邻陆地(避免越界)
                if i - 1 >= 0 and grid[i - 1][j] == 1:
                    cover += 1
                # 统计左边相邻陆地(避免越界)
                if j - 1 >= 0 and grid[i][j - 1] == 1:
                    cover += 1
                # 不需要统计下边和右边,因为每个格子的下边和右边将由下一行和下一列来统计

    print(sum_ * 4 - cover * 2)  # 计算并输出结果

if __name__ == "__main__":
    main()
  1. 使用列表推导式和 map 函数读取每行的陆地数据,并将每行数据转换为整数列表。

  2. 初始化两个计数器 sum_cover 分别用于统计陆地数量和相邻陆地数量。

  3. 使用两层嵌套循环遍历整个网格,外层循环遍历行,内层循环遍历列。

  4. 如果当前位置是陆地(grid[i][j] == 1),则 sum_ 加一。

  5. 检查当前陆地的上边和左边是否有相邻的陆地,并更新 cover 计数器。这里只检查上边和左边,因为下边和右边的相邻陆地将由对应的下一行和下一列来检查,避免重复计算。

  6. 最后,计算并打印结果。每个陆地单元格理论上有四个边界,但由于每个边界会被相邻的单元格共享两次(一次由当前单元格统计,一次由相邻的单元格统计),所以实际的边界总数是 sum_ * 4 - cover * 2

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值