LintCode 425:电话号码的字母组合

https://www.lintcode.com/problem/letter-combinations-of-a-phone-number

描述

给一个不包含01的数字字符串,每个数字代表一个字母,请返回其所有可能的字母组合。
下图的手机按键图,就表示了每个数字可以代表的字母。

1 2
ABC
3
DEF
4
GHI
5
JKL
6
MNO
7
PQRS
8
TUV
9
WXYZ

样例

  1. 输入: "23"
  2. 输出: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]
  3. 解释:
  4. '2' 可以是 'a', 'b' 'c'
  5. '3' 可以是 'd', 'e' 'f'
  6. 输入: "5"
  7. 输出: ["j", "k", "l"]

解题思路

简单深搜题

AC代码

  1. public class Solution {
  2. // 每个数字代表的字母
  3. String[] ss = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
  4. // 存储字母组合
  5. List<String> list = new LinkedList<>();
  6. public List<String> letterCombinations(String digits) {
  7. // 因为测试是用的一个对象,所以list需要清空一下
  8. list.clear();
  9. if (digits.equals(""))
  10. return list;
  11. // 深搜得到字母组合
  12. assemble(0,digits,"");
  13. return list;
  14. }
  15. private void assemble(int i, String digits, String s) {
  16. // 已经找到一个组合,加入list,返回
  17. if (i == digits.length()){
  18. list.add(s);
  19. return;
  20. }
  21. char ch = digits.charAt(i);
  22. String str = ss[((int) ch) - 48];
  23. for (int j = 0; j < str.length(); j++) {
  24. assemble(i + 1,digits,s + str.charAt(j));
  25. }
  26. }
  27. }

LintCode 10:字符串的不同排列

https://www.lintcode.com/problem/string-permutation-ii

描述

给出一个字符串,找到它的所有排列,注意同一个字符串不要打印两次。

样例

  1. 输入:"abb"
  2. 输出:
  3. ["abb", "bab", "bba"]
  4. 输入:"aabb"
  5. 输出:
  6. ["aabb", "abab", "baba", "bbaa", "abba", "baab"]

解题思路

简单的深搜

AC代码

  1. public class Solution {
  2. List<String> list = new ArrayList<>();
  3. public List<String> stringPermutation2(String str) {
  4. list.clear();
  5. if (str == null) { return list; }
  6. // 转成字符数组更容易处理
  7. char[] ch = str.toCharArray();
  8. // 记录当前位置是否已经被选取至组合中
  9. boolean[] flag = new boolean[ch.length];
  10. // 构造组合
  11. StringBuilder sb = new StringBuilder();
  12. // 排序,去重考虑
  13. Arrays.sort(ch);
  14. // 深搜
  15. dfs(sb, 0, ch, flag);
  16. return list;
  17. }
  18. private void dfs(StringBuilder sb, int step, char[] ch, boolean[] flag) {
  19. // 找到一个组合
  20. if (step == ch.length) {
  21. list.add(sb.toString());
  22. return;
  23. }
  24. for (int i = 0; i < ch.length; i++) {
  25. if (flag[i]) { continue; }
  26. // 去重,当有两个相同字母时,在当前层只取一次
  27. if (i > 0 && ch[i] == ch[i - 1] && !flag[i - 1]) { continue; }
  28. // 标准深搜过程
  29. sb.append(ch[i]);
  30. flag[i] = true;
  31. dfs(sb, step + 1, ch, flag);
  32. flag[i] = false;
  33. sb.deleteCharAt(step);
  34. }
  35. }
  36. }

LintCode 135:数字组合

https://www.lintcode.com/problem/combination-sum/

描述

给定一个候选数字的集合 candidates 和一个目标值 target. 找到 candidates 中所有的和为 target 的组合.
在同一个组合中, candidates 中的某个数字不限次数地出现.

  1. 所有数值 (包括 target ) 都是正整数.
  2. 返回的每一个组合内的数字必须是非降序的.
  3. 返回的所有组合之间可以是任意顺序.
  4. 解集不能包含重复的组合.

    样例

    ```java 输入: candidates = [2, 3, 6, 7], target = 7 输出: [[7], [2, 2, 3]]

输入: candidates = [1], target = 3 输出: [[1, 1, 1]]

  1. <a name="Tzght"></a>
  2. #### 解题思路
  3. 给数字集合排序,深搜
  4. <a name="lEvxt"></a>
  5. #### AC代码
  6. ```java
  7. public class Solution {
  8. List<List<Integer>> list = new ArrayList<>();
  9. int[] candidates;
  10. public List<List<Integer>> combinationSum(int[] candidates, int target) {
  11. // 排序
  12. Arrays.sort(candidates);
  13. List<Integer> li = new ArrayList<>();
  14. this.candidates = candidates;
  15. dfs( 0, 0, target, li);
  16. return list;
  17. }
  18. private void dfs(int index, int add, int target, List<Integer> li) {
  19. if (add == target) {
  20. list.add(new ArrayList<>(li));
  21. return;
  22. }
  23. for (int i = index; i < candidates.length; i++) {
  24. // 去重
  25. if (i > 0 && candidates[i] == candidates[i - 1]) {
  26. continue;
  27. }
  28. if (add + candidates[i] > target) {
  29. break;
  30. }
  31. li.add(candidates[i]);
  32. dfs(i, add + candidates[i], target, li);
  33. li.remove(li.size() - 1);
  34. }
  35. }
  36. }

LintCode 90:K数和II

https://www.lintcode.com/problem/k-sum-ii

描述

给定n个不同的正整数,整数k(1<= k <= n)以及一个目标数字。    
在这n个数里面找出K个数,使得这K个数的和等于目标数字,你需要找出所有满足要求的方案。

样例

  1. 输入: [1,2,3,4], k = 2, target = 5
  2. 输出: [[1,4],[2,3]]
  3. 输入: [1,3,4,6], k = 3, target = 8
  4. 输出: [[1,3,4]]

解题思路

和上面的数字组合思路一样,只是个数有限

AC代码

  1. public class Solution {
  2. List<List<Integer>> list = new ArrayList<>();
  3. int[] a;
  4. public List<List<Integer>> kSumII(int[] A, int k, int target) {
  5. Arrays.sort(A);
  6. a = A;
  7. List<Integer> li = new ArrayList<>();
  8. dfs(0, 0, 0, k, target, li);
  9. return list;
  10. }
  11. private void dfs(int index, int level, int add, int k, int target, List<Integer> li) {
  12. if (add == target) {
  13. if (level == k) {
  14. list.add(new ArrayList<>(li));
  15. }
  16. return;
  17. }
  18. if (level >= k || index == a.length) {
  19. return;
  20. }
  21. for (int i = index; i < a.length; i++) {
  22. if (add + a[i] > target) {
  23. break;
  24. }
  25. li.add(a[i]);
  26. dfs(i + 1, level + 1, add + a[i], k, target, li);
  27. li.remove(li.size() - 1);
  28. }
  29. }
  30. }

LintCode 132:单词搜索II

https://www.lintcode.com/problem/word-search-ii

描述

给出一个由小写字母组成的矩阵和一个字典。找出所有同时在字典和矩阵中出现的单词。一个单词可以从矩阵中的任意位置开始,可以向左/右/上/下四个相邻方向移动。一个字母在一个单词中只能被使用一次。且字典中不存在重复单词

样例

  1. 输入:["doaf","agai","dcan"],["dog","dad","dgdg","can","again"]
  2. 输出:["again","can","dad","dog"]
  3. 解释:
  4. d o a f
  5. a g a i
  6. d c a n
  7. 矩阵中查找,返回 ["again","can","dad","dog"]。
  8. 输入:["a"],["b"]
  9. 输出:[]
  10. 解释:
  11. a
  12. 矩阵中查找,返回 []。

解题思路

从矩阵的每个点进行深搜。
优化:深搜到某一层时,如果这个前缀没在字典里出现过,其实就不用继续搜索。

  • 用哈希表存储前缀
  • 用字典树存储前缀

    AC代码

    1. public class Solution {
    2. List<String> list;
    3. // 哈希表存储前缀
    4. Map<String, Boolean> prefixes;
    5. int count = 0;
    6. int[] a = {0, 0, 1, -1};
    7. int[] b = {1, -1, 0, 0};
    8. int n,m;
    9. char[][] board;
    10. public List<String> wordSearchII(char[][] board, List<String> words) {
    11. if (board == null) return null;
    12. if (board.length <1) return null;
    13. if (board[0].length == 0) return null;
    14. this.board = board;
    15. list = new ArrayList<>();
    16. prefixes = new HashMap<>();
    17. count = 0;
    18. // 存储前缀,value值为true代表这是一个单词
    19. for (String str : words) {
    20. for (int i = 1; i < str.length(); i++) {
    21. String prefix = str.substring(0, i);
    22. if (!prefixes.containsKey(prefix)) {
    23. prefixes.put(prefix, false);
    24. }
    25. }
    26. prefixes.put(str, true);
    27. }
    28. n = board.length;
    29. m = board[0].length;
    30. boolean[][] flag = new boolean[n][m];
    31. // 从每个点开始dfs
    32. for (int i = 0; i < n; i++) {
    33. for (int j = 0; j < m; j++) {
    34. if (!prefixes.containsKey(board[i][j] + "")) {
    35. continue;
    36. }
    37. flag[i][j] = true;
    38. dfs(flag, i,j,board[i][j]+"");
    39. flag[i][j] = false;
    40. }
    41. }
    42. return list;
    43. }
    44. public void dfs(boolean[][] flag, int x, int y, String s) {
    45. if (prefixes.get(s)) {
    46. // 去重
    47. if (!list.contains(s)) {
    48. list.add(s);
    49. }
    50. }
    51. for (int i = 0; i < 4; i++) {
    52. int x1 = x + a[i];
    53. int y1 = y + b[i];
    54. if (x1 < 0 || y1 < 0 || x1 >= n || y1 >= m || flag[x1][y1]) {
    55. continue;
    56. }
    57. if (!prefixes.containsKey(s + board[x1][y1])) {
    58. continue;
    59. }
    60. flag[x1][y1] = true;
    61. dfs(flag, x1, y1, s + board[x1][y1]);
    62. flag[x1][y1] = false;
    63. }
    64. }
    65. }