LeetCode DFS Course Schedule 课程表 Find Eventual Safe States找到最终的安全状态

题目链接:

1、Course Schedule  https://leetcode.com/problems/course-schedule/

2、Find Eventual Safe States   https://leetcode.com/problems/find-eventual-safe-states/

这两题有相似性很高,区别在于第一题是判断这个图中有没有环,第二题是找出连接图中环的节点以及环上的节点

 

这是DFS专栏,所以暂时不考虑BFS解法

 

第一题其实很像拓扑排序,但是向无环图(DAG)是拓扑排序的充要条件。题目的本意是要判断是不是DAG,所以和拓扑排序还是 有点差别。(拓扑排序也有DFS和两种解法)

 

解法1:

使用visit数组来保存图中每一个节点的访问情况,visit[i] = 1表示 i 节点被访问了。(本解法不适用第二题,会出现TLE)

//
class Solution {
public:
// if loop, return true
	bool dfs(int node,vector<int>& visit, vector<vector<int>>& graph)
	{
		

		
		if(visit[node] == 1)
		{
			return true;
		}
		
		visit[node] = 1;

		vector<int> temp = graph[node];
		for(int i=0;i<graph[node].size();i++)
		{


			if(dfs(temp[i],visit,graph))
			{
				return true;
			}
			/*//will TLE
			vector<int> temp = prerequisites[i];
			if(temp[1] == node )//&& visit[temp[0]] == 0)
			{
				if(dfs(temp[0],visit,prerequisites))
				{
					return true;
				}
			}
			*/
		}

		visit[node] = 0;
		return false;
	}
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {

    	vector<int> visit(numCourses,0);
    	vector<vector<int>> graph(numCourses, vector<int>());
    	

    	for(int j=0;j<prerequisites.size();j++)
    	{
    		vector<int> temp = prerequisites[j];
    		graph[temp[1]].push_back(temp[0]);
    		//graph[prerequisites[j][1]].push_back(prerequisites[j][0]);
    	}
    	for(int i=0;i<numCourses;i++)
    	{

    		
    		if(dfs(i,visit,graph))
    		{
    			return false;
    		}
    		
    	}
    	return true;



        
    }
};

 

解法2:

如同解法1一样,使用visit数组来保存图中每一个节点的访问情况,不同于解法1的是,visit数组包括初始状态0会有3个状态,visit[i] = 1表示 i 节点正在被访问,visit[i] = 2表示 i 节点已经被访问过了。visit[i] = 2意味着 i 节点的没有其他的延伸节点可以再被访问了。“没有其他的延伸节点可以再被访问了”有两种情形:一是这个节点没有出度,二是该节点的连接节点没有其他的延伸节点可以再被访问了。

可以看到看到“没有其他的延伸节点可以再被访问了”是一种递归

算法步骤:从图中的任意节点开始进行遍历,标记该节点为正在访问,搜索该节点的其它连接节点,若是其它连接节点会出现环,则结束算法,否则就走下去,直到所有节点都已经被遍历过,标记该节点为已经被访问了

//
class Solution {
public:
// if loop, return true
	bool dfs(int node,vector<int>& visit, vector<vector<int>>& graph)
	{
		
		if(visit[node] == 2)
		{
			return false;
		}
		
		if(visit[node] == 1)
		{
			return true;
		}
		
		visit[node] = 1;

		vector<int> temp = graph[node];
		for(int i=0;i<graph[node].size();i++)
		{


			if(dfs(temp[i],visit,graph))
			{
				return true;
			}
			/*//will TLE
			vector<int> temp = prerequisites[i];
			if(temp[1] == node )//&& visit[temp[0]] == 0)
			{
				if(dfs(temp[0],visit,prerequisites))
				{
					return true;
				}
			}
			*/
		}

		visit[node] = 2;
		return false;
	}
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {

    	vector<int> visit(numCourses,0);
    	vector<vector<int>> graph(numCourses, vector<int>());
    	

    	for(int j=0;j<prerequisites.size();j++)
    	{
    		vector<int> temp = prerequisites[j];
    		graph[temp[1]].push_back(temp[0]);
    		//graph[prerequisites[j][1]].push_back(prerequisites[j][0]);
    	}
    	for(int i=0;i<numCourses;i++)
    	{

    		
    		if(dfs(i,visit,graph))
    		{
    			return false;
    		}
    		
    	}
    	return true;



        
    }
};

 

Note:

1、prerequisites要处理成graph,若是在dfs中直接使用prerequisites(如dfs中注释所示),会出现TLE。

2、graph传参时候需要注意使用引用,若是值传递会出现TLE。(传递的是STL容器,对象使用引用传递,int,char这种使用值传递)

3、解法2的效率要比解法1的效率好,解法1中只有两个状态,其visit[i] = 0 状态是包括了解法2中visit[i] = 2和visit[i] = 0两种状态,visit[i] = 1 如同解法2中的 visit[i] = 1。由于visit[i] = 0 的多义性造成了多余深搜。

4、canFinish函数调用dfs在循环之内是因为可能图并不是连通图。

 

图后期补上……

 

 

 

上一篇:PHP项目以连接到硬件


下一篇:WordPress网站加速优化,一键免费使用七牛CDN插件