摘要
主要是的分析介绍leetcode中的算法题目。
一、回溯算法总结:
总结:子集、组合类问题,关键是用一个 start 参数来控制选择列表!!最后回溯六步走:
1、画出递归树,找到状态变量(回溯函数的参数),这一步非常重要※
2、根据题意,确立结束条件
3、找准选择列表(与函数参数相关),与第一步紧密关联※
4、判断是否需要剪枝
5、作出选择,递归调用,进入下一层
6、撤销选择
二、算法练习
剑指 Offer II 087. 复原 IP
package 回溯算法;
import java.util.ArrayList;
import java.util.List;
public class restoreIpAddressesV2 {
public List<String> restoreIpAddressesV2(String s) {
int count = 4;
int[] segment = new int[count];
List<String> list = new ArrayList<>();
int segid = 0;
int index = 0;
dfsv2(s, segid, index, segment, list, count);
return list;
}
private void dfsv2(String s, int segid, int index, int[] segment, List<String> list, int count) {
//如果是segid=4 && index=s.lenegth
if (segid == count) {
if (index == s.length()) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < count; i++) {
sb.append(segment[i]);
if (i != count - 1) {
sb.append('.');
}
}
list.add(sb.toString());
}
return;
}
// 当遍历完成了就返回
if (index == s.length()) {
return;
}
// 当该数字为0的时候
if (s.charAt(index) == '0') {
segment[segid] = 0;
dfsv2(s, segid + 1, index + 1, segment, list, count);
}
int num = 0;
for (int i = index; i < s.length(); i++) {
num = num * 10 + (s.charAt(i) - '0');
// 不能等于0
if (num > 0 && num <= 255) {
segment[segid] = num;
dfsv2(s, segid + 1, i + 1, segment, list, count);
}else {
break;
}
}
}
}
78. 子集
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> lists=new ArrayList<>();
//先添加一个空的集合
lists.add(new ArrayList<>());
for (int num:nums) {
//每遍历一个元素就在之前子集中的每个集合追加这个元素,让他变成新的子集
for (int i=0,j=lists.size();i<j;i++){
List<Integer> list=new ArrayList<>(lists.get(i));
list.add(num);
lists.add(list);
}
}
return lists;
}
}
第二中就判断子集的长度来判断
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> lists = new ArrayList<>();
List<Integer> list = new ArrayList<>();
boolean[] vis = new boolean[nums.length];
for (int i = 0; i <= nums.length; i++) {
dfs(nums, 0, i, vis, list, lists);
}
return lists;
}
private void dfs(int[] nums, int index, int length, boolean[] vis, List<Integer> list, List<List<Integer>> lists) {
if (list.size() == length) {
ArrayList<Integer> tmp=new ArrayList<>();
for (int i:list){
tmp.add(i);
}
Collections.sort(tmp);
// 排序导致有错误
if (!lists.contains(tmp)){
// 这里需要排查在(0,1)(1,0)的两个元素
lists.add(new ArrayList<>(tmp));
return;
}else {
tmp.clear();
}
}
for (int i = index; i < nums.length; i++) {
if (!vis[i]) {
vis[i] = true;
list.add(nums[i]);
dfs(nums, index + 1, length, vis, list, lists);
list.remove(list.size() - 1);
vis[i] = false;
}
}
}
}
package 回溯算法;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
public class subsets78V2 {
public List<List<Integer>> subsets(int[] nums) {
int len = nums.length;
List<List<Integer>> res=new ArrayList<>();
if (len==0){
return res;
}
Deque<Integer> path=new ArrayDeque<>();
dfs(nums,len,0,path,res);
return res;
}
private void dfs(int[] nums, int len, int index, Deque<Integer> path, List<List<Integer>> res) {
if (len==index){
res.add(new ArrayList<>(path));
return;
}
// 不选择这个元素
dfs(nums,len,index+1,path,res);
//选择这个元素
path.addLast(nums[index]);
dfs(nums,len,index+1,path,res);
//回溯算法
path.removeLast();
}
private void dfs2(int[] nums, int len, int index, Deque<Integer> path, List<List<Integer>> res) {
if (len==index){
res.add(new ArrayList<>(path));
return;
}
//选择这个元素
path.addLast(nums[index]);
dfs2(nums,len,index+1,path,res);
//回溯算法
path.removeLast();
// 不选择这个元素
dfs2(nums,len,index+1,path,res);
}
}
17. 电话号码的字母组合
List<String> list = new ArrayList<>();
HashMap<Character, String> map1 = new HashMap<>();
public List<String> letterCombinations3(String digits) {
map1.put('2',"abc");
map1.put('3', "def");
map1.put('4', "ghi");
map1.put('5', "jkl");
map1.put('6', "mno");
map1.put('7', "pqrs");
map1.put('8', "tuv");
map1.put('9', "wxyz");
if (digits.length() == 0) {
return list;
}
dfs(digits, 0, new StringBuilder());
return list;
}
private void dfs(String digits, int index, StringBuilder path) {
if (path.length() == digits.length()) {
list.add(path.toString());
return;
}
String s = map1.get(digits.charAt(index));
for (int i = 0; i < s.length(); i++) {
path.append(s.charAt(i));
dfs(digits,index+1,path);
path.deleteCharAt(path.length()-1);
}
}
22. 括号生成
package 回溯算法;
import java.util.ArrayList;
import java.util.List;
public class generateParenthesis22 {
public List<String> generateParenthesis(int n) {
List<String> ans = new ArrayList<String>();
backtrack(ans, new StringBuilder(), 0, 0, n);
return ans;
}
public void backtrack(List<String> ans, StringBuilder cur, int left, int right, int max) {
// 判断终止条件
if (cur.length() == max * 2) {
ans.add(cur.toString());
return;
}
if (left < max) {
cur.append('(');
backtrack(ans, cur, left + 1, right, max);
cur.deleteCharAt(cur.length() - 1);
}
if (right < left) {
cur.append(')');
backtrack(ans, cur, left, right + 1, max);
cur.deleteCharAt(cur.length() - 1);
}
}
}
39. 组合总和
46. 全排列
package 回溯算法;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
public class permute46 {
/**
* 全排列的 有可能需要去重 也不需要去重
*
* @param nums
* @return
*/
List<List<Integer>> lists;
boolean[] vis;
public List<List<Integer>> permute(int[] nums) {
lists = new ArrayList<>();
vis = new boolean[nums.length];
if (nums.length == 0) {
return lists;
}
dfs(nums, 0, new ArrayList<>(), vis, lists);
return lists;
}
private void dfs(int[] nums, int index, ArrayList<Integer> list, boolean[] vis, List<List<Integer>> lists) {
if (index == nums.length) {
lists.add(new ArrayList<>(list));
return;
}
for (int i = 0; i < nums.length; i++) {
if (!vis[i]) {
vis[i] = true;
list.add(nums[i]);
dfs(nums, index + 1, list, vis, lists);
vis[i] = false;
list.remove(list.size() - 1);
}
}
}
@Test
public void test(){
List<List<Integer>> permute = permute(new int[]{1});
for (List<Integer> list:permute){
for (int i:list){
System.out.print(i+" ");
}
System.out.println();
}
}
}
301. 删除无效的括号
79. 单词搜索
494. 目标和