- 第 166 篇 -
Date: 2026 - 02- 12 | 周四
Author: 郑龙浩(仟墨)
2026-02-12 周四 | 算法打卡day7
文章目录
-
- [2026-02-12 周四 | 算法打卡day7](#2026-02-12 周四 | 算法打卡day7)
10__卡码网110_字符串迁移
题目描述
字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序列:
-
序列中第一个字符串是 beginStr。
-
序列中最后一个字符串是 endStr。
-
每次转换只能改变一个字符。
-
转换过程中的中间字符串必须是字典 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
思路:
这道题没有说点与点之间是如何连接的,需要我们自己去处理点与点之间的连接
最大的疑惑:如何知道 某个字符串 连接的 是哪个字符串呢?
或者说,如何知道A点连接的是什么点?
BFS:
a. 初始化队列,将beginStr入队
b. 初始化visited[beginStr] = 1(起点本身算第一个节点)
c. 当队列不为空时循环
- 使用
unordered_set <strng> set去存储 strList(用于O(1)时间判断字符串是否存在) unordered_set <strng, int> visited记录每个字符串是否被访问过以及从起点到该字符串的路径长度- 然后使用26个字母轮番去替换每一个字符,存入new_word,判断new_word在strList中是否存在,
- 如果new_word == endStr,直接返回
path + 1(找到终点) - 如果
newWord在strSet中存在且 没有被访问过:visited[newWord] = path + 1- 将
newWord入队
本题是个无权图,使用深搜或者广搜就可以
建议使用BFS,因为BFS是一圈一圈去搜索,只要搜到了终点,就一定是最短路径
如果用DFS,会直接搜到最底,还要判断哪个是最短路径
【我的疑惑】:
同一个节点可能被从不同路径多次访问,并且这些路径的长度(如2和3)可能不同。但是BFS只记录了第一次访问时的路径长度(比如3),但后续存在一条更短的路径(比如2),那么path值记录的最短路径长度不就出错了吗?
- BFS是按层搜索,回显搜索所有距离为1的节点(第一层),假设是个波纹,也就是一个节点第一次被波纹触碰到时,它所在的"圈数"就是它距离起点的最短距离。
- 也就是一个节点,无论从哪条路径访问,都是属于同一层的,也就是长度都是一样的,所以,只需要记录第一次访问时的长度就可以了
【我的代码】
cpp
// Date: 2026-02-12 周四 Author:郑龙浩
// 10_卡码网110_字符串迁移
// 算法:BFS
#include "bits/stdc++.h"
using namespace std;
string beginStr, endStr;
unordered_set <string> strList;
int main(void) {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int N; cin >> N;
cin >> beginStr >> endStr;
string word;
// 将所有str存入strList中去
for (int i = 0; i < N; i ++) {
cin >> word;
strList.insert(word);
}
int path = 1; // 到达某节点word的最短长度
unordered_map <string, int> visited; // 存放访问过的String节点 到该节点的路径长度
visited.insert({beginStr, path});
queue <string> que;
que.push(beginStr); // 将第一个string节点存入que
// 启用BFS --> 不搜索当前word,而是搜索word的下一个new_word
// 也就是不对word进行判断,因为在que.push(new_word)前已经对其new_word合理性进行了
while (!que.empty()) {
string word = que.front(); // 取出que中当前处理的String
que.pop(); // 去掉front的char
// 【注意】我刚开始忘记写了
path = visited[word]; // 将path更新为到达word节点的最近的长度
int len = word.size(); //word 字符串 size
// 尝试替换每个字符(用26个字符依次替换某个字符)
// 替换索引i字符
for (int i = 0; i < len; i++) {
string new_word = word; // 存放新组成的单词
for (int j = 0; j < 26; j++) { // 每次只改变i处字符
new_word[i] = j + 'a';
if (new_word == endStr) { //如果找到了终点,此时就是最短路径
cout << path + 1;
return 0;
// 如果new_word在strList中 && 没访问过,就加入que中去,且标记为访问过+记录到该节点的路径长度
} else if (strList.find(new_word) != strList.end() && visited.find(new_word) == visited.end()){
que.push(new_word); // 将new_wor放入que待处理中
visited.insert({new_word, path + 1}); // 将new_word标记为访问过,并且记录到new_word这个节点的最短路径
}
}
}
}
cout << 0; // 如果beginStr无法转换为endstring才会直接输出0
return 0;
}
11_卡码网105_有向图的完全连通
**题目描述
给定一个有向图,包含 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 <= N <= 100;
1 <= K <= 2000。
cpp
// Date: 2026-02-12 周四 Author:郑龙浩
// 11_卡码网105_有向图的完全连通
// 算法:BFS
// 思路:
// 使用BFS或者DFS,从节点1搜索到节点N,只要搜索过,就用visied标记一下。\
最后遍历所有节点,如果visited中有false, 就是存在没有访问的节点,就输出-1,如果全都是true,就输出1
// 因为本题可能会出现节点多边少的情况,所以使用邻接表
// 如果使用矩阵,可能会存在浪费空间的情况
#include "bits/stdc++.h"
using namespace std;
// 从1开始搜索,直到最后
void dfs(vector <list <int>>& graph, vector <bool>& visited, int cur) {
if (visited[cur] == true) { // 如果当前节点访问过,就return
return;
}
visited[cur] = true; // 只要传入了cur且没访问过,既要将其标记访问
// 找到cur的下一个节点
list <int> nexts = graph[cur]; // 将cur连接的所有节点取出
for (int next : nexts) {
if (visited[next] == false) { // 如果next节点没被访问过,就dfs一下
dfs(graph, visited, next);
}
}
}
int main(void) {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int N, K;
cin >> N >> K;
vector <list <int>> graph(N + 1); // 邻接表
int s, t;
while (K--) {
cin >> s >> t;
graph[s].push_back(t); // 节点s可以指向节点t
}
vector <bool> visited(N + 1); // 访问过的
dfs(graph, visited, 1); // 使用dfs搜索所有连接的节点
for (int i = 1; i <= N; i++) {
// 只要有一个节点没有访问过,就直接输出-1,且return
if (visited[i] == false) {
cout << -1; return 0;
}
}
// 只要全都访问过,就会走到这一步,直接输出1
cout << 1;
return 0;
}