算法训练营(day28)
回溯算法模板
1 2 3 4 5 6 7 8 9 10 11 12
| void backtracking(参数) { if (终止条件) { 存放结果; return; }
for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) { 处理节点; backtracking(路径,选择列表); 回溯,撤销处理结果 } }
|
93. 复原 IP 地址
题目链接:https://leetcode.cn/problems/restore-ip-addresses/description/
有效 IP 地址 正好由四个整数(每个整数位于 0
到 255
之间组成,且不能含有前导 0
),整数之间用 '.'
分隔。
- 例如:
"0.1.2.201"
和 "192.168.1.1"
是 有效 IP 地址,但是 "0.011.255.245"
、"192.168.1.312"
和 "192.168@1.1"
是 无效 IP 地址。
给定一个只包含数字的字符串 s
,用以表示一个 IP 地址,返回所有可能的有效 IP 地址,这些地址可以通过在 s
中插入 '.'
来形成。你 不能 重新排序或删除 s
中的任何数字。你可以按 任何 顺序返回答案。
解题思路
解题过程:回溯
- 定义地址有效判断
- 字符串最大长度不超过12
- 字符串仅包含
0-9
的数字
- 如果每段字符串的首位为 0,则0后 不能跟任何数字
- 每段字符串不能超过 255
- 定义终止条件:当 逗点. 等于3时,判断第四段字符串是否有效,合法则放入
result
中
- 定义循环条件
- 横向:从
startIndex
遍历到 s.length() - 1
- 纵向:如果合法,则对字符串加入 逗点. 隔开,下一个字符串起始位置向后延一位
(i + 2)
,计算 逗点的数
- 回溯:回滚逗点个数,同时将字符串连接起来
详细代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| class Solution { List<String> result = new ArrayList<>();
public List<String> restoreIpAddresses(String s) { if(s.length() > 12){ return result; } backTrack(s, 0, 0); return result; }
public boolean isValid(String s, int start, int end){ if(start > end){ return false; } if(s.charAt(start) == '0' && start != end){ return false; } int num = 0; for(int i = start; i <= end; i++){ if(s.charAt(i) > '9' || s.charAt(i) < '0'){ return false; } num = num * 10 + (s.charAt(i) - '0'); if(num > 255){ return false; } } return true; }
public void backTrack(String s, int startIndex, int num){ if(num == 3){ if(isValid(s, startIndex, s.length() - 1)){ result.add(s); } return; } for(int i = startIndex; i < s.length(); i++){ if(isValid(s, startIndex, i)){ s = s.substring(0, i + 1) + "." + s.substring(i + 1); num++; backTrack(s, i + 2, num); num--; s = s.substring(0, i + 1) + s.substring(i + 2); }else{ break; } }
} }
|
78. 子集
题目链接:https://leetcode.cn/problems/subsets/description/
给你一个整数数组 nums
,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
解题思路
解题过程:回溯、子集无序
- 定义终止条件:每一个元素都要使用,所以需要全部遍历,终止条件可以省略
- 定义循环条件
- 横向:从
startIndex
遍历到 nums.length - 1
- 纵向:每一次从
startIndex
往后遍历
- 回溯:回滚
path
的末位元素
详细代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { List<List<Integer>> result = new ArrayList<>(); LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> subsets(int[] nums) { backTrack(nums, 0); return result; }
public void backTrack(int[] nums, int startIndex){ result.add(new ArrayList<>(path)); if(startIndex >= nums.length){ return; } for(int i = startIndex; i < nums.length; i++){ path.add(nums[i]); backTrack(nums, i + 1); path.removeLast(); } } }
|
90. 子集 II
题目链接:https://leetcode.cn/problems/subsets-ii/description/
给你一个整数数组 nums
,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。
解题思路
解题过程:回溯、子集无序、不能重复
- 有重复数组,为进行去重,先对数组进行排序
- 定义终止条件:每一个元素都要使用,所以需要全部遍历,终止条件可以省略
- 定义循环条件
- 添加去重条件:相同元素直接跳过处理
- 横向:从
startIndex
遍历到 nums.length - 1
- 纵向:每一次从
startIndex
往后遍历
- 回溯:回滚
path
的末位元素
详细代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Solution { List<List<Integer>> result = new ArrayList<>(); LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> subsetsWithDup(int[] nums) { Arrays.sort(nums); backTrack(nums, 0); return result; }
public void backTrack(int[] nums, int startIndex){ result.add(new ArrayList<>(path)); if(startIndex >= nums.length){ return; } for(int i = startIndex; i < nums.length; i++){ if(i > startIndex && nums[i - 1] == nums[i]){ continue; } path.add(nums[i]); backTrack(nums, i + 1); path.removeLast(); } } }
|