编程总结
每每刷完一道题后,其思想和精妙之处没有地方记录,本篇博客用以记录刷题过程中的遇到的算法和技巧
79. 单词搜索_一刷 on 2025.11.08
思路:DFS遍历下去,都是套路
1)递归终止条件:越界、之前访问过、字符不相等
2)循环退出条件:字符长度已经和输入字符长度相等,返回true
3)逻辑处理,注意回溯的变量处理,赋值后,需要再减回来,visit数组
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

DFS
int gVisit[NUM_128][NUM_128] = {
0};
int gDirection[4][2] = {
{
0, -1}, {
0, 1}, {
1, 0}, {
-1, 0}};
int gBoardSize;
int *gBoardColSize;
char *gWord;
char **gBoard;
bool DFS(int i, int j, int idx)
{
if ((i < 0) || (j < 0) || (i >= gBoardSize) || (j >= *gBoardColSize)) {
return false;
}
if (gBoard[i][j] != gWord[idx]) {
return false;
}
if (gVisit[i][j] == 1) {
return false;
}
if ((idx + 1) == strlen(gWord)) {
return true;
}
gVisit[i][j] = 1;
for (int dir = 0; dir < 4; dir++) {
int nextX, nextY;
nextX = i + gDirection[dir][0];
nextY = j + gDirection[dir][1];
bool ret = DFS(nextX, nextY, idx + 1);
if (ret == true) {
return true;
}
}
gVisit[i][j] = 0;
return false;
}
bool exist(char **board, int boardSize, int *boardColSize, char *word)
{
gBoard = board;
gBoardSize = boardSize;
gBoardColSize = boardColSize;
gWord = word;
bool ret = false;
for (int i = 0; i < NUM_128; i++) {
memset(gVisit[i], 0, sizeof(int) * NUM_128);
}
for (int i = 0; i < boardSize; i++) {
for (int j = 0; j < *boardColSize; j++) {
if (board[i][j] == word[0]) {
ret = DFS(i, j, 0);
if (ret == true) {
return true;
}
}
}
}
return false;
}
int main()
{
char **board = (char **)malloc(sizeof(char *) * 5);
for (int i = 0; i < 4; i++) {
board[i] = (char *)malloc(sizeof(char) * 5);
}
strcpy(board[0], "ABCE");
strcpy(board[1], "SFCS");
strcpy(board[2], "ADEE");
int boardSize = 4;
int boardColSize = 4;
char word[7] = "ABCB";
bool ret = exist(board, boardSize, &boardColSize, word);
return 0;
}
BFS_部分通过_此题不建议使用
本题使用 BFS 并不适用,因为当前BFS的遍历不会回溯(将 gVisit 变量重新赋值0),会有如下情况导致部分用例Failed;
BFS更偏向无脑横向去遍历
1)访问到“C”时,此时会遍历访问两个“E”进队列,并标记已经访问过(由于目标此时就是匹配字符 “E”)

2)由于已经进队列并做了访问标记,并不会处理回溯,导致后续无法实现答案这种访问

int head = 0;
int tail = 0;
int gVisit[NUM_128][NUM_128] = {
0};
int gDirection[4][2] = {
{
0, -1}, {
0, 1}, {
1, 0}, {
-1, 0}};
int gBoardSize;
int *gBoardColSize;
char *gWord;
char **gBoard;
typedef struct Node {
int x;
int y;
} Node;
Node queue[NUM_128] = {
0};
bool BFS(int i, int j, int idx)
{
int step = 1;
while (head != tail) {
int tmpX = queue[head].x;
int tmpY = queue[head].y;
head = (head + 1) % NUM_128;
if ((step) == strlen(gWord)) {
return true;
}
for (int dir = 0; dir < 4; dir++) {
int nextX, nextY;
nextX = tmpX + gDirection[dir][0];
nextY = tmpY + gDirection[dir][1];
// 有效则进队列
if ((nextX >= 0) && (nextX < gBoardSize) && (nextY >= 0) && (nextY < *gBoardColSize) && (gVisit[nextX][nextY] == 0) && (gBoard[nextX][nextY] == gWord[step])) {
queue[tail].x = nextX;
queue[tail].y = nextY;
printf("queue %d %d %c\n", nextX, nextY, gBoard[nextX][nextY]);
tail = (tail + 1) % NUM_128;
gVisit[nextX][nextY] = 1;
}
}
step = step + 1;
}
return false;
}
bool exist(char **board, int boardSize, int *boardColSize, char *word)
{
gBoard = board;
gBoardSize = boardSize;
gBoardColSize = boardColSize;
gWord = word;
bool ret = false;
for (int i = 0; i < NUM_128; i++) {
memset(gVisit[i], 0, sizeof(int) * NUM_128);
}
for (int i = 0; i < boardSize; i++) {
for (int j = 0; j < *boardColSize; j++) {
if (board[i][j] == word[0]) {
queue[tail].x = i;
queue[tail].y = j;
gVisit[i][j] = 1;
tail = (tail + 1) % NUM_128;
printf("queue %d %d %c\n", i, j, gBoard[i][j]);
ret = BFS(i, j, 0);
if (ret == true) {
return true;
}
}
}
}
return false;
}
int main()
{
char **board = (char **)malloc(sizeof(char *) * 5);
for (int i = 0; i < 4; i++) {
board[i] = (char *)malloc(sizeof(char) * 5);
}
strcpy(board[0], "ABCE");
strcpy(board[1], "SFES");
strcpy(board[2], "ADEE");
int boardSize = 4;
int boardColSize = 4;
char word[11] = "ABCESEEEFS";
bool ret = exist(board, boardSize, &boardColSize, word);
return 0;
}
迷宫_基础
玩走迷宫的游戏.在一个n*m格子状的迷宫中,有一个入口S和多个出口E(一个迷宫中可能有多个出口,都用E表示).0表示这个格子可以走,1表示这个格子不可以走.小华希望可以最快的走出迷宫.每次只能走一步(在格子可以走的情况下,向上下左右移动一个格子), 他想让你计算最少的步数.
如:
1 0 1
0 S 1
0 0 E
输出2
如果无法到达出口输出 “No way”
思路:DFS遍历下去,都是套路
1)递归终止条件:越界、之前访问过、字符不相等
2)循环退出条件:字符长度已经和输入字符长度相等,返回true
3)逻辑处理,注意回溯的变量处理,赋值后,需要再减回来,visit数组
思路:通过DFS四个方向来做,gStep使用全局变量更新状态,step随递归深度进入到形参里
同时,加了gLen用于剪枝,gLen不为0时,同时超过之前存储的步数直接返回。
#define MAX_N 101
#define MAX_M 101
#define MAX_W 101
#define NUM_BIG 0x7FFFFFFF
char gMaze[MAX_N][MAX_M] = {
0}; // 二维矩阵,存储矩阵字符串
int gVisit[MAX_N][MAX_M] = {
0}; // 记录已经访问过的点,用int类型存储
int gLen[MAX_N][MAX_M] = {
0}; // 记录访问过的点的步数
int gResult = 0;
int gStep = NUM_BIG;
int gDirection[4][2] = {
{
1,0}, {
-1,0}, {
0,1}, {
0,-1}};
void DFS(int x, int y, int step, int n, int m)
{
// 如果已经满足条件,到达出口E,直接返回1,退出
if (gMaze[x][y] == 'E') {
gResult = step;
gStep = gStep < gResult ? gStep : gResult; // 更新step值
return ;
}
// 1.已经访问过该点,直接返回0,退出
if (gVisit[x][y] == 1) {
return ;
}
// 2.坐标越界,直接返回0,退出
if (x < 0 || y < 0 || x >= n || y >= m) {
return ;
}
// 3.格子不能走,直接返回0,退出
if (gMaze[x][y] == '1') {
return ;
}
// 4.剪枝,通过构造数组记录之前达到每一点需要的步数,如果超过可以步骤直接返回,不用再遍历
if (gLen[x][y] && gLen[x][y] <= step) {
// gLen不为空且step大于gLen
return ;
}
// 存贮步数点
gLen[x][y] = step;
// 标记为已访问点
gVisit[x][y] = 1;
// 以下上右左的顺序进行遍历查找
for (int i = 0; i < 4; i++) {
DFS(x + gDirection[i][

本文深入探讨了迷宫和岛屿主题的算法问题,包括单词搜索、迷宫基础与进阶、岛屿周长和数量计算等。通过DFS和BFS等技术,解析了各类问题的解决策略和代码实现细节。
最低0.47元/天 解锁文章
3154





