LintCode图论&搜索题总结

LintCode上Graph & Search那一章有这些题目:



15. Permutations

给定一连串数字,要求它的所有可能的排列。

比如123的全排列为[123, 132, 213, 231, 312, 321]

这道题用DFS搜索,递归搜索树如下所示:


画出递归搜索树之后,代码自然就不难了。

每次加入list数组中的元素不能在之前出现过。

    public ArrayList<ArrayList<Integer>> permute(ArrayList<Integer> nums) {
        ArrayList<ArrayList<Integer> > res = new ArrayList();
        if (nums == null || nums.size() == 0) {
            return res;
        }
        ArrayList<Integer> list = new ArrayList<Integer>();
        helper(res, list, nums);
        return res;
    }
    
    private void helper(ArrayList<ArrayList<Integer>> res, ArrayList<Integer> list, ArrayList<Integer> nums) {
        if (list.size() == nums.size()) {
            res.add(new ArrayList<Integer>(list));
            return;
        }
        
        for (int i = 0; i < nums.size(); i++) {
            if (list.contains(nums.get(i))) {
                continue;
            }
            list.add(nums.get(i));
            helper(res, list, nums);
            list.remove(list.size() - 1);
        }
    }
时间复杂度是O(n! * n)


16. Permutations II

这道题和上一道题有点类似,但是输入的数组会有重复的数字,比如[122]的全排列是[122, 212, 221]



这就要求我们在处理重复的元素上花一些功夫了。所以我们需要先对数组进行排序,然后只能连续地选,这样就可以避免生成重复的solution。

需要加一个visit数组,表示哪些已经访问过了。如果当前下标已经访问过了,则不要把它加进了。如果有2个连续的元素相等,并且前一个元素没有访问过,那么后面一个元素也不要加进去。

    public ArrayList<ArrayList<Integer>> permuteUnique(ArrayList<Integer> nums) {
        ArrayList<ArrayList<Integer> > res = new ArrayList();
        if (nums == null || nums.size() == 0) {
            return res;
        }
        Collections.sort(nums);
        boolean[] visit = new boolean[nums.size()];
        ArrayList<Integer> list = new ArrayList<Integer>();
        helper(res, list, nums, visit);
        return res;
    }
    
    private void helper(ArrayList<ArrayList<Integer>> res, ArrayList<Integer> list, ArrayList<Integer> nums, boolean[] visit) {
        if (list.size() == nums.size()) {
            res.add(new ArrayList<Integer>(list));
            return;
        }
        
        for (int i = 0; i < nums.size(); i++) {
            if (visit[i] || (i != 0 && nums.get(i) == nums.get(i-1) && visit[i-1])) {
                continue;
            }
            visit[i] = true;
            list.add(nums.get(i));
            helper(res, list, nums, visit);
            list.remove(list.size() - 1);
            visit[i] = false;
        }
    }


String Permutation I

跟Permutations那道题基本一样,只不过这次处理的是字符串,不是数字数组了。

需要注意的是,如果是求长度:

A) 对于String str来说,调用的是str.length()

B) 对于ArrayList<Integer> list来说,调用的是list.size()

C) 对于char[] arr来说,调用的是arr.length

如果是求是否包含某个元素:

A) 对于String str来说,调用的是str.indexOf(char c)

B) 对于ArrayList<Integer> list来说,调用的是list.contains(int a)

    private void dfs(List<String> res, char[] s, String path) {
        if (path.length() == s.length) {
            res.add(new String(path));
            return;
        }
        
        for (int i = 0; i < s.length; i++) {
            if (path.indexOf(s[i]) != -1) {
                continue;
            }
            path += s[i];
            dfs(res, s, path);
            path = path.substring(0, path.length() - 1);
        }
    }
    public List<String> stringPermutation2(String str) {
        List<String> res = new ArrayList<String>();
        char[] s = str.toCharArray();
        Arrays.sort(s);
        dfs(res, s, "");
        return res;
    }

10. String Permutation II

跟上道题类似,不过输入多了重复的字符,比如abb。处理方法和Permutation II那道题是一样的,加入visit数组判断.

    private void dfs(List<String> res, char[] s, String path, boolean[] visit) {
        if (path.length() == s.length) {
            res.add(new String(path));
            return;
        }
        
        for (int i = 0; i < s.length; i++) {
            if (visit[i] == true || (i != 0 && s[i] == s[i-1] && !visit[i-1])) {
                continue;
            }
            visit[i] = true;
            path += s[i];
            dfs(res, s, path, visit);
            path = path.substring(0, path.length() - 1);
            visit[i] = false;
        }
    }
    public List<String> stringPermutation2(String str) {
        List<String> res = new ArrayList<String>();
        char[] s = str.toCharArray();
        Arrays.sort(s);
        boolean[] visit = new boolean[str.length()];
        dfs(res, s, "", visit);
        return res;
    }


17. Subsets

给定一个含不同整数的集合,返回其所有的子集。子集中的元素排列必须是非降序的,解集必须不包含重复的子集。

这个跟permutation相比,就不用等到list的容量达到指定值才加进去了。每次DFS都能加元素


    public ArrayList<ArrayList<Integer>> subsets(int[] nums) {
        ArrayList<ArrayList<Integer>> res = new ArrayList();
        ArrayList<Integer> list = new ArrayList<Integer>();
        Arrays.sort(nums);
        helper(res, list, nums, 0);
        return res;
    }
    
    private void helper(ArrayList<ArrayList<Integer>> res, ArrayList<Integer> list, int[] nums, int pos) {
        res.add(new ArrayList<Integer>(list));
        for (int i = pos; i < nums.length; i++) {
            list.add(nums[i]);
            helper(res, list, nums, i + 1);
            list.remove(list.size() - 1);
        }
    }

18. Subsets II

跟上一道题类似,只不过输入的数中会有重复的元素。注意要跳过重复元素


    public ArrayList<ArrayList<Integer>> subsetsWithDup(ArrayList<Integer> S) {
        ArrayList<ArrayList<Integer>> res = new ArrayList();
        ArrayList<Integer> list = new ArrayList<Integer>();
        Collections.sort(S);
        helper(res, list, S, 0);
        return res;
    }
    
    private void helper(ArrayList<ArrayList<Integer>> res, ArrayList<Integer> list, ArrayList<Integer> num, int pos) {
        res.add(new ArrayList<Integer>(list));
        for (int i = pos; i < num.size(); i++) {
            if (i != pos && num.get(i) == num.get(i-1)) {
                continue;
            }
            list.add(num.get(i));
            helper(res, list, num, i + 1);
            list.remove(list.size() - 1);
        }
    }

以上四道题都是典型的DFS深度搜索递归。他们的模板可以背下来。可以借助画图来帮助理解。


33. N-Queens


N皇后问题,输入一个数字n,要求出n*n方格下所有符合N皇后规则的棋盘格局。N皇后不能出现在同一直线上(横、竖、对角线)。

这种要求出所有方案类型的题目,典型的是用深搜DFS,并且这道题可以套DFS的模板。

一层一层的向下扫描,需要用到一个pos数组,其中pos[i]表示第i行皇后的位置,然后从第0开始递归,每一行都一次遍历各列,判断如果在该位置放置皇后会不会有冲突,以此类推,当到最后一行的皇后放好后,一种解法就生成了,将其存入结果res中,然后再还会继续完成搜索所有的情况。

    private ArrayList<String> draw(ArrayList<Integer> pos) {
        ArrayList<String> res = new ArrayList();
        int n = pos.size();
        for (int i = 0; i < n; i++) {
            String tmp = new String();
            for (int j = 0; j < n; j++) {
                if (j == pos.get(i)) {
                    tmp += "Q";
                    continue;
                }
                tmp += ".";
            }
            res.add(tmp);
        }
        return res;
    }
    private boolean isValid(ArrayList<Integer> pos, int col) {
        int row = pos.size();
        for (int i = 0; i < row; i++) {
            // same column
            if (col == pos.get(i)) {
                return false;
            }
            // diagonal
            if (Math.abs(i - row) == Math.abs(pos.get(i) - col)) {
                return false;
            }
        }
        return true;
    }
    
    private void dfs(ArrayList<Integer> pos, ArrayList<ArrayList<String>> res, int n) {
        if (pos.size() == n) {
            ArrayList<String> tmp = draw(pos);
            res.add(tmp);
            return;
        }
        
        for (int i = 0; i < n; i++) {
            if (isValid(pos, i)) {
                pos.add(i);
                dfs(pos, res, n);
                pos.remove(pos.size() - 1);
            }
        }
        
    }
    
    ArrayList<ArrayList<String>> solveNQueens(int n) {
        ArrayList<ArrayList<String>> res = new ArrayList();
        if (n <= 0) {
            return res;
        }
        dfs(new ArrayList<Integer>(), res, n);
        return res;
    }

34. N-Queens II

跟上道题很类似,只不过只要求出N皇后的个数,而不是列举出总方案数。记得要声明一个static全局静态变量来记录个数。

    private static int res;
    private boolean isValid(ArrayList<Integer> pos, int col) {
        int row = pos.size();
        for (int i = 0; i < row; i++) {
            // same column
            if (col == pos.get(i)) {
                return false;
            }
            // diagonal
            if (Math.abs(i - row) == Math.abs(pos.get(i) - col)) {
                return false;
            }
        }
        return true;
    }
    
    private void dfs(ArrayList<Integer> pos, int n) {
        if (pos.size() == n) {
            res++;
            return;
        }
        for (int i = 0; i < n; i++) {
            if (isValid(pos, i)) {
                pos.add(i);
                dfs(pos, n);
                pos.remove(pos.size() - 1);
            }
        }
    }
    
    public int totalNQueens(int n) {
        // res = 0;
        dfs(new ArrayList<Integer>(), n);
        return res;
    }

136. Palindrome Partitioning

对字符串进行划分,求出所有使得它能成为回文串的划分组合。

Given s = "aab", return:

[
  ["aa","b"],
  ["a","a","b"]
]
这种题也是经典的DFS深搜题,可以直接套用DFS模板。
    private boolean isPalindrome(String s) {
        int left = 0, right = s.length() - 1;
        while (left < right) {
            if (s.charAt(left) != s.charAt(right)) {
                return false;
            }
            left++;
            right--;
        }
        return true;
    }
    private void dfs(List<List<String>>res, ArrayList<String> path, String s, int pos) {
        if (pos == s.length()) {
            res.add(new ArrayList<String>(path));
            return;
        }
        for (int i = pos; i < s.length(); i++) {
            String prefix = s.substring(pos, i + 1);
            if (isPalindrome(prefix)) {
                path.add(prefix);
                dfs(res, path, s, i + 1);
                path.remove(path.size() - 1);
            }
        }
    }
    public List<List<String>> partition(String s) {
        List<List<String>> res = new ArrayList();
        if (s == null) {
            return res;
        }
        dfs(res, new ArrayList<String>(), s, 0);
        return res;
    }


135. Combination Sum

给出一组候选数字(C)和目标数字(T),找到C中所有的组合,使找出的数字和为T。C中的数字可以无限制重复被选取。

例如,给出候选数组[2,3,6,7]和目标数字7,所求的解为:

[7],

[2,2,3]

由于是从set集合里找元素来进行组合,集合的特点就是每个元素是唯一的。这也是一道可以直接套用DFS模板的题目:
    private void dfs(List<List<Integer>> res, ArrayList<Integer> path, int target, int[] candidates, int pos) {
        if (target == 0) {
            res.add(new ArrayList<Integer>(path));
            return;
        }
        for (int i = pos; i < candidates.length; i++) {
            if (candidates[i] > target) {
                break;
            }
            path.add(candidates[i]);
            dfs(res, path, target - candidates[i], candidates, i);
            path.remove(path.size() - 1);
        }
        
    }
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        List<List<Integer>> res = new ArrayList();
        if (candidates == null) {
            return res;
        }
        Arrays.sort(candidates);
        dfs(res, new ArrayList<Integer>(), target, candidates, 0);
        return res;
    }


153. Combination Sum II

跟上道题不同的是,这次是从一群有重复的数字的集合里找组合,同一个数字会在集合里出现多次。

但是每个数字只允许取一次。需要注意的是对重复数字的处理,出现重复数字就跳过那一次循环。

    private void dfs(List<List<Integer>> res, ArrayList<Integer> path, int target, int[] num, int pos) {
        if (target == 0) {
            res.add(new ArrayList<Integer>(path));
            return;
        }
        for (int i = pos; i < num.length; i++) {
            if (num[i] > target) {
                break;
            }
            if (i != pos && num[i] == num[i-1]) {
                continue;
            }
            path.add(num[i]);
            dfs(res, path, target - num[i], num, i + 1);
            path.remove(path.size() - 1);
        }
    }
    public List<List<Integer>> combinationSum2(int[] num, int target) {
        List<List<Integer>> res = new ArrayList();
        if (num == null) {
            return res;
        }
        Arrays.sort(num);
        dfs(res, new ArrayList<Integer>(), target, num, 0);
        return res;
    }


90. k Sum II

解题思路: 由于k Sum是求个数,所以考虑动态规划,直接DFS会超时。而k Sum II 是求所有具体的解,所以直接DFS. 

思路跟 subsets 类似,可以想象成求一些特殊的subsets,加入result时,要符合subset的和等于target 

本题与 Combination Sum II 也非常类似

    private void dfs(ArrayList<ArrayList<Integer>> res, ArrayList<Integer> path, int[] A, int k, int target, int pos) {
        if (path.size() == k) {
            if (target == 0) {
                res.add(new ArrayList<Integer>(path));
            }
            return;
        }
        for (int i = pos; i < A.length; i++) {
            path.add(A[i]);
            dfs(res, path, A, k, target - A[i], i + 1);
            path.remove(path.size() - 1);
        }
    }
    public ArrayList<ArrayList<Integer>> kSumII(int[] A, int k, int target) {
        ArrayList<ArrayList<Integer>> res = new ArrayList();
        if (k <= 0) {
            return res;
        }
        dfs(res, new ArrayList<Integer>(), A, k, target, 0);
        return res;
    }


137. Clone Graph

给一个邻接表表示的图,返回一个它的深拷贝。这道题的关键在于用BFS首先克隆所有的点,然后再克隆所有的边。克隆点的时候需要用到HashSet来保存每一个节点。

/**
 * Definition for undirected graph.
 * class UndirectedGraphNode {
 *     int label;
 *     ArrayList<UndirectedGraphNode> neighbors;
 *     UndirectedGraphNode(int x) { label = x; neighbors = new ArrayList<UndirectedGraphNode>(); }
 * };
 */
public class Solution {
    /**
     * @param node: A undirected graph node
     * @return: A undirected graph node
     */
    public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
        if (node == null) {
            return null;
        }
        
        // 1. use bfs to get all nodes
        HashSet<UndirectedGraphNode> set = new HashSet<UndirectedGraphNode>();
        Queue<UndirectedGraphNode> q = new LinkedList<UndirectedGraphNode>();
        set.add(node);
        q.offer(node);
        while (!q.isEmpty()) {
            UndirectedGraphNode root = q.poll();
            for (UndirectedGraphNode n : root.neighbors) {
                if (!set.contains(n)) {
                    set.add(n);
                    q.offer(n);
                }
            }
        }
        ArrayList<UndirectedGraphNode> nodes = new ArrayList<UndirectedGraphNode>(set);
        
        // 2. clone all nodes
        HashMap<UndirectedGraphNode, UndirectedGraphNode> map = new HashMap<UndirectedGraphNode, UndirectedGraphNode>();
        for (UndirectedGraphNode tmp : nodes) {
            map.put(tmp, new UndirectedGraphNode(tmp.label));
        }
        
        // 3. clone all edges
        for (UndirectedGraphNode tmp : nodes) {
            UndirectedGraphNode newNode = map.get(tmp);
            for (UndirectedGraphNode n : tmp.neighbors) {
                newNode.neighbors.add(map.get(n));
            }
        }
        
        return map.get(node);
    }
}

127. Topological Sorting

拓扑排序,把一个有向无环图转换成一维的拓扑排序。拓扑排序是对有向无环图的一种排序。表示了顶点按边的方向出现的先后顺序。如果有环,则无法表示两个顶点的先后顺序。一个简单的求拓扑排序的算法:首先要找到任意入度为0的一个顶点,删除它及所有相邻的边,再找入度为0的顶点,以此类推,直到删除所有顶点。顶点的删除顺序即为拓扑排序。这里要用到BFS。

1)首先计算每个点的入度。

2)把入度为0的节点加进队列。

3)用队列进行BFS操作,每次从队列中拿出节点的时候,更新它的后继结点的入度(后继结点入度减1)。

/**
 * Definition for Directed graph.
 * class DirectedGraphNode {
 *     int label;
 *     ArrayList<DirectedGraphNode> neighbors;
 *     DirectedGraphNode(int x) { label = x; neighbors = new ArrayList<DirectedGraphNode>(); }
 * };
 */
public class Solution {
    /**
     * @param graph: A list of Directed graph node
     * @return: Any topological order for the given graph.
     */    
    public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
        // calculate in-degree of all nodes
        HashMap<DirectedGraphNode, Integer> map = new HashMap();
        for (DirectedGraphNode node : graph) {
            for (DirectedGraphNode neighbor : node.neighbors) {
                if (map.containsKey(neighbor)) {
                    map.put(neighbor, map.get(neighbor) + 1);
                } else {
                    map.put(neighbor, 1);
                }
            }
        }
        
        // add nodes with 0 in-degrees into the queue and result array
        ArrayList<DirectedGraphNode> res = new ArrayList<DirectedGraphNode>();
        Queue<DirectedGraphNode> q = new LinkedList<DirectedGraphNode>();
        for (DirectedGraphNode node : graph) {
            if (!map.containsKey(node)) {
                q.offer(node);
                res.add(node);
            }
        }
        
        // BFS
        while (!q.isEmpty()) {
            DirectedGraphNode node = q.poll();
            for (DirectedGraphNode neighbor : node.neighbors) {
                map.put(neighbor, map.get(neighbor) - 1);
                if (map.get(neighbor) == 0) {
                    q.offer(neighbor);
                    res.add(neighbor);
                }
            }
        }
        
        return res;
    }
}

如果要用DFS的话,参考这个博客http://www.geeksforgeeks.org/topological-sorting/


120. Word Ladder

Given: start = "hit" end = "cog" dict = ["hot","dot","dog","lot","log"] As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", return its length 5.

根据一定的单词变化规则,看从起始单词能不能经过这个规则变到终止单词,并求出最少通过多少次能变到。规则就是每次只能变动一个字母,并且变动完后的单词要在给定的字典中。如果把整个变化的过程用图画出来,会发现这其实是一个graph,而求最少的次数,求相当于求最短路径的长度。有点像求二叉树的最小高度,使用的是BFS层次遍历,用到队列和hashset,用到hashset的原因是把每次走过的点标记为已走过,防止再重复走。


需要注意对边界情况做处理,比如字典为空,比如初始单词和终止单词是一个单词。还有就是要先把队列大小size的值给用一个变量保存一下,因为每次出队列都会使得队列的size发生变化,为了使得每个点都能遍历到,一定要用中间变量保存一下size

    private String replace(String s, int index, char c) {
        char[] arr = s.toCharArray();
        arr[index] = c;
        return new String(arr);
    }
    private ArrayList<String> findNeighbor(String word, Set<String> dict) {
        ArrayList<String> res = new ArrayList<String>();
        for (int i = 0; i < word.length(); i++) {
            for (char c = 'a'; c <= 'z'; c++) {
                if (word.charAt(i) != c) {
                    String tmp = replace(word, i, c);
                    if (dict.contains(tmp)) {
                        res.add(tmp);
                    }
                }
            }
        }
        return res;
    }
    public int ladderLength(String start, String end, Set<String> dict) {
        if (dict == null) {
            return 0;
        }
        if (start.equals(end)) {
            return 1;
        }
        dict.add(start);
        dict.add(end);
        
        Queue<String> q = new LinkedList<String>();
        HashSet<String> hash = new HashSet<String>();
        q.offer(start);
        hash.add(start);
        int length = 1;
        
        while (!q.isEmpty()) {
            int size = q.size();
            for (int i = 0; i < size; i++) {
                String word = q.poll();
                for (String str : findNeighbor(word, dict)) {
                    if (hash.contains(str)) {
                        continue;
                    }
                    if (str.equals(end)) {
                        return length + 1;
                    }
                    hash.add(str);
                    q.offer(str);
                }
            }
            length++;
        }
        return 0;
    }

121. Word Ladder II

这道题跟上道题类似,不过要求的不只是最短路径了,而是要把最短路径的多种可能组合都给返回。如果要求出所有的组合,这种题目一般是DFS。如果是求最短路,则是BFS。所以这道题的解法是BFS+DFS。

BFS主要就做2件事情:

1)标记每个点(单词)的位置,越靠近起始单词,数字就越小,越靠近终止单词,数字就越大。比如起始单词的位置为0

2)对于每个单词,求出有哪些单词可以直接到达它,也就是求每个单词的父节点。

DFS就是从终止节点到起始节点进行DFS。一旦找到了起始节点,就可以把路径上经过的节点加入res里了。若还未找到节点,则继续把当前节点加入res里。

    public List<List<String>> findLadders(String start, String end, Set<String> dict) {
        List<List<String>> res = new ArrayList();
        HashMap<String, List<String>> map = new HashMap<String, List<String>>();
        HashMap<String, Integer> distance = new HashMap<String, Integer>();
        
        dict.add(start);
        dict.add(end);
        
        bfs(start, end, dict, map, distance);
        dfs(res, new ArrayList<String>(), start, end, map, distance);
        return res;
    }
    
    private ArrayList<String> findNeighbor(String word, Set<String> dict) {
        ArrayList<String> res = new ArrayList<String>();
        for (int i = 0; i < word.length(); i++) {
            for (char c = 'a'; c <= 'z'; c++) {
                if (word.charAt(i) != c) {
                    String tmp = word.substring(0, i) + c + word.substring(i+1);
                    if (dict.contains(tmp)) {
                        res.add(tmp);
                    }
                }
            }
        }
        return res;
    }
    
    private void bfs(String start, String end, Set<String> dict, HashMap<String, List<String>> map, HashMap<String, Integer> distance) {
        Queue<String> q = new LinkedList<String>();
        q.offer(start);
        distance.put(start, 0);
        
        while (!q.isEmpty()) {
            String father = q.poll();
            for (String str : findNeighbor(father, dict)) {
                if (map.get(str) == null) {
                    ArrayList<String> tmp = new ArrayList<String>();
                    tmp.add(father);
                    map.put(str, tmp);
                } else {
                    map.get(str).add(father);
                }
                // distance同时起到了判断有没有访问过的作用
                if (!distance.containsKey(str)) {
                    q.offer(str);
                    distance.put(str, distance.get(father) + 1);
                }
            }
        }
    }
    
    private void dfs(List<List<String>> res, List<String> path, String start, String end, HashMap<String, List<String>> map, HashMap<String, Integer> distance) {
        if (end.equals(start)) {
            path.add(start);
            Collections.reverse(path);
            res.add(new ArrayList<String>(path));
            Collections.reverse(path);
            path.remove(path.size() - 1);
            return;
        }
        for (String next : map.get(end)) {
            if (distance.get(next) + 1 == distance.get(end)) {
                path.add(end);
                dfs(res, path, start, next, map, distance);
                path.remove(path.size() - 1);
            }
        }
    }

531. Six Degrees

就是直接用BFS找最短长度。但是把HashMap换成HashSet就过不了了,需要注意的是,对于图来说,它的BFS的层次遍历,不能像树那样求高度那样每次length++。树是有规律的,从上到下是填满的,但是图就不一样了,所以要求路径长度,一定要根据它的上一个节点的长度+1.

/**
 * Definition for Undirected graph.
 * class UndirectedGraphNode {
 *     int label;
 *     List<UndirectedGraphNode> neighbors;
 *     UndirectedGraphNode(int x) { 
 *         label = x;
 *         neighbors = new ArrayList<UndirectedGraphNode>(); 
 *     }
 * };
 */
public class Solution {
    /**
     * @param graph a list of Undirected graph node
     * @param s, t two Undirected graph nodes
     * @return an integer
     */
    public int sixDegrees(List<UndirectedGraphNode> graph,
                          UndirectedGraphNode s,
                          UndirectedGraphNode t) {
        if (s == t) {
            return 0;
        }
        Queue<UndirectedGraphNode> q = new LinkedList<UndirectedGraphNode>();
        HashMap<UndirectedGraphNode, Integer> hash = new HashMap<UndirectedGraphNode, Integer>();
        q.offer(s);
        hash.put(s, 0);
        
        int distance = 0;
        while(!q.isEmpty()) {
            UndirectedGraphNode head = q.poll();
            int size = head.neighbors.size();
            for (int i = 0; i < size; i++) {
                UndirectedGraphNode node = head.neighbors.get(i);
                if (hash.containsKey(node)) {
                    continue;
                }
                if (node == t) {
                    return hash.get(head) + 1;
                }
                q.offer(node);
                hash.put(node, hash.get(head) + 1);
            }
        }
        return -1;
    }
}

431. Find the Connected Component in the Undirected Graph

找出无向图中所有的连通块,这道题好像就是Coursera上普林斯顿的算法课的练习题,有两种方法可以做,一种是并查集,还有一种就是BFS。

/**
 * Definition for Undirected graph.
 * class UndirectedGraphNode {
 *     int label;
 *     ArrayList<UndirectedGraphNode> neighbors;
 *     UndirectedGraphNode(int x) { label = x; neighbors = new ArrayList<UndirectedGraphNode>(); }
 * };
 */
public class Solution {
    /**
     * @param nodes a array of Undirected graph node
     * @return a connected set of a Undirected graph
     */
    public void bfs(List<List<Integer>> res, Set<UndirectedGraphNode> set, UndirectedGraphNode node) {
        Queue<UndirectedGraphNode> queue = new LinkedList<UndirectedGraphNode>();
        List<Integer> list = new ArrayList<Integer>();
        list.add(node.label);
        queue.offer(node);
        set.add(node);
        
        while (!queue.isEmpty()) {
            UndirectedGraphNode head = queue.poll();
            List<UndirectedGraphNode> next = head.neighbors;
            for (UndirectedGraphNode nextNode: next) {
                if (!set.contains(nextNode)) {
                    list.add(nextNode.label);
                    set.add(nextNode);
                    queue.offer(nextNode);
                }
            }
        }
        Collections.sort(list);
        res.add(list);
    }
    
    public List<List<Integer>> connectedSet(ArrayList<UndirectedGraphNode> nodes) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        Set<UndirectedGraphNode> set = new HashSet<UndirectedGraphNode>();
        
        for (UndirectedGraphNode node: nodes) {
            if (!set.contains(node)) {
                bfs(res, set, node);
            }
        }
        return res;
    }
}

176. Route Between Two Nodes in Graph

在一个有向图里,问2个点是否是连通的。典型的BFS题,用BFS遍历,如果中途遇到了另外一个点,这说明可到达,否则不可达。

    public boolean hasRoute(ArrayList<DirectedGraphNode> graph, 
                            DirectedGraphNode s, DirectedGraphNode t) {
        HashSet<DirectedGraphNode> visit = new HashSet();
        Queue<DirectedGraphNode> q = new LinkedList();
        
        if (t == s) {
            return true;
        }

        q.offer(s);
        while (!q.isEmpty()) {
            DirectedGraphNode head = q.poll();
            ArrayList<DirectedGraphNode> arr = head.neighbors;
            for (DirectedGraphNode next : arr) {
                if (!visit.contains(next)) {
                    if (next == t) {
                        return true;
                    }
                    visit.add(next);
                    q.offer(next);
                } else {
                    continue;
                }
            }
        }
        return false;
    }


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值