代码随想录算法训练营第二十八天|93. 复原 IP 地址、78. 子集、90. 子集 II

LeetCode 93. 复原 IP 地址

链接:93. 复原 IP 地址

思路:

这道题目和131.分割回文串十分相似,都是分割子字符串,基本做法也是一致的,只不过在判断和结束递归的条件有不同。因为ip地址由四个数构成,所以可以用一个string的数组记录,当数组达到长度4的时候,并且左指针走到了字符串的尾部,则说明这是一个合法的ip地址,记录在最终结果里并返回,反之如果长度为4并且左指针没有走到末尾,则直接返回,因为无论剩下的字符串内容是什么,记录ip地址的数组长度都会超过4,所以不合法。

另外判断单个组成ip地址的数是否合法的条件有两个,一个是stoi(num) <=255,因为不会出现负数所以不需要做>=0的判断。其次是数字首位不能为0,所以当数字首位为0并且数字的位数不为1时直接跳过,当且仅当数字只有一位的时候,数字首位才能为0。最后需要做一个剪枝,因为数字的位数不会超过255,所以数字位数最多只有3位。当子字符串长度超过3时,转换成的数字一定超过255,可以直接break跳过整个数层。

代码:

class Solution {
public:
    vector path;
    vector ans;
    vector restoreIpAddresses(string s) {
        backtracking(s, 0);
        return ans;
    }
    void backtracking(string s, int left)
    {
        if (path.size() == 4 && left == s.size())
        {
            string temp;
            for (int i = 0; i < 3; i++)
            {
                temp.append(path[i]);
                temp.push_back('.');
            }
            temp.append(path[3]);
            ans.push_back(temp);
            return;
        }
        else if (path.size() == 4 || left == s.size())
            return;
        for (int i = left; i < s.size(); i++)
        {
            // 当子字符串长度大于3时剪枝
            if (i - left >= 3)
                break;
            string temp;
            for (int j = left; j <= i; j++)
                temp.push_back(s[j]);
            // 当子字符串长度大于1并且首位为0时剪枝
            if (temp[0] == '0' && temp.size() > 1)
                continue;
            if (stoi(temp) <= 255)
            {
                path.push_back(temp);
                backtracking(s, i + 1);
                path.pop_back();
            }
        }
    }
};

LeetCode 78. 子集

链接:78. 子集

思路:

像这种寻找数组幂集的题目,相当于把树的每个节点的答案都算进去了,所以在每个节点都把答案push进最终结果即可,除此之外,这道题目就是一道标准的找组合的模板题。用一张图可以更清晰的表示子集是如何取每个节点的值的:

代码随想录算法训练营第二十八天|93. 复原 IP 地址、78. 子集、90. 子集 II_第1张图片

 

借用代码随想录的一句话:子集是收集树形结构中树的所有节点的结果而组合问题、分割问题是收集树形结构中叶子节点的结果。

代码:

class Solution {
public:
    vector path;
    vector> ans;
    vector> subsets(vector& nums) {
        // 先把空集push进去
        ans.push_back(path);
        backtracking(nums, 0);
        return ans;
    }
    void backtracking(vector& nums, int idx)
    {
        if (idx == nums.size())
            return;
        for (int i = idx; i < nums.size(); i++)
        {
            path.push_back(nums[i]);
            // 每个节点都要push
            ans.push_back(path);
            backtracking(nums, i + 1);
            path.pop_back();
        }
    }
};

LeetCode 90. 子集 II

链接:90. 子集 II

思路:

和上一题一模一样的套路,唯一的区别是nums数组里的值可能会有重复,这道题中去重的步骤其实和40.组合总和II的逻辑是一样的,都是检查nums[i]是否等于nums[i-1]然后再判断是否可以在树层剪枝,当i>idx则说明是树层。

代码:

class Solution {
public:
    vector path;
    vector> ans;
    vector> subsetsWithDup(vector& nums) {
        ans.push_back(path);
        // 需要排序
        sort(nums.begin(), nums.end());
        backtracking(nums, 0);
        return ans;
    }
    void backtracking(vector& nums, int idx)
    {
        if (idx == nums.size())
            return;
        for (int i = idx; i < nums.size(); i++)
        {
            if (i > idx && nums[i] == nums[i-1])
                continue;
            path.push_back(nums[i]);
            ans.push_back(path);
            backtracking(nums, i + 1);
            path.pop_back();
        }
    }
};

你可能感兴趣的:(代码随想录算法训练营,算法,leetcode,职场和发展)