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<string>& wordList) {
		unordered_set<string> 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<string> 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<string> 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<vector<char>>& 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<vector<char>>& 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<char>> 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<vector<int>>& prerequisites) {
		const int N = INT8_MAX;
		vector<int> 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<int> 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<int>> 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<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
		vector<int> heads(numCourses, -1), degree(numCourses, 0), points, args;
		pair<int, int> p;
		vector<int> 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<int> 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<int>();

		return ans;
	}
};

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

 

 

 

 

 

 

 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章