文章链接: 93.复原IP地址 78.子集 90.子集II

视频链接: 93.复原IP地址 78.子集 90.子集II

题目链接: 93.复原IP地址 78.子集 90.子集II

93.复原IP地址

思路:

切割问题

1.深度(递归函数):移动startIndex

2.宽度(for循环):移动 i

class Solution {
public:
    vector<string> result;

    void backtracking(string& s, int startIndex, int pointNum) {
        if(pointNum == 3) {
        	// 判断第四段子字符串是否合法,如果合法就放进result中
            if(isValid(s, startIndex, s.size() - 1)) { 
                result.push_back(s);
            }
            return;
        }
        for(int i = startIndex; i < s.size(); i++) {
            if(isValid(s, startIndex, i)) {
                s.insert(s.begin() + i + 1, '.');
                pointNum++;
                backtracking(s, i + 2, pointNum);
                s.erase(s.begin() + i + 1);
                pointNum--; 
            } else {
                break; // [startIndex, i] 这个区间的字串不合法,直接跳出
            }
        }
    }

    // 判断是否是有效数字
    bool isValid(const string& s, int start, int end) {
        if(start > end) { // 第一种无效情况
            return false;
        }
        if(s[start] == '0' && start != end) { // 第二种无效情况:0开头的数字无效
            return false;
        }
        int num = 0;
        for(int i = start; i <= end; i++) { // 第三种无效情况:有非正整数字符
            if(s[i] > '9' || s[i] < '0') {
                return false;
            }
            num = num * 10 + (s[i] - '0');
            if(num > 255) { // 第四种无效情况:数字大于255
                return false;
            }
        }
        return true;
    }

    vector<string> restoreIpAddresses(string s) {
        result.clear();
        if(s.size() < 4 || s.size() > 12) {
            return result;
        }
        backtracking(s, 0, 0);
        return result;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.


78.子集

思路:

子集问题

与组合问题、分割问题的区别如果把 子集问题、组合问题、分割问题都抽象为一棵树的话,那么组合问题和分割问题都是收集树的叶子节点,而子集问题是找树的所有节点!

class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;

    void backtracking(vector<int>& nums, int startIndex) {
        result.push_back(path);
        if(startIndex >= nums.size()) {
            return;
        }
        for(int i = startIndex; i < nums.size(); i++) {
            path.push_back(nums[i]);
            backtracking(nums, i + 1);
            path.pop_back();
        }
    }

    vector<vector<int>> subsets(vector<int>& nums) {
        result.clear();
        path.clear();
        backtracking(nums, 0);
        return result;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.


90.子集II

思路:

与上题的区别:所给数组有重复元素,所以要增加去重的部分。

class Solution {
private:
    vector<vector<int>> result;
    vector<int> path;
    
    void backtracking(vector<int>& nums, int startIndex) {
        result.push_back(path);
        for (int i = startIndex; i < nums.size(); i++) {
            // 对使用过的元素进行跳过(去重)
            if (i > startIndex && nums[i] == nums[i - 1] ) { // 注意要i > startIndex
                continue;
            }
            path.push_back(nums[i]);
            backtracking(nums, i + 1);
            path.pop_back();
        }
    }

public:
    vector<vector<int>> subsetsWithDup(vector<int>& nums) {
        result.clear();
        path.clear();
        sort(nums.begin(), nums.end()); // 去重需要排序!!!!!
        backtracking(nums, 0);
        return result;
    }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.