算法工程师第四十六天(110.字符串接龙 105.有向图的完全可达性 106.岛屿的周长 )

参考文献 代码随想录

一、字符串接龙

题目描述

字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序列:

1. 序列中第一个字符串是 beginStr。

2. 序列中最后一个字符串是 endStr。

3. 每次转换只能改变一个字符。

4. 转换过程中的中间字符串必须是字典 strList 中的字符串,且strList里的每个字符串只用使用一次。

给你两个字符串 beginStr 和 endStr 和一个字典 strList,找到从 beginStr 到 endStr 的最短转换序列中的字符串数目。如果不存在这样的转换序列,返回 0。

输入描述

第一行包含一个整数 N,表示字典 strList 中的字符串数量。 第二行包含两个字符串,用空格隔开,分别代表 beginStr 和 endStr。 后续 N 行,每行一个字符串,代表 strList 中的字符串。

输出描述

输出一个整数,代表从 beginStr 转换到 endStr 需要的最短转换序列中的字符串数量。如果不存在这样的转换序列,则输出 0。

输入示例
6
abc def
efc
dbc
ebc
dec
dfc
yhn
输出示例
4
提示信息

从 startStr 到 endStr,在 strList 中最短的路径为 abc -> dbc -> dec -> def,所以输出结果为 4,如图:

数据范围:

2 <= N <= 500

问题分析:要想找到beginStr到endStr的最短路径,那么而且每次改只能变换一个字母,相当于,只有差一个字母时就可以遍历,那么,我们该如何得到一个最短的路径呢。答案使用广度比较好,因为广度就是寻找最短路径的,那么图是什么呢,图其实就是题目给的字符串,我们要从beginStr开始进行构造,并且还要满足是什么条件呢,就是所构造出新的字符串必须出现在题目所给的字符串,问题来了,我们该如何统计路径长度呢?对吧,这里我们使用的是一个邻接表,例如这样的形式['d':[3,4]]这,用来干嘛呢,首先用来标记有没有被访问过,和存储路基,如果对应的路径长度发生了改变,那么就放问过了。如果新的字符串等于结束的字符串,那么直接返回。

# 广搜相对于深搜,总能率先找到目标点
# 深搜适合穷举所有可行路径
from collections import deque, defaultdict


def bfs(d_len, beginStr, endStr, strDic):
    res = 0
    dq = deque()
    dq.append((beginStr, 1))
    # 开始广搜
    while dq:
        tmp = dq.popleft()
        for i in range(len(tmp[0])):
            for j in range(26):
                ttmp = list(tmp[0])
                ttmp[i] = chr(j + ord("a"))  # 先换成对应的数字相加,然后在化为对应的子母
                ttmp = "".join(ttmp)
                if ttmp == endStr:  # 如果当前字符串等于最终的目标字符串,那么结束循环
                    return tmp[1] + 1  # 为什么要加一,因为还有算到最后字符串的长度
                # print(ttmp,endStr)
                if ttmp in strDic and strDic[ttmp] == 1: # 构造出的字符串必须是原数组中的元素,而且没有被访问过
                    strDic[ttmp] = 2
                    dq.append((ttmp, tmp[1] + 1))
                
            # print(dq)
    return 0
    
def main():
    d_len = int(input())
    beginStr, endStr = input().split()
    strDic = defaultdict()  #  使用的是临街表的形式,例如["ab":[3,5]],动态的
    for _ in range(d_len):  #
        strDic[input()] = 1
    res = bfs(d_len, beginStr, endStr, strDic)
    print(res)
    
if __name__ == "__main__":
    main()

二、有向图的完全可达性

题目描述

给定一个有向图,包含 N 个节点,节点编号分别为 1,2,...,N。现从 1 号节点开始,如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。

输入描述

第一行包含两个正整数,表示节点数量 N 和边的数量 K。 后续 K 行,每行两个正整数 s 和 t,表示从 s 节点有一条边单向连接到 t 节点。

输出描述

如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。

输入示例
4 4
1 2
2 1
1 3
2 4
输出示例
1
提示信息

从 1 号节点可以到达任意节点,输出 1。

数据范围:

1 <= N <= 100;
1 <= K <= 2000。

深搜:

n, k = map(int, input().split())
grid =  [[0] * (n + 1) for _ in range(n + 1)]
for i in range(k):
    x, y = map(int, input().split())
    grid[x][y] = 1
    
visited = [False] * (n + 1)

def dfs(start, n):
    for i in range(n + 1):
        if grid[start][i] == 1 and not visited[i]:
            visited[i] = True
            dfs(i,n)
            
visited[1] = True
dfs(1, n)
if visited.count(True) == n:
    print(1)
else:
    print(-1)

 广搜:

n, k = map(int, input().split())
grid =  [[0] * (n + 1) for _ in range(n + 1)]
for i in range(k):
    x, y = map(int, input().split())
    grid[x][y] = 1
    
visited = [False] * (n + 1)

def dfs(start, n):
    from collections import deque
    q = deque()
    q.append(start)
    while q:
        tmp = q.pop()
        for i in range(n + 1):
            if grid[tmp][i] == 1 and not visited[i]:
                visited[i] = True
                q.append(i)
                
visited[1] = True  # 为什么要初始化因为后面的有可能访问不到
dfs(1, n)
if visited.count(True) == n:
    print(1)
else:
    print(-1)

三、岛屿的周长

题目描述

给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿是被水包围,并且通过水平方向或垂直方向上相邻的陆地连接而成的。

你可以假设矩阵外均被水包围。在矩阵中恰好拥有一个岛屿,假设组成岛屿的陆地边长都为 1,请计算岛屿的周长。岛屿内部没有水域。

输入描述

第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。

输出描述

输出一个整数,表示岛屿的周长。

输入示例
5 5
0 0 0 0 0 
0 1 0 1 0
0 1 1 1 0
0 1 1 1 0
0 0 0 0 0
输出示例
14
提示信息

岛屿的周长为 14。

数据范围:

1 <= M, N <= 50。

图论:

n, m = map(int, input().split())
grid = []
grid.append([0] * (m + 2))
for i in range(n):
    tmp = list(map(int, input().split()))
    tmp.insert(0, 0)
    tmp.append(0)
    grid.append(tmp)
grid.append([0] * (m + 2))

visited = [[False] * (m + 2) for _ in range(n + 2)]
direction = [[1, 0],[-1, 0], [0, 1],[0, -1]]

res = 0
def dfs(x, y):
    global res
    for i, j in direction:
        next_x = x + i
        next_y = y + j
        if next_x < 0 or next_y < 0 or next_x > len(grid) or next_y > len(grid[0]):
            continue
        if grid[next_x][next_y] == 0:
            res += 1
        if grid[next_x][next_y] == 1 and not visited[next_x][next_y]:
            visited[next_x][next_y] = True
            dfs(next_x, next_y)

for i in range(n + 2):
    for j in range(m + 2):
        if grid[i][j] == 1 and not visited[i][j]:
            visited[i][j] = True
            dfs(i, j)
print(res)

不用图论:

n, m = map(int, input().split())
grid = []

for i in range(n):
    tmp = list(map(int, input().split()))
    grid.append(tmp)
visited = [[False] * (m) for _ in range(n)]
directions = [[1, 0],[-1, 0], [0, 1],[0, -1]]

res = 0
for i in range(n ):
    for j in range(m):
        if grid[i][j] == 1:
                for direction in  directions:      #// 上下左右四个方向
                    x = i + direction[0];
                    y = j + direction[1];    #// 计算周边坐标x,y
                    if (x < 0                      # // x在边界上
or x >= len(grid)     #// x在边界上
or y < 0                #// y在边界上
 or y >= len(grid[0]) # // y在边界上
                            or grid[x][y] == 0): #// x,y位置是水域
                        res += 1
print(res)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值