01.20 算法练习

1. 分割回文串

算法思路

1. 抽象为组合算法,采用递归,用startIndex进行切割;
2. 只有判断为回文子串,才将StringBuilder加入到path中;

注意点

判断回文子串可以用双指针法。

代码

class Solution {
    List<List<String>> res = new ArrayList<List<String>>();
    LinkedList<String> path = new LinkedList<>();
    public List<List<String>> partition(String s) {
        if(s == null) return res;
        backtracking(s, 0, new StringBuilder());
        return res;
    }

    private void backtracking(String s, int startIndex, StringBuilder sb){
        if(startIndex == s.length()){
            res.add(new ArrayList<>(path));
            return;
        }

        for(int i = startIndex; i<s.length(); i++){
            sb.append(s.charAt(i));
            if(check(sb)){
                path.add(sb.toString());
                backtracking(s, i+1, new StringBuilder());
                path.removeLast();

            }
        }

    }

    private boolean check(StringBuilder sb){
        for(int i = 0; i< sb.length()/2; i++){
            if (sb.charAt(i) != sb.charAt(sb.length()-i-1)) return false;
        }
        return true;
    }
}

2. 复原IP地址

算法思路

1. 用startIndex将数字进行分割;
2. 若分割后的数字满足IP格式要求,再将该数字后面加 “.” ,继续递归;
3. 直至pointNum等于3,终止递归。

注意点

1. 循环 for (int i = start; i < sb.length(); i++) 应该是 for (int i = start; i <= end; i++),只需要计算 start 到 end 之间的数字,而不是整个 sb 的长度;
2. 在 isvalid 方法中,当 sb.charAt(start) == '0' && start!= end 时,应该使用单引号将 0 括起来,因为 char 类型需要使用单引号。
3. 因为有 “。” 的存在,startIndex每次需要加2。

代码

class Solution {
    List<String> res = new ArrayList<>();
    public List<String> restoreIpAddresses(String s) {
        if(s == null) return res;
        StringBuilder sb = new StringBuilder(s);
        backtracking(sb, 0, 0);
        return res;
        
    }

    private void backtracking(StringBuilder sb, int startIndex, int pointNum){
        if(pointNum == 3){
            if(isvalid(sb, startIndex, sb.length()-1)){
                res.add(sb.toString());
            }
            return;
        }

        for(int i = startIndex; i<sb.length(); i++){
            if(isvalid(sb, startIndex, i)){
                sb.insert(i+1, '.');
                pointNum += 1;
                backtracking(sb, i+2, pointNum);
                sb.deleteCharAt(i+1);
                pointNum -= 1;
            }
        }
    }

    private boolean isvalid(StringBuilder sb, int start, int end){
        if(start > end) return false;
        if(sb.charAt(start) == '0' && start != end) return false;
        int nums = 0;
        for(int i = start; i<=end; i++){
            int digit = sb.charAt(i)-'0';
            nums = nums * 10 + digit;
            if(nums > 255) return false;
        }

        return true;
    }
}

3. 子集

算法思路

使用递归的方式,将每一个可能的子集都放进结果集即可。

注意点

如果判断条件是startIndex >= nums.length,则需要加path.add操作放在之前,否则会漏掉自己。

代码

class Solution {
    List<List<Integer>> res = new ArrayList<>();// 存放符合条件结果的集合
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> subsets(int[] nums) {
        if (nums.length == 0) return res;
        backtracking(nums, 0);
        return res;
        
    }

    private void backtracking(int[] nums, int startIndex){
        res.add(new ArrayList<>(path));
        if(startIndex >= nums.length) return;
        for(int i=startIndex; i<nums.length; i++){
            path.add(nums[i]);
            backtracking(nums, i+1);
            path.removeLast();
        }
    }
}

4. 子集 II

算法思路

与前面的子集相同,就是要做去重

注意点

去重操作是要判断used[i-1]是否为false,如果是,说明 i-1 已经回溯了,此时属于同层去重。

代码

class Solution {
    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        if(nums.length == 0) return res;
        Arrays.sort(nums);
        boolean[] used = new boolean[nums.length];
        Arrays.fill(used, false);
        backtracking(nums, 0, used);
        return res;
        
    }

    private void backtracking(int[] nums, int startIndex, boolean[] used){
        res.add(new ArrayList<>(path));
        if(startIndex >= nums.length) return;
        for(int i = startIndex; i<nums.length; i++){
            if(i>0 && nums[i] == nums[i-1] && used[i-1] == false){
                continue;
            }
            path.add(nums[i]);
            used[i] = true;
            backtracking(nums, i+1, used);
            path.removeLast();
            used[i] = false;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值