package Graph;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Set; public class GraphProblem { public static void main(String[] args) {
// TODO Auto-generated method stub }
/*
* 207. Course Schedule
* 2016-3-28 by jyuan
* BFS:典型的拓扑排序。原理也很简单,在一个有向图中,每次找到一个没有前驱节点的节点(也就是入度为0的节点),
* 然后把它指向其他节点的边都去掉,重复这个过程(BFS),直到所有节点已被找到,或者没有符合条件的节点(如果图中有环存在)。。
* DFS的解法,也需要建立有向图,还是用二维数组来建立,和BFS不同的是,我们像现在需要一个一维数组visit来记录访问状态,
* 大体思路是,先建立好有向图,然后从第一个门课开始,找其可构成哪门课,暂时将当前课程标记为已访问,
* 然后对新得到的课程调用DFS递归,直到出现新的课程已经访问过了,则返回false,没有冲突的话返回true,然后把标记为已访问的课程改为未访问
* http://www.jyuan92.com/blog/leetcode-course-schedule/
*/
public boolean canFinishWithBFS(int numCourses, int[][] prerequisites) {
if (null == prerequisites || numCourses == 0 || prerequisites.length == 0) {
return true;
}
int[] preCourses = new int[numCourses];
// store the in-degree #
for (int[] prerequisite : prerequisites) {
preCourses[prerequisite[0]]++;
}
Queue<Integer> queue = new LinkedList<Integer>();
for (int i = 0; i < preCourses.length; i++) {
if (preCourses[i] == 0) {
queue.add(i);
}
}
int numOfPreCourse = 0;
while (!queue.isEmpty()) {
int top = queue.poll();
numOfPreCourse++;
for (int[] prerequisite : prerequisites) {
if (prerequisite[1] == top) {//Find all the neighbor
preCourses[prerequisite[0]]--;
if (preCourses[prerequisite[0]] == 0) {
queue.add(prerequisite[0]);
}
}
}
}
return numOfPreCourse == numCourses;
}
/*
* 210 Course ScheduleII
* 2016-3-28 by jyuan
* http://www.jyuan92.com/blog/leetcode-course-schedule-ii/
*/
public int[] findOrder(int numCourses, int[][] prerequisites) {
int[] res = new int[numCourses];//区别1,多了一个装order的array
int[] preCourses = new int[numCourses];
// store the in-degree #
for (int[] prerequisite : prerequisites) {
preCourses[prerequisite[0]]++;
}
Queue<Integer> queue = new LinkedList<Integer>();
for (int i = 0; i < preCourses.length; i++) {
if (preCourses[i] == 0) {
queue.add(i);
}
}
int numOfPreCourse = 0;
int i = 0;//区别2,多了一个i来遍历res
while (!queue.isEmpty()) {
int top = queue.poll();
res[i++] = top;
numOfPreCourse++;
for (int[] prerequisite : prerequisites) {
if (prerequisite[1] == top) {
preCourses[prerequisite[0]]--;
if (preCourses[prerequisite[0]] == 0) {
queue.add(prerequisite[0]);
}
}
}
}//最后再多一个判断,就是返回是否是需要return新的
if (numOfPreCourse == numCourses) {
return res;
} else {
return new int[0];
}
}
/*
* 下面给出207的DFS方法:
* DFS的思路就简单一点,就是首先构造图的Map,每一个点包含一个list,表明这个点作为这个list
* 每一门课程的前备课程以待后用。那么主体思路就是每一个点为起点做一次dfs,知道底端,
* 如果没有问题就continue,如果有问题直接return false。
* 那么在主体部分,几个状态,如果为-1表示已经访问过肯定return false,如果为1表示这条路
* 已经是通路,已经验证完毕,所有连接这个点的直接return true。
*/
public boolean canFinishWithDFS(int numCourses, int[][] prerequisites) {
if (null == prerequisites || numCourses == 0 || prerequisites.length == 0) {
return true;
}
int[] isVisited = new int[numCourses];
Map<Integer, ArrayList<Integer>> map = new HashMap<Integer, ArrayList<Integer>>();
for (int[] prerequisite : prerequisites) {
if (!map.containsKey(prerequisite[1])) {
map.put(prerequisite[1], new ArrayList<Integer>());
}
map.get(prerequisite[1]).add(prerequisite[0]);
}
for (int i = 0; i < numCourses; i++) {
if (!dfs(isVisited, map, i)) {
return false;
}
}
return true;
}
private boolean dfs(int[] isVisited, Map<Integer, ArrayList<Integer>> map, int index) {
if (isVisited[index] == -1) {
return false;
}
if (isVisited[index] == 1) {
return true;
}
isVisited[index] = -1;//假如最后一个点进来,先赋值-1,然后没有map的值,所以直接为1,以后所有遇到这个点的都是通路
if (map.containsKey(index)) {
for (int value : map.get(index)) {
if (!dfs(isVisited, map, value)) {
return false;
}
}
}
isVisited[index] = 1;
return true;
}
/*
* 下面给出210的DFS方法:
*/
int i;//区别1全局变量i
public int[] findOrderWithDFS(int numCourses, int[][] prerequisites) {
i = numCourses - 1;
int[] res = new int[numCourses];
int[] isVisited = new int[numCourses];
Map<Integer, ArrayList<Integer>> map = new HashMap<Integer, ArrayList<Integer>>();
for (int[] prerequisite : prerequisites) {
if (!map.containsKey(prerequisite[1])) {
map.put(prerequisite[1], new ArrayList<Integer>());
}
map.get(prerequisite[1]).add(prerequisite[0]);
}
for (int i = 0; i < numCourses; i++) {
if (!dfs(map, isVisited, res, i)) {
return new int[0];
}
}
return res;
}
private boolean dfs(Map<Integer, ArrayList<Integer>> map, int[] isVisited, int[] res, int index) {
if (isVisited[index] == -1) {
return false;
}
if (isVisited[index] == 1) {
return true;
}
isVisited[index] = -1;
if (map.containsKey(index)) {
for (int value : map.get(index)) {
if (!dfs(map, isVisited, res, value)) {
return false;
}
}
}
res[i--] = index;
isVisited[index] = 1;
return true;
}
/*
* 261.Graph Valid Tree
* 2016-3-29 by Buttercola
* 和上面的BFS方法一样,不过这里是无向图,所以需要两个点都要存对方
* 图要形成树必须有两个方面,一个是没有cycle另一个是没有孤立的点
* Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes),
* write a function to check whether these edges make up a valid tree.
* Given n = 5 and edges = [[0, 1], [0, 2], [0, 3], [1, 4]], return true.
* Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]], return false.
*/
private boolean valid(int n, int[][] edges) {
// build the graph using adjacent list
List<Set<Integer>> graph = new ArrayList<Set<Integer>>();
for(int i = 0; i < n; i++)
graph.add(new HashSet<Integer>());
for(int[] edge : edges) {
graph.get(edge[0]).add(edge[1]);
graph.get(edge[1]).add(edge[0]);
}
// no cycle
boolean[] visited = new boolean[n];
Queue<Integer> queue = new LinkedList<Integer>();
queue.add(0);
while(!queue.isEmpty()) {
int node = queue.poll();
if(visited[node])
return false;
visited[node] = true;
for(int neighbor : graph.get(node)) {
queue.offer(neighbor);
graph.get(neighbor).remove((Integer)node);
}
}
// fully connected
for(boolean result : visited){
if(!result)
return false;
}
return true;
}
/*
* 310. Minimum Height Trees
* 2016-3-29 by Mingyang
* 同样的方法构建无向图
* 这里运用的一个层层剥丝的方式,一层一层的来,去掉不要的
*/
public List<Integer> findMinHeightTrees(int n, int[][] edges) {
if (n == 1) return Collections.singletonList(0);
List<Set<Integer>> adj = new ArrayList<Set<Integer>>(n);
for (int i = 0; i < n; ++i) adj.add(new HashSet<Integer>());
for (int[] edge : edges) {
adj.get(edge[0]).add(edge[1]);
adj.get(edge[1]).add(edge[0]);
}
List<Integer> leaves = new ArrayList<Integer>();
for (int i = 0; i < n; ++i)
if (adj.get(i).size() == 1) leaves.add(i);
while (n > 2) {
n -= leaves.size();
List<Integer> newLeaves = new ArrayList<Integer>();
for (int i : leaves) {
int j = adj.get(i).iterator().next();
adj.get(j).remove(i);
if (adj.get(j).size() == 1) newLeaves.add(j);
}
leaves = newLeaves;
}
return leaves;
}
/*
* 332. Reconstruct Itinerary
* 2016-3-14 by Mingyang
* 这道题给我们一堆飞机票,让我们建立一个行程单,如果有多种方法,取其中字母顺序小的那种方法。
* 这道题的本质是有向图的遍历问题,那么LeetCode关于有向图的题只有两道Course Schedule和Course Schedule II,
* 而那两道是关于有向图的顶点的遍历的,而本题是关于有向图的边的遍历。
* 每张机票都是有向图的一条边,我们需要找出一条经过所有边的路径,那么DFS不是我们的不二选择。
* 代码前半段都在准备工作。把所有的tickets全部装进一个map,string对应了一个priority queue
* 后半段dfs中,找出第一个顺序的结果。最终输出是从最后一个开始,一个一个往前退的情况下addFirst加起来的
*/
HashMap<String, PriorityQueue<String>> map = new HashMap<String, PriorityQueue<String>>();
LinkedList<String> result = new LinkedList<String>();
public List<String> findItinerary(String[][] tickets) {
for (String[] ticket : tickets) {
if (!map.containsKey(ticket[0])) {
PriorityQueue<String> q = new PriorityQueue<String>();
map.put(ticket[0], q);
}
map.get(ticket[0]).offer(ticket[1]);
}
dfs("JFK");
return result;
}
public void dfs(String s) {
PriorityQueue<String> q = map.get(s);
while (q != null && !q.isEmpty()) {
dfs(q.poll());
}
result.addFirst(s);
}
/*
* 323 Number of Connected Components in an Undirected Graph
* 2016-4-2 by Mingyang
* Given n nodes labeled from 0 to n - 1 and
* a list of undirected edges (each edge is a pair of nodes),
* write a function to find the number of connected components in an undirected graph.
* You can assume that no duplicate edges will appear in edges.
* Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.
*/
public int countComponents(int n, int[][] edges) {
if (n <= 1) {
return n;
}
List<List<Integer>> adjList = new ArrayList<List<Integer>>();
for (int i = 0; i < n; i++) {
adjList.add(new ArrayList<Integer>());
}
for (int[] edge : edges) {
adjList.get(edge[0]).add(edge[1]);
adjList.get(edge[1]).add(edge[0]);
}
boolean[] visited = new boolean[n];
int count = 0;
for (int i = 0; i < n; i++) {
if (!visited[i]) {
count++;
dfs(visited, i, adjList);
}
}
return count;
}
public void dfs(boolean[] visited, int index, List<List<Integer>> adjList) {
visited[index] = true;
for (int i : adjList.get(index)) {
if (!visited[i]) {
dfs(visited, i, adjList);
}
}
}
}

Leetcode总结之Graph的更多相关文章

  1. [Leetcode Week3]Clone Graph

    Clone Graph题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/clone-graph/description/ Description Clon ...

  2. [LeetCode] 785. Is Graph Bipartite? 是二分图么?

    Given an undirected graph, return true if and only if it is bipartite. Recall that a graph is bipart ...

  3. LeetCode 785. Is Graph Bipartite?

    原题链接在这里:https://leetcode.com/problems/is-graph-bipartite/ 题目: Given an undirected graph, return true ...

  4. [LeetCode] 133. Clone Graph 克隆无向图

    Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. OJ's ...

  5. leetcode 133. Clone Graph ----- java

    Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. OJ's ...

  6. 【leetcode】Clone Graph(python)

    类似于二叉树的三种遍历,我们能够基于遍历的模板做非常多额外的事情,图的两种遍历,深度和广度模板相同也能够做非常多额外的事情,这里举例利用深度优先遍历的模板来进行复制,深度优先中,我们先訪问第一个结点, ...

  7. [LeetCode] 785. Is Graph Bipartite?_Medium tag: DFS, BFS

    Given an undirected graph, return true if and only if it is bipartite. Recall that a graph is bipart ...

  8. [leetcode]785. Is Graph Bipartite? [bai'pɑrtait] 判断二分图

    Given an undirected graph, return true if and only if it is bipartite. Example 1: Input: [[1,3], [0, ...

  9. Java for LeetCode 133 Clone Graph

    Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. OJ's ...

随机推荐

  1. LeetCode(123) Best Time to Buy and Sell Stock III

    题目 Say you have an array for which the ith element is the price of a given stock on day i. Design an ...

  2. POJ 3057 网络流 Evacuation

    题意: 有一个n×m的房间,四周每个格子要么是墙要么是门.中间部分是墙或者人. 现在所有人要从房间逃出去,每个人的速度为1,也就是每个单位时间只能向上下左右四个方向走一格. 多个人可以站在同一个格子上 ...

  3. 实现类似QQ单一账户登录,在另一个地方登录后在原登录窗口提示下线

    首先,使用框架做的最好,可以在框架页直接做一次就好了 再登陆成功后保存session的代码后添加以下代码: 注意:需要引入命名空间using System.Collections; SetApplic ...

  4. 如何在官网下载Spring jar包

    该链接里面讲的很仔细! http://blog.csdn.net/frankarmstrong/article/details/69808813

  5. python 查看异常

    接触python 一直觉着编译后报错经常没能捕捉显示,每次也只能从头看到尾 恰好在水木社区中看到关于异常捕捉帖子 方法一:捕获所有异常 try: a=b b=c except Exception,ex ...

  6. how can I ues Dataset to shuffle a large whole dataset?

    The Dataset.shuffle() implementation is designed for data that could be shuffled in memory; we're co ...

  7. 【Luogu】P2254瑰丽华尔兹(堆优化DP)

    题目链接 我也不知道为什么脑子一抽就想了个堆优化……然后贼慢…… 因为上午听不懂wys的电音专场(快速傅立叶变换),然后就做了这么一道题. 首先朴素DP很sb都能秒出.就是枚举时刻.位置(两维)然后转 ...

  8. ACM程序设计选修课——1057: Beautiful Garden(模拟+耐心调试)

    1057: Beautiful Garden Time Limit: 5 Sec  Memory Limit: 128 MB Submit: 25  Solved: 12 [Submit][Statu ...

  9. P2622 关灯问题II (状态压缩,最短路)

    题目链接 Solution 这道题算是很经典的状压问题了,好题. 考虑到 \(n\) 的范围仅为 \(10\) , 那么也就是说所有状态压起来也只有 \(1024\) 种情况. 然后我们发现 \(m\ ...

  10. [SCOI2008]配对 (贪心,动态规划)

    题目链接 Solution 很妙的DP,很妙的贪心. 首先考虑,如果说没有那个相同的不能配对的情况; 那么我们肯定是直接排两遍序,然后一一对应即可. 但是是有限制的,同时我们可得几个条件供贪心: 每个 ...