10.力扣2018年常见编程题总结(图论)

1.给定两个单词(beginWord 和 endWord)和一个字典,找到从 beginWord 到 endWord 的最短转换序列的长度。转换需遵循如下规则:

  1. 每次转换只能改变一个字母。
  2. 转换过程中的中间单词必须是字典中的单词。

说明:

  • 如果不存在这样的转换序列,返回 0。
  • 所有单词具有相同的长度。
  • 所有单词只由小写字母组成。
  • 字典中不存在重复的单词。
  • 你可以假设 beginWord 和 endWord 是非空的,且二者不相同。

示例 1:

输入: beginWord = "hit", endWord = "cog", wordList = ["hot","dot","dog","lot","log","cog"]

输出: 5

解释: 一个最短转换序列是 "hit" -> "hot" -> "dot" -> "dog" -> "cog", 返回它的长度 5。

using namespace std;

class Solution {
public:
	int ladderLength(string beginWord, string endWord, vector& wordList) {
		unordered_set dict(wordList.begin(), wordList.end()), head, tail, *phead, *ptail;
		if (dict.find(endWord) == dict.end()) {
			return 0;	//结束字符不在字典中则直接返回0
		}
		head.insert(beginWord);
		tail.insert(endWord);
		int ladder = 2;
		while (!head.empty() && !tail.empty()) {
			if (head.size() < tail.size()) {
				phead = &head;
				ptail = &tail;
			}
			else {
				phead = &tail;
				ptail = &head;
			}
			unordered_set temp;
			for (auto it = phead->begin(); it != phead->end(); it++) {
				string word = *it;
				for (int i = 0; i < word.size(); i++) {
					char t = word[i];
					for (int j = 0; j < 26; j++) {
						word[i] = 'a' + j;
						if (ptail->find(word) != ptail->end()) {
							return ladder;
						}
						if (dict.find(word) != dict.end()) {
							temp.insert(word);
							dict.erase(word);
						}
					}
					word[i] = t;
				}
			}
			ladder++;
			phead->swap(temp);
		}
		return 0;
	}
};

int main()
{
	Solution s1;
	vector ss = { "hot","dot","dog","lot","log","cog" };
	cout << s1.ladderLength("hit","cog",ss);
	return 0;
}

2.给定一个由 '1'(陆地)和 '0'(水)组成的的二维网格,计算岛屿的数量。一个岛被水包围,并且它是通过水平方向或垂直方向上相邻的陆地连接而成的。你可以假设网格的四个边均被水包围。

输入: 11110 11010 11000 00000

输出: 1

解:递归调用infect函数,利用深度搜索,遇到1时,它的上下左右都被改为2

代码:

using namespace std;

class Solution {
public:
	int numIslands(vector>& grid) {
		if (grid.empty() || grid[0].empty()) {
			return 0;	//行空 或 列空
		}
		int N = grid.size();//grid网格的列长
		int M = grid[0].size();//grid网格的行长
		int res = 0;
		//深度优先搜索
		for (int i = 0; i < N; ++i) {
			for (int j = 0; j < M; ++j) {
				if (grid[i][j] == '1') {
					++res;//只计数作为起始感染点的1的个数,即为岛屿个数
					infect(grid, i, j, N, M);
				}
			}
		}
		return res;
	}

	void infect(vector>& grid, int i, int j, int N, int M) {
		if (i < 0 || i >= N || j < 0 || j >= M || grid[i][j] != '1') {
			return;
		}
		grid[i][j] = '2';
		infect(grid, i + 1, j, N, M);
		infect(grid, i - 1, j, N, M);
		infect(grid, i, j - 1, N, M);
		infect(grid, i, j + 1, N, M);
	}
};

int main()
{
	Solution s1;
	vector < vector> ss = { {'1','1','0','0','0'} ,{'1','1','0','0','0'},{'0','0','1','0','0'},{'0','0','0','1','1'} };
	cout << s1.numIslands(ss);
	return 0;
}

3.现在你总共有 n 门课需要选,记为 0 到 n-1

在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]

给定课程总量以及它们的先决条件,判断是否可能完成所有课程的学习?

示例 1:

输入: 2, [[1,0]]

输出: true

解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。

代码:

using namespace std;

class Solution {
public:
	bool canFinish(int numCourses, vector>& prerequisites) {
		const int N = INT8_MAX;
		vector head[N], res;
		int du[N] = { 0 }, n = numCourses;
		int len = prerequisites.size();
		//根据课程表,构建有向图
		for (int i = 0; i < len; i++) {
			int aft = prerequisites[i][0];
			int pre = prerequisites[i][1];
			du[aft]++;
			head[pre].push_back(aft);
		}
		//将第一个要修的课程,即du为0的课程压入队列中
		queue q;
		for (int i = 0; i < n; i++) {
			if (!du[i]) q.push(i);
		}
		//依次按照有向图的方向,将所有课程按顺序放入数组中
		while (!q.empty()) {
			int top = q.front();
			q.pop();
			res.push_back(top);
			du[top] = -1;
			for (auto x : head[top]) {
				du[x]--;
				if (!du[x]) q.push(x);
			}
		}
		return n == res.size();
	}
};

int main()
{
	Solution s1;
	vector < vector> ss = { {1,0} };
	cout << s1.canFinish(2,ss);
	return 0;
}

4.现在你总共有 n 门课需要选,记为 0 到 n-1

在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]

给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。

可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。

示例 1:

输入: 2, [[1,0]]

输出: [0,1]

解释: 总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。

代码:

class Solution {
public:
	vector findOrder(int numCourses, vector>& prerequisites) {
		vector heads(numCourses, -1), degree(numCourses, 0), points, args;
		pair p;
		vector ans;
		int from, to, count = 0, len = prerequisites.size();

		/* 构造有向图,邻接表 */
		for (int i = 0; i < len; ++i) {

			from = prerequisites[i][1];
			to = prerequisites[i][0];
			++degree[to];
			args.push_back(heads[from]);
			points.push_back(to);
			heads[from] = count++;
		}

		/* bfs拓扑排序,依次移除入度为0的点 */
		queue q;
		for (int i = 0; i < numCourses; ++i)
			if (degree[i] == 0) {
				q.push(i);
				ans.push_back(i);
			}
		while (!q.empty()) {
			from = q.front();
			q.pop();
			to = heads[from];
			while (to != -1) {
				if (--degree[points[to]] == 0) {
					q.push(points[to]);
					ans.push_back(points[to]);
				}
				to = args[to];
			}
		}

		/* 判定是否所有的点入度都为0,若是则不存在环,否则存在环 */
		for (int i = 0; i < numCourses; ++i)
			if (degree[i] > 0)
				return vector();

		return ans;
	}
};

int main()
{
	Solution s1;
	vector < vector> ss = { {1,0} };
	vector s;
	s = s1.findOrder(2,ss);
	return 0;
}

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(10.力扣2018年常见编程题总结(图论))