开宗明义:本系列基于小象学院林沐老师课程《面试算法 LeetCode 刷题班》,刷题小白,旨在理解和交流,重在记录,望各位大牛指点!
Leetcode学习之深度优先搜索与宽度优先搜索(1)
题目来源: L e e t C o d e 200. N u m b e r o f I s l a n d s LeetCode \ 200. \ Number \ of \ Islands LeetCode 200. Number of Islands
描述:用一个二维数组代表一张地图,这张地图由字符 '0’ 或者 ‘1’ 组成。其中 '0’ 代表水域,‘1’ 代表小岛土地。我们认为 '1’ 被 ‘0’ 所包围,当小岛土地 ‘1’ 在水平和垂直方向相连接时,认为是同一块土地。求这张地图中小岛的数量。
分析:
#include
#include
#include
#include
#include
using namespace std;
void DFS(vector<vector<int>> &mark, vector<vector<char>> &grid, int x, int y) {
mark[x][y] = 1; //标记已搜寻的位置
static const int dx[] = { -1,1,0,0 }; //按照上下左右顺序
static const int dy[] = { 0,0,-1,1 }; //方向数组
for (int i = 0; i < 4; i++) {
int newx = dx[i] + x;
int newy = dy[i] + y;
if (newx < 0 || newx >= mark.size() || //超出数组边界
newy < 0 || newy >= mark[newx].size()) {
continue;
}
if (mark[newx][newy] == 0 && grid[newx][newy] == '1') { //深搜的情况:grid为1且mark没有搜到
DFS(mark, grid, newx, newy);
}
}
}
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
int island_num = 0;
//二维数组的构造形式
vector<vector<int>> mark;
for (int i = 0; i < grid.size(); i++) {
mark.push_back(vector<int>());
for (int j = 0; j < grid[i].size(); j++) {
mark[i].push_back(0);
}
}
for (int i = 0; i < grid.size(); i++) {
for (int j = 0; j < grid[i].size(); j++) {
if (mark[i][j] == 0 && grid[i][j] == '1') {
DFS(mark, grid, i, j);
island_num++;
}
}
}
return island_num;
}
};
int main() {
vector<vector<char>> grid;
char str[10][10] = { "11100","11000 ","00100","00011" };
for (int i = 0; i < 4; i++) {
grid.push_back(vector<char>());
for (int j = 0; j < 5; j++) {
grid[i].push_back(str[i][j]);
}
}
Solution solve;
printf("%d\n", solve.numIslands(grid));
system("pause");
return 0;
}
#include
#include
#include
#include
#include
#include
using namespace std;
void BFS(vector<vector<int>> &mark, vector<vector<char>> &grid, int x, int y) {
static const int dx[] = { -1,1,0,0 }; //方向数组
static const int dy[] = { 0,0,-1,1 };
queue<pair<int, int>> Q; //宽度优先搜索队列
Q.push(std::make_pair(x, y)); //将(x,y)push进入队列,并做标记
mark[x][y] = 1;
while (!Q.empty()) {
x = Q.front().first; //取队列头部元素
y = Q.front().second;
Q.pop(); //弹出队头元素
for (int i = 0; i < 4; i++) {
int newx = dx[i] + x; //拓展四个方向
int newy = dy[i] + y;
if (newx < 0 || newx >= mark.size() || newy<0 || newy>mark[newx].size()) { //忽略越过地图边界的位置
continue;
}
//如果当前位置未搜索,且为陆地
if (mark[newx][newy] == 0 && grid[newx][newy] == '1') {
Q.push(std::make_pair(newx, newy)); //将新位置push进入队列
mark[newx][newy] = 1; //并做标记
}
}
}
}
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
int island_num = 0;
//二维数组的构造形式
vector<vector<int>> mark;
for (int i = 0; i < grid.size(); i++) {
mark.push_back(vector<int>());
for (int j = 0; j < grid[i].size(); j++) {
mark[i].push_back(0);
}
}
for (int i = 0; i < grid.size(); i++) {
for (int j = 0; j < grid[i].size(); j++) {
if (mark[i][j] == 0 && grid[i][j] == '1') {
BFS(mark, grid, i, j);
island_num++;
}
}
}
return island_num;
}
};
int main() {
vector<vector<char>> grid;
char str[10][10] = { "11100","11000 ","00100","00011" };
for (int i = 0; i < 4; i++) {
grid.push_back(vector<char>());
for (int j = 0; j < 5; j++) {
grid[i].push_back(str[i][j]);
}
}
Solution solve;
printf("%d\n", solve.numIslands(grid));
system("pause");
return 0;
}
题目来源: L e e t C o d e 127. W o r d L a d d e r LeetCode \ 127. \ Word \ Ladder LeetCode 127. Word Ladder
描述:已知两个单词(起始单词 b e g i n W o r d beginWord beginWord、结束单词 e n d W o r d endWord endWord),一个单词词典 w o r d L i s t wordList wordList ,根据转换规则计算从起始单词到结束但系的最短转换步数。
转换规则如下:
测试代码:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
//判断word1与word2相差是否只有一个字符
bool connect(const string &word1, const string &word2) {
int cnt = 0;//记录word1与word2不相等字符的个数
for (int i = 0; i < word1.length(); i++) {
if (word1[i] != word2[i]) {
cnt++;
}
}
return cnt == 1;
}
//构造图
void construct_graph(string &beginWord, vector<string> &wordList, map<string, vector<string>> &graph) {
wordList.push_back(beginWord);
for (int i = 0; i < wordList.size(); i++) {
graph[wordList[i]] = vector<string>();
}
for (int i = 0; i < wordList.size(); i++) {
for (int j = i + 1; j < wordList.size(); j++) {
if (connect(wordList[i], wordList[j])){ //判断vector里面两个string是否只相差一个字符
graph[wordList[i]].push_back(wordList[j]);
graph[wordList[j]].push_back(wordList[i]); //然后map映射
}
} //对任意两个单词wordlist[i]与wordlist[j],若wordlist[i]与wordlist[j]只相差一个字符,则将他们相连。
}
}
//图的宽度遍历
int BFS_graph(string &beginWord, string &endWord, map<string, vector<string>> &graph) {
//给定图的起点beginWord,终点endWord,图graph
queue<pair<string, int>> Q; //搜索队列 pair<顶点,步数>
set<string> visit; //记录已访问的顶点
Q.push(make_pair(beginWord, 1)); //添加起始点,起始点步数为1 队列初始化
visit.insert(beginWord); //标记起点已访问
while (!Q.empty()) { //队列不空,就不断进行搜索
string node = Q.front().first; //取队列头部节点与步数
int step = Q.front().second;
Q.pop(); //每搜索完成一个节点,即从队列弹出
if (node == endWord) { //找到终点,返回步数
return step;
}
const vector<string> &neighbors = graph[node]; //取node的全部临接点
for (int i = 0; i < neighbors.size(); i++) { //若相邻节点还未添加至该队列中
if (visit.find(neighbors[i]) == visit.end()) {
Q.push(make_pair(neighbors[i], step + 1));
visit.insert(neighbors[i]);
} //标记neighbors[i]已添加至队列
}
}
return 0;
}
class Solution {
public:
int ladderLength(string beginword, string endword, vector<string>& wordList) {
map<string, vector<string>> graph; //映射string ->vector
construct_graph(beginword, wordList, graph); //构造图
return BFS_graph(beginword, endword, graph);
}
};
int main() {
string beginword = "hit";
string endword = "cog";
vector<string> wordList;
wordList.push_back("hot");
wordList.push_back("dot");
wordList.push_back("dog");
wordList.push_back("lot");
wordList.push_back("log");
wordList.push_back("cog");
//beginword="hit",endword="cog",wordlist=["hot","dot","dog","lot","log","cog"]
Solution solve;
int result = solve.ladderLength(beginword, endword, wordList);
printf("result = %d\n", result);
system("pause");
return 0;
}
题目来源: L e e t C o d e 126. W o r d L a d d e r LeetCode \ 126. \ Word \ Ladder LeetCode 126. Word Ladder
描述:已知两个单词(起始单词 b e g i n W o r d beginWord beginWord、结束单词 e n d W o r d endWord endWord),一个单词词典 w o r d L i s t wordList wordList ,根据转换规则计算从起始单词到结束但系的最短转换步数。
转换规则如下:
测试代码:
#include
#include
#include
#include
#include
#include
#include
using namespace std;
struct Qitem {
string node; //搜索节点
int parent_pos; //前驱节点在队列中的位置
int step; //到达当前节点的步数
Qitem(string node, int parent_pos, int step): node(node),parent_pos(parent_pos),step(step){}
};
//判断word1与word2相差是否只有一个字符
bool connect(const string &word1, const string &word2) {
int cnt = 0;//记录word1与word2不相等字符的个数
for (int i = 0; i < word1.length(); i++) {
if (word1[i] != word2[i]) {
cnt++;
}
}
return cnt == 1;
}
void BFS_graph(string &beginWord, string &endWord,
map<string, vector<string> > &graph,
vector<Qitem> &Q, //使用vector实现队列,里面包含结构体,可保存所有信息
vector<int> &end_word_pos) { //终点 endWord 所在队列的位置下标
map<string, int> visit; //<单词,步数>
int min_step = 0; //到达 endWord 的最小步数
Q.push_back(Qitem(beginWord.c_str(), -1, 1)); //起始单词的前驱为-1
visit[beginWord] = 1; //标记起始单词步数为1
int front = 0; //队列头指针front,指向vector表示的队列头
while (front!=Q.size()){
const string &node = Q[front].node; //front指向Q.size()即vector尾步时,队列为空
int step = Q[front].step; //取队头元素
if (min_step != 0 && step > min_step){ //step>min_step时,代表所有到终点的路径都搜索完成
break;
}
if (node == endWord) {
min_step = step; //当搜索到结果时,记录到达终点的最小步数
end_word_pos.push_back(front);
}
const vector<string> &neighbors = graph[node];
for (int i = 0; i < neighbors.size(); i++) { //节点没被访问,或另一条最短路径
if (visit.find(neighbors[i]) == visit.end() ||
visit[neighbors[i]] == step + 1) {
Q.push_back(Qitem(neighbors[i], front, step + 1));
visit[neighbors[i]] = step + 1; //标记到达临接点neighbors[i]的最小步数
}
}
front++;
}
}
void construct_graph(string &beginWord,
vector<string>& wordList,
map<string, vector<string>> &graph) {
int has_begin_word = 0;
for (int i = 0; i < wordList.size(); i++) {
if (wordList[i] == beginWord) {
has_begin_word = 1;
}
graph[wordList[i]] = vector<string>();
}
for (int i = 0; i < wordList.size(); i++) {
for (int j = i + 1; j < wordList.size(); j++) {
if (connect(wordList[i], wordList[j])) {
graph[wordList[i]].push_back(wordList[j]);
graph[wordList[j]].push_back(wordList[i]);
}
}
if (has_begin_word == 0 && connect(beginWord, wordList[i])) {
graph[beginWord].push_back(wordList[i]);
}
}
}
class Solution {
public:
vector<vector<string>> findLadders(
string beginWord, string endWord,
vector<string>& wordList) {
map<string, vector<string>> graph;
construct_graph(beginWord, wordList, graph); //构造图
vector<Qitem> Q; //使用vector实现的队列
vector<int> end_word_pos; //endword在搜索队列的位置
BFS_graph(beginWord, endWord, graph, Q, end_word_pos);
vector<vector<string>> result; //最终结果
for (int i = 0; i < end_word_pos.size(); i++) {
int pos = end_word_pos[i];
vector<string> path;
while (pos != -1) {
path.push_back(Q[pos].node);
pos = Q[pos].parent_pos;
}
result.push_back(vector<string>());
for (int j = path.size() - 1; j >= 0; j--) {
result[i].push_back(path[j]);
}
}
return result;
}
};
int main() {
string beginword = "hit";
string endword = "cog";
vector<string> wordList;
wordList.push_back("hot");
wordList.push_back("dot");
wordList.push_back("dog");
wordList.push_back("lot");
wordList.push_back("log");
wordList.push_back("cog");
//beginword="hit",endword="cog",wordlist=["hot","dot","dog","lot","log","cog"]
Solution solve;
vector<vector<string>> result = solve.findLadders(beginword, endword, wordList);
for (int i = 0; i < result.size(); i++) {
for (int j = 0; j < result[i].size(); j++) {
printf(" [%s] ", result[i][j].c_str());
}
printf("\n");
}
system("pause");
return 0;
}