我的Leetcode学习之旅第一周——第一部分 BFS
文章参考了很多网上的代码及思想,非全部原创。
第一周 2020年1月25日-2月1日 第一部分:
BFS:200 102 207 210 444 133 297 127
200.岛屿数量
class Solution {
public:
int numIslands(vector<vector<char>>& grid) {
int n = grid.size();
if (!n) return 0;
int m = grid[0].size();
int ans = 0;
int X[4] = { 0,0,1,-1 };
int Y[4] = { 1,-1,0,0 };
pair<int, int> top;
queue<pair<int, int>> Q;
for (int x = 0; x < n; x++) {
for (int y = 0; y < m; y++) {
if (grid[x][y] == '1') {
++ans;
Q.push({x,y});
grid[x][y] = '0';
while (!Q.empty()) {
top = Q.front();
Q.pop();
for (int i = 0; i < 4; i++) {
int newX = top.first + X[i];
int newY = top.second + Y[i];
bool judge = true;
if (newX >= n || newX < 0 || newY >= m || newY < 0 || grid[newX][newY] =='0'){
judge = false;
}
if (judge) {
Q.push({newX,newY});
grid[newX][newY] = '0';
}
}
}
}
}
}
return ans;
}
};
102.二叉树的层次遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> list;
vector<int> now_list;
if(!root) return list;
queue<TreeNode*> q;
q.push(root);
while(!q.empty()){
int len = q.size();
for(int i=0;i<len;i++){
TreeNode* now = q.front();
now_list.push_back(now->val);
q.pop();
if(now->left != NULL) q.push(now->left);
if(now->right != NULL) q.push(now->right);
}
list.push_back(now_list);
now_list.clear();
}
return list;
}
};
207.课程表
class Solution {
public:
bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> inDegree(numCourses, 0);
vector<int> list[numCourses];
for (auto v : prerequisites)
{
inDegree[v[0]]++; // 初始化入度列表
list[v[1]].push_back(v[0]); // 初始化邻接表
}
int num = 0; //加入拓步队列的顶点数
queue<int> que;
for (int i = 0; i < numCourses; i++){
if (inDegree[i] == 0) que.push(i); // 将入度为0的结点放入队列
}
while (!que.empty()){
int q = que.front();
que.pop();
num++;
for (int i=0;i<list[q].size();i++){
inDegree[list[q][i]]--;
if (inDegree[list[q][i]] == 0) que.push(list[q][i]);
}
}
return num == numCourses;
}
};
- 课程表 II
class Solution {
public:
vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {
vector<int> inDegree(numCourses, 0);
vector<vector<int> > list(numCourses, vector<int>());
vector<int> output;
for (auto v : prerequisites)
{
inDegree[v[0]]++; // 初始化入度列表
list[v[1]].push_back(v[0]); // 初始化邻接表
}
int num = 0; //加入拓步队列的顶点数
queue<int> que;
for (int i = 0; i < inDegree.size(); i++){
if (inDegree[i] == 0) que.push(i); // 将入度为0的结点放入队列
}
while (!que.empty())
{
int q = que.front();
output.push_back(q);
que.pop();
num++;
for (int i=0;i<list[q].size();i++){
inDegree[list[q][i]]--;
if (inDegree[list[q][i]] == 0) que.push(list[q][i]);
}
}
int a[0];
if(num != numCourses) output.clear();
return output;
}
};
444.序列重建(没有尊贵的vip,lintcode也没有,就没写)
133.克隆图(仍有不解)
其中一个答案解析,使用copy库的深拷贝:copy.deepcopy。一句话搞定(过分了),不过底层实现过程我仍需用c++写一写。
python:
"""
# Definition for a Node.
class Node(object):
def __init__(self, val = 0, neighbors = []):
self.val = val
self.neighbors = neighbors
"""
class Solution(object):
def cloneGraph(self, node):
"""
:type node: Node
:rtype: Node
"""
return copy.deepcopy(node)
c++:
思路:先创建节点,再连接节点。
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> neighbors;
Node() {
val = 0;
neighbors = vector<Node*>();
}
Node(int _val) {
val = _val;
neighbors = vector<Node*>();
}
Node(int _val, vector<Node*> _neighbors) {
val = _val;
neighbors = _neighbors;
}
};
*/
class Solution {
public:
Node* cloneGraph(Node* node) {
if ( !node ) return NULL; // 特殊情况:无内容时返回空
queue<Node *> m_queue; // 定义队列 BFS
map<Node *,Node *> m_map; // 定义映射
Node *temp; // 映射中的键
Node *p; // 映射中的值
m_queue.push(node); //第一个结点入队
//首先BFS所有节点,创建新节点,并保存新节点与原节点的映射关系
while(!m_queue.empty()){
//出队元素
temp = m_queue.front();
m_queue.pop();
//新节点创建
p = new Node(temp->val,{});
m_map.insert({temp,p});
//入队元素
for( Node *neighborsNode : temp->neighbors ) {
if( m_map.find(neighborsNode) == m_map.end() ) { //如果该节点已经有了映射关系,则不入队
m_queue.push(neighborsNode);
}
}
}
//遍历所有节点 完成边的链接
map<Node *,Node *>::iterator iter;
for( iter = m_map.begin(); iter != m_map.end(); ++iter ){
for( Node *neighborsNode : iter->first->neighbors ) {
iter->second->neighbors.push_back(m_map.find(neighborsNode)->second);
}
}
return m_map.find(node)->second;
}
};
297. 二叉树的序列化与反序列化
其中一种解法,使用了< sstream >中的类 stringstream
string serialize(TreeNode* root) {
if(!root) return "";
stringstream ss;
queue<TreeNode*> Q;
Q.push(root);
while(Q.size()){
TreeNode* p = Q.front();Q.pop();
if(!p) ss <<"# ";
else{
ss << p->val <<" ";
Q.push(p->left);
Q.push(p->right);
}
}
return ss.str();
}
TreeNode* deserialize(string data) {
if(data.empty()) return NULL;
stringstream ss(data);
string t;
ss >> t;
TreeNode* rt = new TreeNode(stoi(t)); //stoi 将字符串转化为10进制
queue<TreeNode*> Q;
Q.push(rt);
while(Q.size()){
TreeNode* p = Q.front();Q.pop();
ss >> t;
if(t[0] == '#'){
p->left = NULL;
}else{
p->left = new TreeNode(stoi(t));
Q.push(p->left);
}
ss >> t;
if(t[0] == '#'){
p->right = NULL;
}else{
p->right = new TreeNode(stoi(t));
Q.push(p->right);
}
}
return rt;
}
作者:jason-2
链接:https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/solution/liang-chong-jie-fa-by-jason-2-13/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
另外一种解法感觉用的是DFS,会更加简单一些。 ostringstream:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Codec {
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
ostringstream out;
serialize(root,out);
return out.str();
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
istringstream in(data);
return deserialize(in);
}
private:
void serialize(TreeNode* root,ostringstream& out){
if(root){
out<<root->val<<' ';
serialize(root->left,out);
serialize(root->right,out);
}else{
out<<"# ";
}
}
TreeNode* deserialize(istringstream& in){
string val;
in>>val;
if(val=="#"){
return nullptr;
}
TreeNode* root=new TreeNode(stoi(val));
root->left=deserialize(in);
root->right=deserialize(in);
return root;
}
};
// Your Codec object will be instantiated and called as such:
// Codec codec;
// codec.deserialize(codec.serialize(root));
作者:ZZYuting
链接:https://leetcode-cn.com/problems/serialize-and-deserialize-binary-tree/solution/c-version-by-zzyuting/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
127. 单词接龙
思路
1、单词预处理做成邻接表
2、双向bfs
注意:
1、使用size_t可能会提高代码的可移植性、有效性或者可读性。size_t类型是一个类型定义,通常将一些无符号的整形定义为size_t,比如说unsigned int或者unsigned long,甚至unsigned long long。每一个标准C实现应该选择足够大的无符号整形来代表该平台上最大可能出现的对象大小。
2、map与unordered_map的区别
3、双向bfs:知道起点和终点,从两个方向分别搜索,极大提高单个bfs的搜索效率
int ladderLength(string beginWord, string endWord, vector<string>& wordList)
{
if (beginWord == endWord) return 1; // 如果两个单词相同不符合题意,直接返回
bool flag = true; // 用于判断是否直接返回
map<string, vector<string>> comboList; // 用于做成连接表,存放hit的三种类型: *it h*t hi*
for (auto w : wordList)
{
if (w == endWord) // 迭代边界
{
flag = false; // 找到 endword
}
for (size_t i = 0; i < w.size(); i++)
{
auto temp = w;
temp[i] = '*';
comboList[temp].push_back(w);
}
}
if (flag) return 0; // 找不到endword无法转换,直接返回 0
unordered_map<string, int> vi[2]; // 双向BFS,vi[0]和vi[1]是双向的步数
queue<string> que[2];
que[0].push(beginWord);
vi[0][beginWord] = 1;
que[1].push(endWord);
vi[1][endWord] = 1;
while (!que[0].empty() || !que[1].empty())
{
int k = (que[0].size() < que[1].size()) ? 0 : 1; //三元运算符,哪个长度短选哪个,交替处理两个队列
k = (que[k].size() == 0) ? (k + 1) % 2 : k; // 如果是空的,转向另一个
auto& qr = (que[0].size() < que[1].size()) ? que[0] : que[1]; //好像没用
for (int i = que[k].size(); i > 0; i--) // 循环处理队列元素
{
auto q = que[k].front(); // 出队
que[k].pop();
for (size_t i = 0; i < q.size(); i++) // 查找转换的下一个单词
{
auto temp = q;
temp[i] = '*';
for (auto w : comboList[temp]) // 找到了就导出双向步数之和,没找到就步数加一,入队下一组单词。
{
if (vi[k].count(w) != 0) continue;
int k2 = (k + 1) % 2;
if (vi[k2].count(w) != 0)
{
return vi[k2][w] + vi[k][q];
}
que[k].push(w);
vi[k][w] = vi[k][q] + 1;
}
}
}
}
return 0;
}
作者:ikaruga
链接:https://leetcode-cn.com/problems/word-ladder/solution/127-by-ikaruga/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。