1. 数字键盘组合
17. Letter Combinations of a Phone Number
class Solution {
private static final String[] keys = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
public List<String> letterCombinations(String digits) {
List<String> ret = new ArrayList<> ();
String curStr = "";
if(digits!=null&&digits.length()!=0){
dfs(digits, -1, 0, ret, curStr);
}
return ret;
}
// i代表按键数字,j代表按键数字的某一位
private void dfs(String digits, int i, int j, List<String> ret, String curStr){
//获得当前的数字,-1的时候不执行该操作
if(i>=0){
int curNum = digits.charAt(i) - '0';
curStr += keys[curNum].charAt(j);
}
// 如果已经检索到最后一位,则不继续往下检索了
if(i==digits.length()-1){
ret.add(curStr);
return;
}
//获得当前数字对应的字符串,并将对应位加进当前数组
int nextNum = digits.charAt(i+1) - '0';
for(int k=0; k<keys[nextNum].length(); k++){
System.out.print(k);
dfs(digits, i+1, k, ret, curStr);
}
}
}
2.在矩阵中寻找字符串
思路:图的深度搜索一般都有套路,如果主程序的n*m个入口;然后递归程序有一个终止返回条件,一个不符合返回条件,然后就是对上下左右的遍历
Leetcode : 79. Word Search (Medium)
class Solution {
private int[][] direction = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
// 用来记录访问过的值,但是每次退出当前节点的子节点时,要恢复
private boolean[][] visited;
public boolean exist(char[][] board, String word) {
if (word == null || word.length() == 0) return true;
if (board == null || board.length == 0 || board[0].length == 0) return false;
int n = board.length;
int m = board[0].length;
visited = new boolean[n][m];
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
if(board[i][j]==word.charAt(0)){
if(dfs(board, word, i, j, 0)) return true;
}
}
}
return false;
}
private boolean dfs(char[][] board, String word, int i, int j, int k){
if(k==word.length()) {return true;}
//不符合条件包括四项
if(i<0||i>=board.length||j<0||j>=board[0].length||board[i][j]!=word.charAt(k)||visited[i][j]){
return false;
}
// if(k==word.length()-1&&board[i][j]==word.charAt(k)) {flag=true; return;}
// char temp = board[i][j];
visited[i][j] = true;
for(int d=0; d<direction.length; d++){
if (dfs(board, word, i+direction[d][0], j+direction[d][1], k+1)) return true;
}
visited[i][j] = false;
return false;
}
}
3.字符串排列
import java.util.ArrayList;
import java.util.*;
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> ret= new ArrayList<>();
if(str.length()==0) return ret;
else{
backtracking(str.toCharArray(), 0, ret);
Collections.sort(ret);
}
return ret;
}
public void backtracking(char[] str, int i, ArrayList<String> ret){
if(i==str.length-1) ret.add(String.valueOf(str));
// 没有不符合条件退回
else{
//fix -1 position and 0 exchanges values with other positions
// 遍历能交换的元素
for(int j=i; j<str.length; j++){
if(i==j||str[i]!=str[j]){
swap(str, i, j);
backtracking(str, i+1, ret);
swap(str, j, i);
}
}
}
}
public void swap(char[] str, int i, int j){
char temp = str[i];
str[i] = str[j];
str[j] = temp;
}
}
4. 组合
Leetcode : 77. Combinations (Medium)
思路:差不多的思路,但是要注意第一层只能是n-k+1, 每往后一层,可选的数字范围就+1,所以每次k都要减1
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> ret = new ArrayList<>();
List<Integer> combineList = new ArrayList<>();
backtracking(1, n, k, combineList, ret);
return ret;
}
private void backtracking(int start, int n, int k, List<Integer> combineList, List<List<Integer>> ret){
if(k == 0){
ret.add(new ArrayList(combineList)); // 这里要重新构造一个 List
return;
}
for(int i = start; i <= n - k + 1; i++){ // 剪枝
combineList.add(i); // 把 i 标记为已访问
backtracking(i + 1, n, k - 1, combineList, ret);
combineList.remove(combineList.size() - 1); // 把 i 标记为未访问
}
}
5. 数组和为某个数的所有组合
Leetcode : 39. Combination Sum (Medium)
class Solution {
public List<List<Integer>> combinationSum(int[] candidates, int target) {
List<List<Integer>> ret= new ArrayList<>();
int sum = 0;
doCombinationSum(candidates, ret, target, sum, 0, new ArrayList<>());
return ret;
}
private void doCombinationSum(int[] candidates, List<List<Integer>> ret, int target, int sum, int start, List<Integer> list){
if(target<sum) return;
else if(target==sum) {
ret.add(new ArrayList<>(list));
return;
}
//因为某个数可以被重复使用多次,所以start在下一层递归中是不需要的
for(int i=start; i<candidates.length; i++){
//这个写在递归函数里会保险点,但是不允许
list.add(candidates[i]);
doCombinationSum(candidates, ret, target, sum + candidates[i], i, list);
// 因为返回的时候我们不需要当前记载的元素了。
list.remove(list.size()-1);
}
}
}
6.数组和为某个数的所有组合II
Leetcode : 40. Combination Sum II (Medium)
public List<List<Integer>> combinationSum2(int[] candidates, int target) {
List<List<Integer>> list = new LinkedList<List<Integer>>();
// 要先排序
Arrays.sort(candidates);
backtrack(list, new ArrayList<Integer>(), candidates, target, 0);
return list;
}
private void backtrack(List<List<Integer>> list, List<Integer> tempList, int[] cand, int remain, int start) {
if(remain < 0) return; /** no solution */
else if(remain == 0) list.add(new ArrayList<>(tempList));
else{
for (int i = start; i < cand.length; i++) {
//区别在这里
if(i > start && cand[i] == cand[i-1]) continue; /** skip duplicates */
tempList.add(cand[i]);
backtrack(list, tempList, cand, remain - cand[i], i+1);
tempList.remove(tempList.size() - 1);
}
}
}
7.不含有相同元素的子集
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
backtrack(list, new ArrayList<>(), nums, 0);
return list;
}
private void backtrack(List<List<Integer>> list , List<Integer> tempList, int [] nums, int start){
list.add(new ArrayList<>(tempList));
for(int i = start; i < nums.length; i++){
tempList.add(nums[i]);
backtrack(list, tempList, nums, i + 1);
tempList.remove(tempList.size() - 1);
}
}
8. 含有相同元素的子集
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
backtrack(list, new ArrayList<>(), nums, 0);
return list;
}
private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, int start){
list.add(new ArrayList<>(tempList));
for(int i = start; i < nums.length; i++){
//只能选一个
if(i > start && nums[i] == nums[i-1]) continue; // skip duplicates
tempList.add(nums[i]);
backtrack(list, tempList, nums, i + 1);
tempList.remove(tempList.size() - 1);
}
}
9. 数组的所有排列组合结果
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
// Arrays.sort(nums); // not necessary
backtrack(list, new ArrayList<>(), nums);
return list;
}
private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums){
if(tempList.size() == nums.length){
list.add(new ArrayList<>(tempList));
} else{
for(int i = 0; i < nums.length; i++){
if(tempList.contains(nums[i])) continue; // element already exists, skip
tempList.add(nums[i]);
backtrack(list, tempList, nums);
tempList.remove(tempList.size() - 1);
}
}
}
10.数组的所有排列组合结果II
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
backtrack(list, new ArrayList<>(), nums, new boolean[nums.length]);
return list;
}
private void backtrack(List<List<Integer>> list, List<Integer> tempList, int [] nums, boolean [] used){
if(tempList.size() == nums.length){
list.add(new ArrayList<>(tempList));
} else{
for(int i = 0; i < nums.length; i++){
if(used[i] || i > 0 && nums[i] == nums[i-1] && !used[i - 1]) continue;
used[i] = true;
tempList.add(nums[i]);
backtrack(list, tempList, nums, used);
used[i] = false;
tempList.remove(tempList.size() - 1);
}
}
}
11.分割字符串成回文字符串
public List<List<String>> partition(String s) {
List<List<String>> list = new ArrayList<>();
backtrack(list, new ArrayList<>(), s, 0);
return list;
}
public void backtrack(List<List<String>> list, List<String> tempList, String s, int start){
if(start == s.length())
list.add(new ArrayList<>(tempList));
else{
for(int i = start; i < s.length(); i++){
if(isPalindrome(s, start, i)){
tempList.add(s.substring(start, i + 1));
backtrack(list, tempList, s, i + 1);
tempList.remove(tempList.size() - 1);
}
}
}
}
public boolean isPalindrome(String s, int low, int high){
while(low < high)
if(s.charAt(low++) != s.charAt(high--)) return false;
return true;
}