算法
93. 复原 IP 地址
思路:我们通过StringBuilder来做拼接、删除操作,给了一段ip,我们按每个间隙去分隔,符合就加入分隔情况,然后跳过分隔点,i+2位置继续去回溯检索。
class Solution {
List<String> res = new LinkedList<>();
public List<String> restoreIpAddresses(String s) {
StringBuilder sb = new StringBuilder(s);
back(sb,0,0);
return res;
}
public void back(StringBuilder s,int index,int count){
if(count == 3){
//分隔了三次后就表示可以判断最后一段IP了
if(isVaild(s,index,s.length()-1)){
res.add(s.toString());
}
return;
}
for(int i = index;i<s.length();i++){
//判断是否符合规则
if(isVaild(s,index,i)){
//符合的话,加入StringBuilder
s.insert(i+1,'.');
back(s,i+2,count+1);
s.deleteCharAt(i+1);
}else{
break;
}
}
}
public boolean isVaild(StringBuilder s,int start,int end){
if(start > end){
return false;
}
//不能包含前导零
if(s.charAt(start) == '0' && start!=end){
return false;
}
//检查是否在255里
int num = 0;
for(int i = start;i<=end;i++){
int now = s.charAt(i) - '0';
num = num*10 + now;
if(num > 255){
return false;
}
}
return true;
}
}
class Solution {
List<List<Integer>> res = new ArrayList<>();
List<Integer> list = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
Arrays.sort(nums);
back(nums,0);
return res;
}
public void back(int[] nums,int index){
//我们每次都需要加入
res.add(new ArrayList<>(list));
//回溯返回条件
if(index>=nums.length){
return;
}
//子集
for(int i = index;i<nums.length;i++){
list.add(nums[i]);
back(nums,i+1);
list.remove(list.size()-1);
}
}
}
这里的剪枝其实就是跟day7里面有道题是一样的。
class Solution {
List<List<Integer>> llist = new ArrayList<>();
List<Integer> list = new ArrayList<>();
boolean[] used;
public List<List<Integer>> subsetsWithDup(int[] nums) {
Arrays.sort(nums);
used = new boolean[nums.length];
back(nums,0);
return llist;
}
public void back(int[]nums,int idx){
//子集问题,开头直接加入集合即可
llist.add(new ArrayList(list));
if(idx >= nums.length) return;
for(int i = idx;i<nums.length;i++){
//思考如何剪枝
if(i>0 && nums[i] == nums[i-1] && !used[i-1]){
continue;
}
list.add(nums[i]);
used[i] = true;
back(nums,i+1);
list.remove(list.size()-1);
used[i] = false;
}
}
}
class Solution {
//非递减子序列,本题并没有说是按非递减去排序的,不要一上来就去给排序,其实是乱序找非递减子序列
//因此会出现同一父节点下元素重复使用的情况,我们要排查的就是这个
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
back(nums,0);
return res;
}
public void back(int[]nums,int idx){
//终止:序列中至少有两个元素
if(path.size() >= 2){
res.add(new ArrayList<>(path));
}
//负数转化为正数统计
int[] hash = new int[201];
for(int i = idx;i<nums.length;i++){
//如何剪枝:在path非空的时候,非递减 或 出现过该种情况:如4767
//会出现:47(第一个7),47(第二个7)的情况
if(!path.isEmpty() && nums[i]<path.get(path.size()-1) || hash[nums[i]+100] == 1){
continue;
}
path.add(nums[i]);
hash[nums[i]+100] = 1;
back(nums,i+1);
path.remove(path.size()-1);
}
}
}
class Solution {
List<List<Integer>> llist = new ArrayList<>();
List<Integer> list = new ArrayList<>();
boolean[] used;
public List<List<Integer>> permute(int[] nums) {
used = new boolean[nums.length];
back(nums);
return llist;
}
public void back(int[] nums){
//终止条件:要求全排列,list.size()满足nums长度即可
if(list.size() == nums.length){
llist.add(new ArrayList<>(list));
return;
}
for(int i = 0;i<nums.length;i++){
if(used[i]) continue;
list.add(nums[i]);
used[i] = true;
back(nums);
list.remove(list.size()-1);
used[i] = false;
}
}
}
class Solution {
List<List<Integer>> llist = new ArrayList<>();
List<Integer> list = new ArrayList<>();
boolean[] used;
public List<List<Integer>> permuteUnique(int[] nums) {
Arrays.sort(nums);
used = new boolean[nums.length];
back(nums);
return llist;
}
public void back(int[] nums){
//终止条件:全排列,list长度要为nums长度
if(list.size() == nums.length){
llist.add(new ArrayList<>(list));
return;
}
for(int i = 0;i<nums.length;i++){
//如何剪枝?这种剪枝做法前提是得排序
if(used[i] || i>0 && nums[i] == nums[i-1] && !used[i-1]){
continue;
}
list.add(nums[i]);
used[i] = true;
back(nums);
list.remove(list.size()-1);
used[i] = false;
}
}
}
补充知识点
这两天都只能暂时刷算法(因为租房啊搬家啥的)