C++力扣Leetcode算法5--搜索

1.深度优先遍历(depth-first-search),遇到新节点就遍历下去。因此遍历需要用先入后出的栈来实现,也可以通过与栈等价的递归来实现。

        深度优先搜索也可以用来检测环路:记录每个遍历过的节点的父节点,若一个节点被再次遍历且父节点不同,则说明有环。我们也可以用拓扑排序判断是否有环路,若最后存在入度不为零的点,则说明有环。 有时我们可能会需要对已经搜索过的节点进行标记,以防止在遍历时重复搜索某个节点,这 种做法叫做状态记录或记忆化(memoization)。

        一般来说,深度优先搜索类型 的题可以分为主函数和辅函数,主函数用于遍历所有的搜索位置,判断是否可以开始搜索,如果 可以即在辅函数进行搜索。辅函数则负责深度优先搜索的递归调用。

2. 广度优先遍历(BFS),先访问起始顶点,然后依次访问起始顶点的领接顶点,再依次访问领接顶点的领接顶点,直到访问完,还有顶点没被访问,重复上述步骤,直到全部顶点都被访问。

        利用队列实现搜索。通常解决最短路线问题。

3. 回溯法,又称为试探法,常用于需要记录节点状 态的深度优先搜索。通常来说,排列、组合、选择类问题使用回溯法比较方便。

        在搜索到某一节点的时候,如果我们发现目前的节点(及 其子节点)并不是需求目标时,我们回退到原来的节点继续搜索,并且把在目前节点修改的状态还原。这样的好处是我们可以始终只对图的总状态进行修改,而非每次遍历时新建一个图来储存状态。在具体的写法上,它与普通的深度优先搜索一样,都有 [修改当前节点状态]→[递归子节点] 的步骤,只是多了回溯的步骤,变成了 [修改当前节点状态][递归子节点][回改当前节点状态]。

        记住两个小诀窍,一是按引用传状态,二是所有的状态修改在递归完成后回改。

        回溯法修改一般有两种情况,一种是修改最后一位输出,比如排列组合;一种是修改访问标记,比如矩阵里搜字符串。

        回溯法通常用最简单的递归方法来实现。

695 岛屿的最大面积

给你一个大小为 m x n 的二进制矩阵 grid 。岛屿 是由一些相邻的 1 (代表土地) 构成的组合,这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0(代表水)包围着。岛屿的面积是岛上值为 1 的单元格的数目。计算并返回 grid 中最大的岛屿面积。如果没有岛屿,则返回面积为 0 。
书中最优解 栈
对于四个方向的遍历,可以创造一个数组 [-1, 0, 1, 0, -1],每相邻两位即为上右下左四个方向之一,-1,0是向上。按数组走的
一种是先判定是否越界,只有在合法的情况下才进行下一步搜索
vector<int> direction{ -1, 0, 1, 0, -1 };
// 主函数
int maxAreaOfIsland(vector<vector<int>>& grid) {
	if (grid.empty() || grid[0].empty()) return 0;
	int max_area = 0;
	for (int i = 0; i < grid.size(); ++i) {
		for (int j = 0; j < grid[0].size(); ++j) {
			//遇到岛屿 调用dfs将相连的岛屿遍历并统计面积
			//将最大面积的岛屿 赋给max_area
			if (grid[i][j] == 1) {
				max_area = max(max_area, dfs(grid, i, j));
			}
		}
	}
	return max_area;
}
// 辅函数
int dfs(vector<vector<int>>& grid, int r, int c) {
	//判断边界,判断是否到海洋
	if (grid[r][c] == 0) return 0;
	//为了确保每个土地访问不超过一次,我们每次经过一块土地时,将这块土地的值置为 0。这样我们就不会多次访问同一土地。
	grid[r][c] = 0;
	int x, y, area = 1;
	for (int i = 0; i < 4; ++i) {
		//遍历一次,陆地加一
		x = r + direction[i], y = c + direction[i + 1];
		if (x >= 0 && x < grid.size() && y >= 0 && y < grid[0].size()) {
			area += dfs(grid, x, y);
		}
	}
	return area;
}

一种是不管三七二十一先进行下一步搜索,待下一步搜索开始时再判断是否合法(即判断放在辅函数第一行)。

// 主函数
int maxAreaOfIsland(vector<vector<int>>& grid) {
	if (grid.empty() || grid[0].empty()) return 0;
	int max_area = 0;
	for (int i = 0; i < grid.size(); ++i) {
		for (int j = 0; j < grid[0].size(); ++j) {
			max_area = max(max_area, dfs(grid, i, j));
		}
	}
	return max_area;
}
// 辅函数
int dfs(vector<vector<int>>& grid, int r, int c) {
	if (r < 0 || r >= grid.size() ||
		c < 0 || c >= grid[0].size() || grid[r][c] == 0) {
		return 0;
	}
	grid[r][c] = 0;
	return 1 + dfs(grid, r + 1, c) + dfs(grid, r - 1, c) +
		dfs(grid, r, c + 1) + dfs(grid, r, c - 1);
}

vector<int> direction{ -1, 0, 1, 0, -1 };
int pointers::maxAreaOfIsland(vector<vector<int>>& grid)
{
	int m = grid.size(), n = m ? grid[0].size() : 0, local_area, area = 0, x, y;
	for (int i = 0; i < m; ++i) {
		for (int j = 0; j < n; ++j) {
			if (grid[i][j]) {
				local_area = 1;
				grid[i][j] = 0;
				stack<pair<int, int>> island;
				//Stack(栈)是一种后进先出的数据结构,使用STL的STACK需要的头文件
				island.push({ i, j });      //入栈,注意是圆括号里面套花括号
				while (!island.empty()) {
					auto [r, c] = island.top(); //输出栈顶数据
					island.pop();     //弹出栈顶数据
					for (int k = 0; k < 4; ++k) {
						x = r + direction[k], y = c + direction[k + 1];
						if (x >= 0 && x < m &&
							y >= 0 && y < n && grid[x][y] == 1) {
							grid[x][y] = 0;
							++local_area;
							island.push({ x, y });
						}
					}
				}
				area = max(area, local_area);
			}
		}
	}
	return area;
}

547 省份数量

有 n 个城市,其中一些彼此相连,另一些没有相连。如果城市 a 与城市 b 直接相连,且城市 b 与城市 c 直接相连,那么城市 a 与城市 c 间接相连。省份 是一组直接或间接相连的城市,组内不含其他没有相连的城市。给你一个 n x n 的矩阵 isConnected ,其中 isConnected[i][j] = 1 表示第 i 个城市和第 j 个城市直接相连,而 isConnected[i][j] = 0 表示二者不直接相连。返回矩阵中 省份 的数量。
解:因为对称性,对角线全是1

书中最优解

int pointers::findCircleNum(vector<vector<int>>& isConnected)
{
	int n = isConnected.size(), count = 0;
	vector<bool> visited(n, false);
	for (int i = 0; i < n; ++i) {
		if (!visited[i]) {
			dfs(isConnected, i, visited);
			++count;
		}
	}
	return count;
}
// 辅函数
void dfs(vector<vector<int>>& isConnected, int i, vector<bool>& visited) {
	visited[i] = true;   //表示已访问
	for (int k = 0; k < isConnected.size(); ++k) {
		if (isConnected[i][k] == 1 && !visited[k]) {  
			dfs(isConnected, k, visited);
		}
	}
}

417 太平洋大西洋流水问题

有一个 m × n 的矩形岛屿,与 太平洋 和 大西洋 相邻。 “太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。

这个岛被分割成一个由若干方形单元格组成的网格。给定一个 m x n 的整数矩阵 heights , heights[r][c] 表示坐标 (r, c) 上单元格 高于海平面的高度 。

岛上雨水较多,如果相邻单元格的高度 小于或等于 当前单元格的高度,雨水可以直接向北、南、东、西流向相邻单元格。水可以从海洋附近的任何单元格流入海洋。

返回网格坐标 result 的 2D 列表 ,其中 result[i] = [ri, ci] 表示雨水从单元格 (ri, ci) 流动 既可流向太平洋也可流向大西洋 。

书中最优解

vector<int> direction{ -1, 0, 1, 0, -1 };
// 主函数
vector<vector<int>> pacificAtlantic(vector<vector<int>>& matrix) {
	if (matrix.empty() || matrix[0].empty()) {
		return {};
	}
	vector<vector<int>> ans;
	int m = matrix.size(), n = matrix[0].size();  //m是行数,n是列数
	vector<vector<bool>> can_reach_p(m, vector<bool>(n, false));
	vector<vector<bool>> can_reach_a(m, vector<bool>(n, false));
	for (int i = 0; i < m; ++i) {
		dfs(matrix, can_reach_p, i, 0);   //太平洋,第一列
		dfs(matrix, can_reach_a, i, n - 1);   //大西洋,最后一列
	}
	for (int i = 0; i < n; ++i) {
		dfs(matrix, can_reach_p, 0, i);    //太平洋,第一行
		dfs(matrix, can_reach_a, m - 1, i);  //大西洋,最后一行
	}
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; ++j) {
			if (can_reach_p[i][j] && can_reach_a[i][j]) {  //既流向太平洋又流向大西洋
				ans.push_back(vector<int>{i, j});
			}
		}
	}
	return ans;
}
// 辅函数
void dfs(const vector<vector<int>>& matrix, vector<vector<bool>>& can_reach,int r, int c) {
	if (can_reach[r][c]) {
		return;
	}
	can_reach[r][c] = true;
	int x, y;
	for (int i = 0; i < 4; ++i) {
		x = r + direction[i];         //上下左右标
		y = c + direction[i + 1];
		if (x >= 0 && x < matrix.size()
			&& y >= 0 && y < matrix[0].size() &&
			matrix[r][c] <= matrix[x][y]) {
			dfs(matrix, can_reach, x, y);
		}
	}
}

网页答案,辅函数稍作调整,执行用时更快

if (visited[x][y]) return;
visited[x][y] = true;
for (int i = 0; i < 4; i++) { // 向四个方向遍历
    int nextx = x + dir[i][0];
    int nexty = y + dir[i][1];
    // 超过边界
    if (nextx < 0 || nextx >= heights.size() || nexty < 0 || nexty >= heights[0].size()) continue;
    // 高度不合适,注意这里是从低向高判断
    if (heights[x][y] > heights[nextx][nexty]) continue;
    dfs (heights, visited, nextx, nexty);
}
       

46 全排列

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

网页答案  相对好理解

技术博客 http://www.cnblogs.com/itdef/
B站算法视频题解 https://space.bilibili.com/18508846

class Solution {
public:
    vector<int> vis;
    vector<vector<int>> ans;
    vector<int> v;
    void dfs(vector<int>& nums, int idx)
    {
        if (idx > nums.size()) return;
        if (idx == nums.size()) {
            ans.push_back(v);
            return;
        }

        for (int i = 0; i < nums.size(); i++) {
            if (vis[i] == 0) {
                v[idx] = nums[i];
                vis[i] = 1;
                dfs(nums, idx + 1);
                vis[i] = 0;
                v[idx] = -1;
            }
        }


        return;
    }

    vector<vector<int>> permute(vector<int>& nums) {
        int len = nums.size();
        vis = vector<int>(len,0);
        v = vector<int>(len, -1);
        dfs(nums, 0);
        return ans;
    }
};

网页答案

链接:https ://leetcode.cn/problems/permutations/solutions/2570195/javapython3chui-su-fa-mei-ge-wei-zhi-tia-p9wp/

class Solution {
private:
	/**
	 * 枚举当前nums中未使用过的元素nums[i],填入当前位置ans[idx]
	 * @param nums: 元素数组
	 * @param idx: 当前元素要填入的位置
	 * @param res: 结果数组
	 * @param ans:排列数组,用于生成一种排列的可能
	 * @param used:判断枚举的元素是否使用过
	*/
	void backtracking(vector<int>& nums, int idx, vector<vector<int>>& res, vector<int>& ans, vector<bool>& used) {
		if (idx == nums.size()) {
			// 填入位置到达终点,说明生成了一种排列可能,加入结果数组
			res.emplace_back(ans);
			return;
		}
		for (int i = 0; i < nums.size(); i++) {
			// 枚举nums中的每个索引
			if (used[i])continue;    // 如果当前枚举的索引使用过了,则跳过
			used[i] = true;         // 标记当前索引已经使用
			ans[idx] = nums[i];     // 将元素nums[i]填入当前位置idx
			backtracking(nums, idx + 1, res, ans, used);    // 处理后续位置
			used[i] = false;        // ans[idx]填入nums[i]的情况枚举完了,恢复nums[i]是未处理的状态【这样当这个位置填入其他元素时,后续位置还可以使用nums[i]】
		}
	}
public:
	vector<vector<int>> permute(vector<int>& nums) {
		vector<vector<int>> res;    // 结果列表
		int n = nums.size();
		vector<int> ans(n);         // 用于生成一种排列的列表,长度为n
		vector<bool> used(n);       // 用于标记每个索引的元素是否使用过
		backtracking(nums, 0, res, ans, used);      // 从索引0的位置开始填入元素
		return res;
	}
};

书中最优解

// 主函数
vector<vector<int>> permute(vector<int>& nums) {
	vector<vector<int>> ans;
	backtracking(nums, 0, ans);
	return ans;
}
// 辅函数
void backtracking(vector<int>& nums, int level, vector<vector<int>>& ans) {
	if (level == nums.size() - 1) {   // 填入位置到达终点,说明生成了一种排列可能,加入结果数组
		ans.push_back(nums);          //减一是因为最后一个数用不着交换
		return;
	}
	for (int i = level; i < nums.size(); i++) {    //循环实现level后面每个元素的交换
		swap(nums[i], nums[level]); // 修改当前节点状态,将元素[i]填入当前位置level
		backtracking(nums, level + 1, ans); // 递归子节点
		swap(nums[i], nums[level]); // 回改当前节点状态,一层层递归后到不交换为止,再换回原位    
	}
}

77 组合

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。你可以按 任何顺序 返回答案。

书中最优解

// 主函数
vector<vector<int>> combine(int n, int k) {
vector<vector<int>> ans;
vector<int> comb(k, 0);
int count = 0;
backtracking(ans, comb, count, 1, n, k);
return ans;
}
// 辅函数
void backtracking(vector<vector<int>>& ans, vector<int>& comb, int& count, int
pos, int n, int k) {
if (count == k) {
ans.push_back(comb);
return;
}
for (int i = pos; i <= n; ++i) {
comb[count++] = i; // 修改当前节点状态
backtracking(ans, comb, count, i + 1, n, k); // 递归子节点
--count; // 回改当前节点状态
}
}

79 单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

解:回溯+深度优先遍历

书中最优解

// 主函数
bool exist(vector<vector<char>>& board, string word) {
	if (board.empty()) return false;
	int m = board.size(), n = board[0].size();
	vector<vector<bool>> visited(m, vector<bool>(n, false));
	bool find = false;
	for (int i = 0; i < m; ++i) {
		for (int j = 0; j < n; ++j) {
			backtracking(i, j, board, word, find, visited, 0);
		}
	}
	return find;
}
// 辅函数
void backtracking(int i, int j, vector<vector<char>>& board, string& word, bool
	& find, vector<vector<bool>>& visited, int pos) {
	// 越界、被访问过、当前位置的字符不是word对应位置的字符
	if (i < 0 || i >= board.size() || j < 0 || j >= board[0].size()) {
		return;
	}
	if (visited[i][j] || find || board[i][j] != word[pos]) {
		return;
	}
	if (pos == word.size() - 1) {   //最后一个字符
		find = true;
		return;
	}
	visited[i][j] = true; // 修改当前节点状态
	// 递归子节点
	backtracking(i + 1, j, board, word, find, visited, pos + 1);
	backtracking(i - 1, j, board, word, find, visited, pos + 1);
	backtracking(i, j + 1, board, word, find, visited, pos + 1);
	backtracking(i, j - 1, board, word, find, visited, pos + 1);
	visited[i][j] = false; // 回改当前节点状态
}

网页答案

class Solution {
public:
    bool exist(vector<vector<char>>& board, string word) {
        rows = board.size();
        cols = board[0].size();
        for(int i = 0; i < rows; i++) {
            for(int j = 0; j < cols; j++) {
                if (dfs(board, word, i, j, 0)) return true;
            }
        }
        return false;
    }
private:
    int rows, cols;
    bool dfs(vector<vector<char>>& board, string word, int i, int j, int k) {
        if (i >= rows || i < 0 || j >= cols || j < 0 || board[i][j] != word[k]) return false;
        if (k == word.size() - 1) return true;
        board[i][j] = '\0';
        bool res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) || 
                      dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);
        board[i][j] = word[k];
        return res;
    }
};

作者:Krahets
链接:https://leetcode.cn/problems/word-search/solutions/

51 皇后

书中最优解

// 主函数
vector<vector<string>> solveNQueens(int n) {
	vector<vector<string>> ans;
	if (n == 0) {
		return ans;
	}
	vector<string> board(n, string(n, ’.’));
	vector<bool> column(n, false), ldiag(2 * n - 1, false), rdiag(2 * n - 1, false);
	backtracking(ans, board, column, ldiag, rdiag, 0, n);
	return ans;
}
// 辅函数
void backtracking(vector<vector<string>>& ans, vector<string>& board, vector<
	bool>& column, vector<bool>& ldiag, vector<bool>& rdiag, int row, int n) {
	if (row == n) {
		ans.push_back(board);
		return;
	}
	for (int i = 0; i < n; ++i) {
		if (column[i] || ldiag[n - row + i - 1] || rdiag[row + i + 1]) {
			continue;
		}
		// 修改当前节点状态
		board[row][i] = ’Q’;
		column[i] = ldiag[n - row + i - 1] = rdiag[row + i + 1] = true;
		// 递归子节点
		backtracking(ans, board, column, ldiag, rdiag, row + 1, n);
		// 回改当前节点状态
		board[row][i] = ’.’;
		column[i] = ldiag[n - row + i - 1] = rdiag[row + i + 1] = false;
	}
}

934最短的桥

给你一个大小为 n x n 的二元矩阵 grid ,其中 1 表示陆地,0 表示水域。

 是由四面相连的 1 形成的一个最大组,即不会与非组内的任何其他 1 相连。grid 中 恰好存在两座岛 。你可以将任意数量的 0 变为 1 ,以使两座岛连接起来,变成 一座岛 。

返回必须翻转的 0 的最小数目。

解:先深度优先遍历找其中一个岛,然后广度优先遍历找到另一个岛

书中最优解

vector<int> direction{ -1, 0, 1, 0, -1 };
// 主函数
int shortestBridge(vector<vector<int>>& grid) {
	int m = grid.size(), n = grid[0].size();
	queue<pair<int, int>> points;
	// dfs寻找第一个岛屿,并把1全部赋值为2
	bool flipped = false;
	for (int i = 0; i < m; ++i) {
		if (flipped) break;
		for (int j = 0; j < n; ++j) {
			if (grid[i][j] == 1) {
				dfs(points, grid, m, n, i, j);
				flipped = true;
				break;
			}
		}
	}
	// bfs寻找第二个岛屿,并把过程中经过的0赋值为2
	int x, y;
	int level = 0;
	while (!points.empty()) {
		++level;
		int n_points = points.size();
		while (n_points--) {
			auto [r, c] = points.front();
			points.pop();
			for (int k = 0; k < 4; ++k) {
				x = r + direction[k], y = c + direction[k + 1];
				if (x >= 0 && y >= 0 && x < m && y < n) {
					if (grid[x][y] == 2) {
						continue;
					}
					if (grid[x][y] == 1) {
						return level;
					}
					points.push({ x, y });
					grid[x][y] = 2;
				}
			}
		}
	}
	return 0;
}
// 辅函数
void dfs(queue<pair<int, int>>& points, vector<vector<int>>& grid, int m, int n, int i, int j) {
	if (i < 0 || j < 0 || i == m || j == n || grid[i][j] == 2) {
		return;
	}
	if (grid[i][j] == 0) {
		points.push({ i, j });
		return;
	}
	grid[i][j] = 2;
	dfs(points, grid, m, n, i - 1, j);
	dfs(points, grid, m, n, i + 1, j);
	dfs(points, grid, m, n, i, j - 1);
	dfs(points, grid, m, n, i, j + 1);
}

网页答案

http://t.csdnimg.cn/GSNQQ

class Solution {
public:
    void dfs(vector<vector<int>>& A, vector<pair<int,int>>& tmp, int r, int c)
    {
        if(r-1>=0 && 1==A[r-1][c])
        {
            A[r-1][c]=2;
            tmp.push_back(make_pair(r-1,c));
            dfs(A,tmp,r-1,c);
        }
        if(r+1<A.size() && 1==A[r+1][c])
        {
            A[r+1][c]=2;
            tmp.push_back(make_pair(r+1,c));
            dfs(A,tmp,r+1,c);
        }
        if(c-1>=0 && 1==A[r][c-1])
        {
            A[r][c-1]=2;
            tmp.push_back(make_pair(r,c-1));
            dfs(A,tmp,r,c-1);
        }
        if(c+1<A[0].size() && 1==A[r][c+1])
        {
            A[r][c+1]=2;
            tmp.push_back(make_pair(r,c+1));
            dfs(A,tmp,r,c+1);
        }        
    }
    
    int shortestBridge(vector<vector<int>>& A) 
    {
        int m=A.size();
        int n=A[0].size();
        int flag=0;
        vector<pair<int,int>> tmp;
        int res=0;
        for(int i=0;i<m;i++)
        {
            if(flag)
            {
                break;
            }
            for(int j=0;j<n;j++)
            {
                if(1==A[i][j])
                {
                    tmp.push_back(make_pair(i,j));
                    A[i][j]=2;
                    dfs(A,tmp,i,j);
                    flag=1;
                    break;
                }
            }
        }
        while(flag)
        {
            vector<pair<int,int>> vec;
            for(auto it:tmp)
            {
                int r=it.first;
                int c=it.second;
                if(r-1>=0)
                {
                    if(1==A[r-1][c])
                    {
                        flag=0;
                        break;
                    }
                    else if(0==A[r-1][c])
                    {
                        A[r-1][c]=2;
                        vec.push_back(make_pair(r-1,c));
                    }
                }
                if(r+1<A.size())
                {
                    if(1==A[r+1][c])
                    {
                        flag=0;
                        break;
                    }
                    else if(0==A[r+1][c])
                    {
                        A[r+1][c]=2;
                        vec.push_back(make_pair(r+1,c));
                    }                    
                }
                if(c-1>=0)
                {
                    if(1==A[r][c-1])
                    {
                        flag=0;
                        break;
                    }
                    else if(0==A[r][c-1])
                    {
                        A[r][c-1]=2;
                        vec.push_back(make_pair(r,c-1));                     
                    }
                }
                if(c+1<A[0].size())
                {
                    if(1==A[r][c+1])
                    {
                        flag=0;
                        break;
                    }
                    else if(0==A[r][c+1])
                    {
                        A[r][c+1]=2;
                        vec.push_back(make_pair(r,c+1));                       
                    }
                }                
            }
            if(flag)
            {
                res++;
            }
            tmp=vec;      //不理解
        }
        return res;        
    }
};

126 单词接龙II

给定一个起始字符串和一个终止字符串,以及一个单词表,求是否可以将起始字符串每次改
一个字符,直到改成终止字符串,且所有中间的修改过程表示的字符串都可以在单词表里找到。
若存在,输出需要修改次数最少的所有更改方式。
书中最优解
// 主函数
vector<vector<string>> findLadders(string beginWord, string endWord, vector<
	string>& wordList) {
	vector<vector<string>> ans;
	unordered_set<string> dict;
	for (const auto& w : wordList) {
		dict.insert(w);
	}
	if (!dict.count(endWord)) {
		return ans;
	}
	dict.erase(beginWord);
	dict.erase(endWord);
	unordered_set<string> q1{ beginWord }, q2{ endWord };
	unordered_map<string, vector<string>> next;
	bool reversed = false, found = false;
	while (!q1.empty()) {
		unordered_set<string> q;
		for (const auto& w : q1) {
			string s = w;
			for (size_t i = 0; i < s.size(); i++) {
				char ch = s[i];
				for (int j = 0; j < 26; j++) {
					s[i] = j + ’a’;
					if (q2.count(s)) {
						reversed ? next[s].push_back(w) : next[w].push_back(s);
						found = true;
					}
					if (dict.count(s)) {
						reversed ? next[s].push_back(w) : next[w].push_back(s);
						q.insert(s);
					}
				}
				s[i] = ch;
			}
		}
		if (found) {
			break;
		}
		for (const auto& w : q) {
			dict.erase(w);
		}
		if (q.size() <= q2.size()) {
			q1 = q;
		}
		else {
			reversed = !reversed;
			q1 = q2;
			q2 = q;
		}
	}
	if (found) {
		vector<string> path = { beginWord };
		backtracking(beginWord, endWord, next, path, ans);
	}
	return ans;
}
// 辅函数
void backtracking(const string& src, const string& dst, unordered_map<string,
	vector<string>> &next, vector<string>& path, vector<vector<string>>& ans) {
	if (src == dst) {
		ans.push_back(path);
		return;
	}
	for (const auto& s : next[src]) {
		path.push_back(s);
		backtracking(s, dst, next, path, ans);
		path.pop_back();
	}
}

  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值