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

一、110. 字符串接龙

题目连接:110. 字符串接龙 (kamacoder.com)

Leetcode链接:127. 单词接龙 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——110. 字符串接龙

思路:求最短路径——bfs。先判断点与点之间是否可以相连,如果两个点只差一个字符,那么可以相连,连接后找出最短路径,广搜找到的终点一定就是最短路径。

Note:无向图,需要记录字符串是否走过。

"""
BFS
"""
from collections import deque

def bfs(beginStr, endStr, strList):
    # 将字符串转换为集合方便查找
    strSet = set(strList)
    
    # 记录字符串是否被访问过及路径长度
    visiteMap = {beginStr: 1}
    
    # 初始化队列
    que = deque()
    que.append(beginStr)
    
    # 如果队列不为空
    while que:
        # 取出队列口元素
        word = que.popleft()
        # 获取当前字符串路径长度
        path = visiteMap[word]
        
        # 对字符串中每个字母进行替换
        for i in range(len(word)):
            # 遍历26个字母
            for j in range(26):
                # ord获取字母的ASIC码,chr将ASIC码返回字母字符
                newWord = word[:i] + chr(j + ord('a')) + word[i + 1:]
                
                # 检查 newWord 是否为结束字符串,返回路径长度+1
                if newWord == endStr:
                    return path + 1
                
                # 如果 newWord 在集合中且未被访问
                if newWord in strSet and newWord not in visiteMap:
                    # 记录新字符串的路径长度,并添加到队列
                    visiteMap[newWord] = path + 1
                    que.append(newWord)
                    
    # 未找到
    return 0

if __name__ == '__main__':
    n = int(input())
    beginStr, endStr = input().split()
    strList = [input().strip() for _ in range(n)]
    
    result = bfs(beginStr, endStr, strList)
    
    print(result)

二、105. 有向图的完全可达性

题目连接:105. 有向图的完全可达性 (kamacoder.com)
文章讲解:代码随想录 (programmercarl.com)——105. 有向图的完全可达性

思路:本题为有向图搜索全路径问题。

"""
DFS
写法一:终止条件部分,dfs 处理当前访问节点
"""
# 1. 确定递归函数,参数
# grid: 地图
# key: 当前需要处理的节点
# visited: 记录走过哪些房间
def dfs(grid, key, visited):
    # 2. 确定终止条件
    # case1. 处理当前节点,如果当前节点为True,即访问过,终止递归
    if visited[key]:
        return
    
    # 标记当前节点已访问
    visited[key] = True
    
    # 遍历邻接节点
    for keys in grid[key]:
        # dfs递归
        dfs(grid, keys, visited)
        
if __name__ == '__main__':
    n, m = map(int, input().split())

    # 创建邻接表,长度为 n + 1 ,且每个元素都初始成空列表。
    # 用 n + 1 是因为需要用到索引从 1 到 n。
    grid = [[] for _ in range(n + 1)]
    # 循环m次
    for _ in range(m):
        # 读取每一行的输入,将该行字符串分割成多个部分,int转换为整数
        s, t = map(int, input().split())
        # 在邻接表中,将节点 's' 的邻接表中添加节点 't' 
        grid[s].append(t)
        
    # 创建一个长度为 n + 1 的 False 列表
    visited = [False] * (n + 1)
    
    # 从节点1开始深搜
    dfs(grid, 1, visited)
    
    # 检查是否所有节点都被访问过,因为从1开始,不需要访问第一个节点
    for i in range(1, n + 1):
        # 如果有没访问的,说明不可以到达任何节点,返回-1
        if not visited[i]:
            print(-1)
            break
    else:
        print(1)
"""
DFS
写法二:dfs 处理下一个节点,注释的地方是和写法一不同的
"""
def dfs(grid, key, visited):
    # 直接进入循环
    for keys in grid[key]:
        # 确认下一个节点没访问过
        if not visited[keys]:
            visited[keys] = True
            dfs(grid, keys, visited)
            
if __name__ == '__main__':
    n, m = map(int, input().split())
    
    grid = [[] for _ in range(n + 1)]
    for _ in range(m):
        s, t = map(int, input().split())
        grid[s].append(t)
        
    visited = [False] * (n + 1)
    
    # 节点1预处理,设置成访问过
    visited[1] = True
    
    dfs(grid, 1, visited)
    
    for i in range(1, n + 1):
        if not visited[i]:
            print(-1)
            break
    else:
        print(1)
"""
BFS
"""
from collections import deque

def bfs(grid, key, visited):
    que = deque()
    que.append(key)
    
    while que:
        key = que.popleft()
        for keys in grid[key]:
            if not visited[keys]:
                que.append(keys)
                visited[keys] = True
        
if __name__ == '__main__':
    n, m = map(int, input().split())
    
    grid = [[] for _ in range(n + 1)]
    for _ in range(m):
        s, t = map(int, input().split())
        grid[s].append(t)
        
    visited = [False] * (n + 1)
    visited[1] = True
    
    bfs(grid, 1, visited)
    
    for i in range(1, n + 1):
        if not visited[i]:
            print(-1)
            break
    else:
        print(1)

三、106.岛屿的周长

题目连接:106. 岛屿的周长 (kamacoder.com)
文章讲解:代码随想录 (programmercarl.com)——106.岛屿的周长

思路1:遍历每一个空格,遇到岛屿则计算其上下左右空格情况,如果有水域则是一条边,如果出界了也是一条边。

"""
思路1:遍历每一个空格,遇到岛屿则计算其上下左右空格情况,
       如果有水域则是一条边,如果出界了也是一条边。
"""
def boundary(grid):
    # 行
    n = len(grid)
    # 列
    m = len(grid[0])
    
    dir = [(0, 1), (1, 0), (0, -1), (-1, 0)]
    
    result = 0
    
    for i in range(n):
        for j in range(m):
            # 如果是陆地,则遍历四个方向
            if grid[i][j] == 1:
                for k in dir:
                    # 计算周围坐标
                    x = i + k[0]
                    y = j + k[1]
                    # 如果在边界上,或者有水
                    if x < 0 or x >= n or y < 0 or y >= m or grid[x][y] == 0:
                        result += 1
                        
    return result
    
if __name__ == '__main__':
    n, m = map(int, input().split())
    
    grid = [list(map(int, input().split())) for _ in range(n)]
    
    result = boundary(grid)
    
    print(result)

思路2:计算出所有岛屿数量 * 4,得到所有岛屿边长,但是每两个岛屿相连,边长需要相应减2。需要统计所有岛屿数量 sum,相邻岛屿数量 cover,result = sum * 4 - cover * 2

"""
思路2:计算出所有岛屿数量 * 4,得到所有岛屿边长,但是每两个岛屿相连,边长需要相应减2。
       需要统计所有岛屿数量 sum,相邻岛屿数量 cover,result = sum * 4 - cover * 2
"""
def boundary(grid):
    # 行
    n = len(grid)
    # 列
    m = len(grid[0])
    
    dir = [(0, 1), (1, 0), (0, -1), (-1, 0)]
    
    # 统计所有岛屿数量
    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
    
    result = sum * 4 - cover * 2
    
    return result 
    
if __name__ == '__main__':
    n, m = map(int, input().split())
    
    grid = [list(map(int, input().split())) for _ in range(n)]
    
    result = boundary(grid)
    
    print(result)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值