栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

0611刷题

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

0611刷题

0611刷题

回溯问题

基本模板

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

    for (选择:本层集合中元素(树中节点孩子的数量就是集合的大小)) {
        处理节点;
        backtracking(路径,选择列表); // 递归
        回溯,撤销处理结果
    }
}
LeetCode 77. 组合 LeetCode 77. 组合
class Solution {
public:
    vector> combine(int n, int k) {
        backtracking(1,n,k);
        return result;
    }

    vector> result;
    vector 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 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 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> combinationSum(vector& candidates, int target) {
        backtracking(candidates,target,0,0);
        return result;
    }

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

        for(int i=start;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> combinationSum2(vector& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        vector used(candidates.size(), false);
        backtracking(candidates,target,0,0,used);
        return result;
    }

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

        for(int i=start;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

与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> result;
    vector 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
            if(s[left]!=s[right]) return false;
            left++;
            right--;
        }
        return true;
    }
public:
    vector> 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,很关键。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/965684.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号