Leetcode算法刷题笔记1-链表
Leetcode算法刷题笔记2-栈、队、堆
Leetcode算法刷题笔记3-递归与回溯
Leetcode算法刷题笔记4-贪心
Leetcode算法刷题笔记5-二叉树
Leetcode算法刷题笔记6-图
Leetcode算法刷题笔记7-动态规划
Leetcode算法刷题笔记8-二分查找
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/course-schedule/
你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
示例 1:
输入: 2, [[1,0]] 输出: true 解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
示例 2:
输入: 2, [[1,0],[0,1]] 输出: false 解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程
0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
提示:
输入的先决条件是由 边缘列表 表示的图形,而不是邻接矩阵 。
详情请参见图的表示法。
你可以假定输入的先决条件中没有重复的边。
1 <= numCourses <= 10^5
#include
using namespace std;
struct GraphNode{
int label;
vector<GraphNode *> neighbors;
GraphNode(int x) :label(x){};
};
//Leetcode提交部分
class Solution {
public:
bool canFinish(int numCourses, vector<pair<int,int> > & prerequisites) {
vector<GraphNode*>graph;
vector<int> degree;
for(int i=0;i<numCourses;i++){
degree.push_back(0);
graph.push_back(new GraphNode(i));
}
for(int i=0;i<prerequisites.size();i++){
GraphNode *end = graph[prerequisites[i].first];
GraphNode *begin = graph[prerequisites[i].second];
begin->neighbors.push_back(end);
degree[prerequisites[i].first]++;
}
queue<GraphNode*> Q;
for(int i=0;i<numCourses;i++){
if(degree[i]==0){
Q.push(graph[i]);
}
}
while(!Q.empty()){
GraphNode* node = Q.front();
Q.pop();
for(int i=0;i<node->neighbors.size();i++){
degree[node->neighbors[i]->label]--;
if(degree[node->neighbors[i]->label]==0){
Q.push(node->neighbors[i]);
}
}
}
for(int i=0;i<graph.size();i++){
delete graph[i];
}
for(int i=0;i<degree.size();i++){
if(degree[i]){
return false;
}
}
return true;
}
};
//Leetcode自行使用编译器(如DEV\VC\VS)测试部分
int main(){
vector<pair<int,int> >prerequisites;
prerequisites.push_back(make_pair(1,0));
prerequisites.push_back(make_pair(2,0));
prerequisites.push_back(make_pair(3,1));
prerequisites.push_back(make_pair(3,2));
Solution solve;
cout<<solve.canFinish(4,prerequisites)<<endl;
return 0;
}
#include
using namespace std;
struct GraphNode{
int label;
vector<GraphNode *> neighbors;
GraphNode(int x) :label(x){};
};
//Leetcode提交部分
class Solution {
public:
bool canFinish(int numCourses, vector<pair<int,int> >&prerequisites) {
vector<int> visit;
vector<GraphNode*> graph;
for(int i=0;i<numCourses;i++){
graph.push_back(new GraphNode(i));
visit.push_back(-1);
}
for(int i=0;i<prerequisites.size();i++){
GraphNode *end = graph[prerequisites[i].first];
GraphNode *begin = graph[prerequisites[i].second];
begin->neighbors.push_back(end);
}
for(int i=0;i<graph.size();i++){//深度搜索,
if(visit[i]==-1&&!DFS_graph(graph[i],visit)){
return false;//如果节点没有访问国,进行dfs,遇到环
}//就返回false
}
for(int i=0;i<numCourses;i++){
delete graph[i];
}
return true;
}
private:
bool DFS_graph(GraphNode* root,vector<int> &visit){
visit[root->label] = 0;
for(int i=0;i<root->neighbors.size();i++){
if(visit[root->neighbors[i]->label]==-1){
if(DFS_graph(root->neighbors[i],visit)==0){
return false;
}
}else if(visit[root->neighbors[i]->label]==0){
return false;
}
}
visit[root->label]=1;
return true;
}
};
//Leetcode自行使用编译器(如DEV\VC\VS)测试部分
int main(){
vector<pair<int,int> >prerequisites;
prerequisites.push_back(make_pair(1,0));
prerequisites.push_back(make_pair(2,0));
prerequisites.push_back(make_pair(3,1));
prerequisites.push_back(make_pair(3,2));
Solution solve;
cout<<solve.canFinish(4,prerequisites)<<endl;
return 0;
}
/**天空树 2019.4.23
有向图不可以使用!!!
假定:图顶点个数为M,边条数为E
遍历一遍,判断图分为几部分(假定为P部分,即图有 P 个连通分量)
对于每一个连通分量,如果无环则只能是树,即:边数=结点数-1
只要有一个满足 边数 > 结点数-1
原图就有环
将P个连通分量的不等式相加,就得到:
P1:E1=M1-1
P2:E2=M2-1
...
PN:EN>MN-1
所有边数(E) > 所有结点数(M) - 连通分量个数(P)
即: E + P > M 所以只要判断结果 E + P > M 就表示原图有环,否则无环.
**/
#include
#include
using namespace std;
#define maxNum 100 //定义邻接举证的最大定点数
int visited[maxNum];//通过visited数组来标记这个顶点是否被访问过,0表示未被访问,1表示被访问
int DFS_Count;//连通部件个数,用于测试无向图是否连通,DFS_Count=1表示只有一个连通部件,所以整个无向图是连通的
int pre[maxNum];
int post[maxNum];
int point;//pre和post的值
//图的邻接矩阵表示结构
typedef struct
{
char v[maxNum];//图的顶点信息
int e[maxNum][maxNum];//图的顶点信息
int vNum;//顶点个数
int eNum;//边的个数
}graph;
void createGraph(graph *g);//创建图g
void DFS(graph *g);//深度优先遍历图g
void dfs(graph *g,int i);//从顶点i开始深度优先遍历与其相邻的点
void dfs(graph *g,int i)
{
//cout<<"顶点"<v[i]<<"已经被访问"<
cout<<"顶点"<<i<<"已经被访问"<<endl;
visited[i]=1;//标记顶点i被访问
pre[i]=++point;
for(int j=1;j<=g->vNum;j++)
{
if(g->e[i][j]!=0&&visited[j]==0)
dfs(g,j);
}
post[i]=++point;
}
void DFS(graph *g)
{
int i;
//初始化visited数组,表示一开始所有顶点都未被访问过
for(i=1;i<=g->vNum;i++)
{
visited[i]=0;
pre[i]=0;
post[i]=0;
}
//初始化pre和post
point=0;
//初始化连通部件数为0
DFS_Count=0;
//深度优先搜索
for(i=1;i<=g->vNum;i++)
{
if(visited[i]==0)//如果这个顶点为被访问过,则从i顶点出发进行深度优先遍历
{
DFS_Count++;//统计调用void dfs(graph *g,int i);的次数
dfs(g,i);
}
}
}
void createGraph(graph *g)//创建图g
{
cout<<"正在创建无向图..."<<endl;
cout<<"请输入顶点个数vNum:";
cin>>g->vNum;
cout<<"请输入边的个数eNum:";
cin>>g->eNum;
int i,j;
//输入顶点信息
//cout<<"请输入顶点信息:"<
//for(i=0;ivNum;i++)
// cin>>g->v[i];
//初始画图g
for(i=1;i<=g->vNum;i++)
for(j=1;j<=g->vNum;j++)
g->e[i][j]=0;
//输入边的情况
cout<<"请输入边的头和尾"<<endl;
for(int k=0;k<g->eNum;k++)
{
cin>>i>>j;
g->e[i][j]=1;
g->e[j][i]=1;//无向图对称
}
}
int main()
{
graph *g;
g=(graph*)malloc(sizeof(graph));
createGraph(g);//创建图g
DFS(g);//深度优先遍历
//连通部件数,用于判断是否连通图
cout<<"连通部件数量:";
cout<<DFS_Count<<endl;
if(DFS_Count==1)
cout<<"图g是连通图"<<endl;
else if(DFS_Count>1)
cout<<"图g不是连通图"<<endl;
//各顶点的pre和post值
for(int i=1;i<=g->vNum;i++)
cout<<"顶点"<<i<<"的pre和post分别为:"<<pre[i]<<" "<<post[i]<<endl;
//cout<
//判断无向图中是否有环
if(g->eNum+DFS_Count>g->vNum)
cout<<"图g中存在环"<<endl;
else
cout<<"图g中不存在环"<<endl;
int k;
cin>>k;
return 0;
}
/*
输入:
正在创建无向图...
请输入顶点个数vNum:10
请输入边的个数eNum:9
请输入边的头和尾
1 2
1 4
2 5
2 6
4 7
5 9
6 3
7 8
9 10
*/
/**天空树 2019.4.16
图中的一个节点,根据其C[N]的值,有三种状态:
0,此节点没有被访问过
-1,被访问过至少1次,其后代节点正在被访问中
1,其后代节点都被访问过。
按照这样的假设,当按照DFS进行搜索时,碰到一个节点时有三种可能:
1、如果C[V]=0,这是一个新的节点,不做处理
2、如果C[V]=-1,说明是在访问该节点的后代的过程中访问到该节点本身,则图中有环。
3、如果C[V]=1,类似于2的推导,没有环。 在程序中加上一些特殊的处理,即可以找出图中有几个环,并记录每个环的路径
**/
#include
#include
using namespace std;
#define maxNum 100 //定义邻接举证的最大定点数
int pre[maxNum];
int post[maxNum];
int point=0;//pre和post的值
bool is_DAG=true;//标识位,表示有向无环图
/*
顶点颜色表 color[u]
0 白色,未被访问过的节点标白色
-1 灰色,已经被访问过一次的节点标灰色
1 黑色,当该节点的所有后代都被访问过标黑色
反向边:
如果第一次访问(u,v)时v为灰色,则(u,v)为反向边。在对图的深度优先搜索中没有发现
反向边,则该图没有回路
程序判断依据:
仍然是按图的节点深度遍历,访问到V时,V若被访问过,那么有2种状态:
color[u]=-1,程序跳出,存在环
color[u]=1,程序继续,这不是环
时间复杂度:O(n+e)
*/
int color[maxNum];//顶点颜色表 color[u]
//图的邻接矩阵表示结构
typedef struct
{
char v[maxNum];//图的顶点信息
int e[maxNum][maxNum];//图的顶点信息
int vNum;//顶点个数
int eNum;//边的个数
}graph;
void createGraph(graph *g);//创建图g
void DFS(graph *g);//深度优先遍历图g
void dfs(graph *g,int i);//从顶点i开始深度优先遍历与其相邻的点
void dfs(graph *g,int i)
{
//cout<<"顶点"<v[i]<<"已经被访问"<
cout<<"顶点"<<i<<"已经被访问"<<endl;
color[i]=-1;
pre[i]=++point;
for(int j=1;j<=g->vNum;j++)
{
if(g->e[i][j]!=0)
{
if(color[j]==-1)//探索到回边,存在环
{
is_DAG=false;//不是有向无环图
}
else if(color[j]==0)
dfs(g,j);
}
}
post[i]=++point;
color[i]=1;//表示i的后裔节点都被访问过
}
void DFS(graph *g)
{
int i;
//初始化color数组,表示一开始所有顶点都未被访问过,//初始化pre和post
for(i=1;i<=g->vNum;i++)
{
color[i]=0;
pre[i]=0;
post[i]=0;
}
//深度优先搜索
for(i=1;i<=g->vNum;i++)
{
if(color[i]==0)//如果这个顶点为被访问过,则从i顶点出发进行深度优先遍历
{
dfs(g,i);
}
}
}
void createGraph(graph *g)//创建图g
{
cout<<"正在创建有向图..."<<endl;
cout<<"请输入顶点个数vNum:";
cin>>g->vNum;
cout<<"请输入边的个数eNum:";
cin>>g->eNum;
int i,j;
//初始画图g
for(i=1;i<=g->vNum;i++)
for(j=1;j<=g->vNum;j++)
g->e[i][j]=0;
//输入边的情况
cout<<"请输入边的头和尾"<<endl;
for(int k=1;k<=g->eNum;k++)
{
cin>>i>>j;
g->e[i][j]=1;
}
}
int main()
{
graph *g;
g=(graph*)malloc(sizeof(graph));
createGraph(g);//创建图g
DFS(g);//深度优先遍历
//各顶点的pre和post值
for(int i=1;i<=g->vNum;i++)
cout<<"顶点"<<i<<"的pre和post分别为:"<<pre[i]<<" "<<post[i]<<endl;
//判断是否是有向无环图
if(is_DAG)
cout<<"图g是有向无环图,没有环"<<endl;
else
cout<<"图g不是有向无环图,存在环"<<endl;
int k;
cin>>k;
return 0;
}
/*
输入1:
正在创建无向图...
请输入顶点个数vNum:3
请输入边的个数eNum:3
请输入边的头和尾
1 2
1 3
3 2
输入2:
正在创建无向图...
请输入顶点个数vNum:4
请输入边的个数eNum:4
请输入边的头和尾
1 2
2 3
3 4
4 2
*/