代码随想录回溯算法02

39. 组合总和

本题是 集合里元素可以用无数次,那么和组合问题的差别 其实仅在于 startIndex上的控制

题目链接/文章讲解:代码随想录

视频讲解:带你学透回溯算法-组合总和(对应「leetcode」力扣题目:39.组合总和)| 回溯法精讲!_哔哩哔哩_bilibili

import java.util.*;

class Solution {
    LinkedList<Integer> path = new LinkedList<>();
    List<List<Integer>> res = new ArrayList<>();

    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        back(target, 0, 0, candidates);
        return res;
    }

    public void back(int target, int index, int sum, int[] candidates) {
        // 如果当前和等于目标值,加入当前的组合
        if (sum == target) {
            res.add(new LinkedList<>(path)); // 新建一个副本,防止修改
            return;
        }

        // 如果当前和大于目标值,返回
        if (sum > target) {
            return;
        }

        // 从当前索引开始遍历,允许重复选择同一数字
        for (int i = index; i < candidates.length; i++) {
            // 选择当前数字
            path.add(candidates[i]);
            // 递归调用,允许继续选择当前数字
            back(target, i, sum + candidates[i], candidates);
            // 回溯,撤销选择
            path.removeLast();
        }
    }
}

因为数字可以重复使用,在再次调用回溯算法的参数列表里面,i保持不变,表示可以重复选择,记住要把数组传递进来

40.组合总和II

本题开始涉及到一个问题了:去重。

注意题目中给我们 集合是有重复元素的,那么求出来的 组合有可能重复,但题目要求不能有重复组合。

题目链接/文章讲解:代码随想录

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次 。

注意:解集不能包含重复的组合。 

示例 1:

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

视频讲解:回溯算法中的去重,树层去重树枝去重,你弄清楚了没?| LeetCode:40.组合总和II_哔哩哔哩_bilibili

class Solution {
    LinkedList<Integer>path=new LinkedList<>();
    List<List<Integer>>res=new ArrayList<>();
    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);//对数组排序,便于剪枝和避免重复
        back(candidates,target,0,0);
        return res;}
        
        public void back(int []candidates,int target,int index,int sum)
        {
            if(sum==target)
            {
                res.add(new LinkedList<>(path));
                return;
            }
            if(sum>target)
            {
                return;
            }
            for(int i=index;i<candidates.length;i++)
            {
                if(i>index&&candidates[i]==candidates[i-1])continue;//跳过当前i
             path.add(candidates[i]);
             back(candidates,target,i+1,sum+candidates[i]);
             path.removeLast();
            }
        }
}

要想去重,首先得对数组排序,再加上关键语句

if(i>index&&candidates[i]==candidates[i-1])continue;//跳过当前i

可以回顾一下之前的三数之和,四数之和的剪枝去叶操作。

131.分割回文串

本题较难,大家先看视频来理解 分割问题,明天还会有一道分割问题,先打打基础。

给你一个字符串 s,请你将 s 分割成一些 子串,使每个子串都是 回文串 。返回 s 所有可能的分割方案。

示例 1:

输入:s = "aab"
输出:[["a","a","b"],["aa","b"]]

示例 2:

输入:s = "a"
输出:[["a"]]

代码随想录

视频讲解:带你学透回溯算法-分割回文串(对应力扣题目:131.分割回文串)| 回溯法精讲!_哔哩哔哩_bilibili

class Solution {
    List<List<String>>res=new ArrayList<>();
    LinkedList<String>path=new LinkedList<>();
    public List<List<String>> partition(String s) {
        back(s,0);
        return res;
    }
   public void back(String s,int index)
   {
    if(index==s.length())//表示所有的子串都已经分割
    {
        res.add(new LinkedList<>(path));
         return;
         }
   
   for(int i=index;i<s.length();i++)
   {
    String m=s.substring(index,i+1);//不断分割字符串,起点索引和终点索引,左闭右开
    if(ishuiwen(m)){
    path.add(m);
    back(s,i+1);
    path.removeLast();//集合使用size()
   }
}}
//java中方法中不能嵌套方法
public boolean ishuiwen(String s)
{
    int left=0;
    int right=s.length()-1;
    while(left<right)
    {
        if(s.charAt(left)!=s.charAt(right))
        {return false;}
        left++;
        right--;
    }
    return true;
}

}

注意点:在回溯函数中,注意什么时候使用index,什么时候使用i

s.substring(i,j),i为起始索引,j为终点索引,左闭右开

难点部分和优化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值