0611刷题

这篇博客详细介绍了如何使用回溯算法解决LeetCode中的组合问题,包括组合总和、电话号码字母组合等。通过展示代码模板和具体实例,解释了回溯法在求解组合问题时的思路和步骤,并强调了回溯过程中终止条件、递归调用及回溯操作的重要性。此外,还讨论了如何处理重复元素,确保每个数字在每个组合中只使用一次。
摘要由CSDN通过智能技术生成

0611刷题

回溯问题

基本模板

void backtracking(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}

LeetCode 77. 组合

LeetCode 77. 组合
class Solution {
public:
    vector<vector<int>> combine(int n, int k) {
        backtracking(1,n,k);
        return result;
    }

    vector<vector<int>> result;
    vector<int> vec;
    void backtracking(int start,int n,int k)
    {
        
        if(vec.size()==k)
        {
            result.push_back(vec);
            return;
        }

        for(int i=start;i<=n;++i)
        {
            vec.push_back(i);
            backtracking(i+1,n,k);
            vec.pop_back();
        }
    }
};

for循环每次从start开始遍历,然后用vec保存取到的节点i。

LeetCode 17. 电话号码的字母组合

LeetCode 17. 电话号码的字母组合
class Solution {
private:
    const string letterMap[10] = {
        "", // 0
        "", // 1
        "abc", // 2
        "def", // 3
        "ghi", // 4
        "jkl", // 5
        "mno", // 6
        "pqrs", // 7
        "tuv", // 8
        "wxyz", // 9
    };
public:
    vector<string> result;
    string s;
    void backtracking(const string& digits, int index) {
        if (index == digits.size()) {
            result.push_back(s);
            return;
        }
        int digit = digits[index] - '0';        // 将index指向的数字转为int
        string letters = letterMap[digit];      // 取数字对应的字符集
        for (int i = 0; i < letters.size(); i++) {
            s.push_back(letters[i]);            // 处理
            backtracking(digits, index + 1);    // 递归,注意index+1,一下层要处理下一个数字了
            s.pop_back();                       // 回溯
        }
    }
    vector<string> letterCombinations(string digits) {
        s.clear();
        result.clear();
        if (digits.size() == 0) {
            return result;
        }
        backtracking(digits, 0);
        return result;
    }
};

终止条件就是如果index 等于 输入的数字个数(digits.size)了(本来index就是用来遍历digits的)

这个index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。

LeetCode 39. 组合总和

LeetCode 39. 组合总和
class Solution {
public:
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        backtracking(candidates,target,0,0);
        return result;
    }

    vector<vector<int>> result;
    vector<int> vec;
    void backtracking(vector<int>& candidates,int target,int sum,int start)
    {
        if(sum>target) return;
        if(sum==target)
        {
            result.push_back(vec);
            return ;
        }

        for(int i=start;i<candidates.size();++i)
        {
            vec.push_back(candidates[i]);
            sum+=candidates[i];
            backtracking(candidates,target,sum,i);
            sum-=candidates[i];
            vec.pop_back();
        }
    }
};

LeetCode 40. 组合总和 II

LeetCode 40. 组合总和 II
class Solution {
public:
    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        vector<bool> used(candidates.size(), false);
        backtracking(candidates,target,0,0,used);
        return result;
    }

    vector<vector<int>> result;
    vector<int> vec;
    void backtracking(vector<int>& candidates,int target,int sum,int start,vector<bool>& used)
    {
        if(sum>target) return;
        if(sum==target)
        {
            result.push_back(vec);
            return ;
        }

        for(int i=start;i<candidates.size()&& sum + candidates[i] <= target;++i)
        {
            // 要对同一树层使用过的元素进行跳过
            //如果candidates[i] == candidates[i - 1] 并且 used[i - 1] == false,就说明:前一个树枝,使用了candidates[i - 1],也就是说同一树层使用过candidates[i - 1]。此时for循环里就应该做continue的操作。
            if(i>0&&candidates[i]==candidates[i-1]&&used[i-1]==false) continue;

            vec.push_back(candidates[i]);
            sum+=candidates[i];
            used[i]=true;
            backtracking(candidates,target,sum,i+1,used);
            used[i]=false;
            sum-=candidates[i];
            vec.pop_back();  
        }
    }
};
//1 1 2 5 6 7 10

40.组合总和II1

LeetCode 39. 组合总和套路相同,此题还需要加一个bool型数组used,用来记录同一树枝上的元素是否使用过。

如果candidates[i] == candidates[i - 1] 并且 used[i - 1] == false,就说明:前一个树枝,使用了candidates[i - 1],也就是说同一树层使用过candidates[i - 1]。此时for循环里就应该做continue的操作。

下面代码保证每个数字只使用一次:

backtracking(candidates, target, sum, i + 1, used); // 和39.组合总和的区别1:这里是i+1,每个数字在每个组合中只能使用一次

LeetCode 131. 分割回文串

LeetCode 131. 分割回文串
class Solution {
private:
    vector<vector<string>> result;
    vector<string> path; // 放已经回文的子串
    void backtracking (const string& s, int startIndex) {
        // 如果起始位置已经大于s的大小,说明已经找到了一组分割方案了
        if (startIndex >= s.size()) {
            result.push_back(path);
            return;
        }
        for (int i = startIndex; i < s.size(); i++) {
            if (isPalindrome(s, startIndex, i)) {   // 是回文子串
                // 获取[startIndex,i]在s中的子串
                string str = s.substr(startIndex, i - startIndex + 1);
                path.push_back(str);
            } else {                                // 不是回文,跳过
                continue;
            }
            backtracking(s, i + 1); // 寻找i+1为起始位置的子串
            path.pop_back(); // 回溯过程,弹出本次已经填在的子串
        }
    }
    bool isPalindrome(const string& s, int left, int right) {
        while(left<right)
        {
            if(s[left]!=s[right]) return false;
            left++;
            right--;
        }
        return true;
    }
public:
    vector<vector<string>> partition(string s) {
        result.clear();
        path.clear();
        backtracking(s, 0);
        return result;
    }
};

注意点:判断回文串中使用 left和right,使得在回溯函数中可以直接在原string上判断是否回文串,然后用substr直接得到回文串。

bool isPalindrome(const string& s, int left, int right)

注意回溯过程中的continue,很关键。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值