---------------------------------------------------------------
本文使用方法:所有题目,只需要把标题输入lintcode就能找到。主要是简单的剖析思路以及不能bug-free的具体细节原因。
----------------------------------------------------------------
-------------------------------------------
第九周:图和搜索。
-------------------------------------------
1,-------Clone Graph(克隆图)
(1)答案和思路:首先用list来记录有哪些图,然后对于每一个节点都要新建。用map来做新旧节点的一一对应,以便于后面的建立邻结点。
/** * 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; } ArrayList<UndirectedGraphNode> nodes = new ArrayList(); nodes.add(node); Map<UndirectedGraphNode, UndirectedGraphNode> map = new HashMap(); map.put(node, new UndirectedGraphNode(node.label)); int index = 0; while (index < nodes.size()) { UndirectedGraphNode curNode = nodes.get(index++); for (int i = 0; i < curNode.neighbors.size(); i++) { if (!nodes.contains(curNode.neighbors.get(i))) { nodes.add(curNode.neighbors.get(i)); map.put(curNode.neighbors.get(i), new UndirectedGraphNode(curNode.neighbors.get(i).label)); } } } for (int i = 0; i < nodes.size(); i++) { UndirectedGraphNode curNode = nodes.get(i); for (int j = 0; j < curNode.neighbors.size(); j++) { map.get(curNode).neighbors.add(map.get(curNode.neighbors.get(j))); } } return map.get(node); } }
(2)一刷没有AC:思路没有处理好。
(2)二刷bug-free;
2,-----------Toplogical Sorting(拓扑排序)
(1)答案和思路:首先,利用map来记录入度。并且把没进去map的那些点先加入结果,因为他们入度为0.为了方便遍历,用queue来辅助遍历。
/** * 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) { ArrayList<DirectedGraphNode> result = new ArrayList(); if (graph == null || graph.size() == 0) { return result; } HashMap<DirectedGraphNode, Integer> map = new HashMap(); //map 用来记录那些成为了别人邻居的点作为多少个邻居,也就是他的入度是多少。 for (DirectedGraphNode g : graph) { for (DirectedGraphNode n : g.neighbors) { if (map.containsKey(n)) { map.put(n, map.get(n) + 1); } else { map.put(n, 1); } } } Queue<DirectedGraphNode> queue = new LinkedList(); for (DirectedGraphNode g : graph) { if (!map.containsKey(g)) { //不在map里面,说明他的度为0 result.add(g); queue.add(g); } } while (!queue.isEmpty()) { DirectedGraphNode node = queue.poll(); for (DirectedGraphNode n : node.neighbors) { map.put(n, map.get(n) - 1); if (map.get(n) == 0) { result.add(n); queue.add(n); } } } return result; } }
(2)一刷没过。
3,------permutation(全排列)
(1)答案和思路:就是没一个数字加进去之前,他可以放在已经有的地方的n+1个位置。不断地循环就可以了。
class Solution { /** * @param nums: A list of integers. * @return: A list of permutations. */ public static ArrayList<ArrayList<Integer>> permute(ArrayList<Integer> nums) { ArrayList<ArrayList<Integer>> res = new ArrayList(); if (nums == null || nums.size() == 0) { return res; } ArrayList<Integer> list1 = new ArrayList(); list1.add(nums.get(0)); res.add(list1); for (int i = 1; i < nums.size(); i++){ ArrayList<ArrayList<Integer>> res2 = new ArrayList(); for (ArrayList<Integer> tmp : res) { for (int j = 0; j <= tmp.size(); j++) { ArrayList<Integer> list2 = new ArrayList(tmp); list2.add(j, nums.get(i)); res2.add(list2); } } res = new ArrayList(res2); } return res; } }
(2)注意细节问题。
(3)二刷bug-free;
4,---------permutationII(全排列)
(1)答案和思路:跟上一题的区别就只需要再加入结果之前判断一下是否已经有了。
class Solution { /** * @param nums: A list of integers. * @return: A list of unique permutations. */ public static ArrayList<ArrayList<Integer>> permuteUnique(ArrayList<Integer> nums) { // write your code here HashSet<ArrayList<Integer>> res = new HashSet(); ArrayList<ArrayList<Integer>> ans = new ArrayList(); if (nums == null || nums.size() == 0) { return ans; } ArrayList<Integer> list1 = new ArrayList(); list1.add(nums.get(0)); res.add(list1); for (int i = 1; i < nums.size(); i++){ HashSet<ArrayList<Integer>> res2 = new HashSet(); for (ArrayList<Integer> tmp : res) { for (int j = 0; j <= tmp.size(); j++) { ArrayList<Integer> list2 = new ArrayList(tmp); list2.add(j, nums.get(i)); res2.add(list2); } } res = new HashSet(res2); } for (ArrayList list : res){ ArrayList<Integer> list3 = new ArrayList(list); ans.add(list3); } return ans; } }
(2)一刷bug-free;
5,----------N Queens (n皇后问题)
(1)答案和思路:首先,就是一场不断尝试放置的过程,那么需要一个函数来判断是否能够放(不能放的条件:这一列已经放了,他不能和上面的行构成斜对角线(当行差值==列差值的时候,就是在对角线上))。技巧:columns[i] = j来记录每一行的Q放在哪里。i行放在j列。 第二步就是进行放置:放置对于第一行来说,能放N个位置,所以,for循环。放好了第一个,利用递归,开始放第二。不断的判断是否可行,直到放置行数达到N。那么就是一次合法的放置,存进list里面。
import java.util.ArrayList; public class Solution { public static void main(String[] args) { System.out.println(solveNQueens(4)); } public static ArrayList<ArrayList<String>> solveNQueens(int n) { ArrayList<ArrayList<String>> result = new ArrayList(); int[] columns = new int[n]; for (int i = 0; i < n; i++) { columns[i] = -1; } ArrayList<int[]> results = new ArrayList(); placeNQueens(0, columns, results, n); for (int[] r : results) { ArrayList<String> list = new ArrayList(); for (int i = 0; i < r.length; i++) { char[] c = new char[n]; for (int j = 0; j < n; j++) { c[j] = '.'; } c[r[i]] = 'Q'; list.add(new String(c)); } result.add(new ArrayList(list)); } return result; } private static void placeNQueens(int row, int[] columns, ArrayList<int[]> results, int n) { if (row == n) { results.add(columns.clone()); } else { for (int col = 0; col < n; col++) { if (checkValid(columns, row, col)) { columns[row] = col; placeNQueens(row + 1, columns, results, n); } } } } // columns[i] = j 表示第i行第j列放皇后 private static boolean checkValid(int[] columns, int row, int column) { // 看一下跟已有的行的哪些列冲突了 // i 到 row 行之间这些行已经存了东西了。columns[i]能得到存了哪些列 for (int i = 0; i < row; i++) { int hasColumn = columns[i]; if (hasColumn == column) { return false; } if (row - i == Math.abs(column - hasColumn)) { // 如果行之间的差值等于列之间的差值,那么在同一个对角线 return false; } } return true; } }
(2)一刷没过。完全没想到怎么判断。
6,--------Palindrome Partition I(回文区分)
(1)答案和思路:首先,拿到0到第i个字符,如果他是回文,那么存下来,然后从他到结尾,这一个字符串,也来进行0,到1,。。,i的判断。
基本思路就是从0-i是否是回文,是的话,接着处理i到结束的字符串递归:在后面的字符串里继续考虑:第一个到新的i是否是回文。如果一直这样处理,直到最后的str为空了,那么说明找到一组完整的了,因为只有是回文才会进入递归。这里就是递归结束之后,要remove掉list的最后一个,这是因为:假如,0-i是,但是后来一直处理结束了都不是,那么这就不是一组合格的,那么递归结束,这个值必须出局。想法如果全部都是,那么一层一层往外走,也需要list一个一个删除。
import java.util.ArrayList; import java.util.List; public class Solution { public static void main(String[] args) { System.out.println(partition("aaa")); } public static List<List<String>> partition(String s) { List<List<String>> result = new ArrayList(); if (null == s || s.length() == 0) { return result; } List<String> list = new ArrayList(); calResult(result, list, s); return result; } public static void calResult(List<List<String>> result, List<String> list, String str) { if (str == null || str.length() == 0) { // ERROR : result.add(list); result.add(new ArrayList(list)); } for (int i = 1; i <= str.length(); i++) { String subStr = str.substring(0, i); if (isPalindrome(subStr)) { list.add(subStr); calResult(result, list, str.substring(i)); list.remove(list.size() - 1); } } } public static boolean isPalindrome(String s) { if (null == s || s.length() == 0) { return false; } int i = 0; int j = s.length() - 1; while (i < j) { if (s.charAt(i) != s.charAt(j)) { return false; } i++; j--; } return true; } }
(2)一刷没过。
(3)二刷错在:list存入是需要new的。不然一直是原来的list,是错的。
7,----------combination sum(求一个集合里面能够组合成目标值的组合种类)
(1)答案和思路:这里依然是利用递归来做。不同的就是,从i开始,在sum没有大于target之前,再次递归的元素下标是不变的。
import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Solution { public static void main(String[] args) { int[] a = {7, 1, 2, 5, 1, 6, 10}; System.out.println(combinationSum(a, 8)); } public static List<List<Integer>> combinationSum(int[] candidates, int target) { List<List<Integer>> result = new ArrayList(); if (candidates == null || candidates.length == 0) { return result; } List<Integer> list = new ArrayList(); Arrays.sort(candidates); calResult(candidates,target, 0, 0, result, list); return result; } public static void calResult(int[] candidates, int target, int sum, int index, List<List<Integer>> result, List<Integer> list) { if (sum > target) { return; } if (sum == target) { if (!result.contains(list)) { result.add(new ArrayList(list)); } } for (int i = index; i < candidates.length; i++) { sum += candidates[i]; list.add(candidates[i]); calResult(candidates, target, sum, i, result, list); sum -= candidates[i]; list.remove(list.size() - 1); } } }
(2)一刷思路没弄对。
(3)二刷:忘记了sort数组。因为结果要求有序。
8, --------------combination sum II(和I的区别是,每个元素只能用一次,那么就是每一次递归都是i+1的走)
答案:
import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Solution { // public static void main(String[] args) { // int[] a = {7, 1, 2, 5, 1, 6, 10}; // System.out.println(combinationSum(a, 8)); // } public static List<List<Integer>> combinationSum2(int[] candidates, int target) { List<List<Integer>> result = new ArrayList(); if (candidates == null || candidates.length == 0) { return result; } List<Integer> list = new ArrayList(); Arrays.sort(candidates); calResult(candidates,target, 0, 0, result, list); return result; } public static void calResult(int[] candidates, int target, int sum, int index, List<List<Integer>> result, List<Integer> list) { if (sum > target) { return; } if (sum == target) { if (!result.contains(list)) { result.add(new ArrayList(list)); } } for (int i = index; i < candidates.length; i++) { sum += candidates[i]; list.add(candidates[i]); calResult(candidates, target, sum, i + 1, result, list); sum -= candidates[i]; list.remove(list.size() - 1); } } }
(1)一刷bug-free;
9,--------------word ladder
(1)答案和思路:利用队列来进行记录每一次可以有多少个next直到遇到了end。
import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedList; import java.util.Queue; import java.util.Set; public class Solution { public static int ladderLength(String start, String end, Set<String> dict) { if (dict == null) { return 0; } dict.add(start); dict.add(end); HashSet<String> hash = new HashSet(); Queue<String> queue = new LinkedList(); queue.add(start); hash.add(start); int length = 1; while (!queue.isEmpty()) { length++; int size = queue.size(); for (int i = 0; i < size; i++) { String word = queue.poll(); dict.remove(word); for (String nextWord : getNextWords(word, dict)) { if (hash.contains(nextWord)) { continue; } if (nextWord.equals(end)) { return length; } hash.add(nextWord); queue.add(nextWord); } } } return 0; } private static String replace(String s, int index, char c) { char[] chars = s.toCharArray(); chars[index] = c; return new String(chars); } private static ArrayList<String> getNextWords(String word, Set<String> dict) { ArrayList<String> nextWords = new ArrayList(); for (char c = 'a'; c <= 'z'; c++) { for (int i = 0; i < word.length(); i++) { if (c == word.charAt(i)) { continue; } String nextWord = replace(word, i, c); if (dict.contains(nextWord)) { nextWords.add(nextWord); } } } return nextWords; } }