• 关于集合的一系列问题


    前几天在力扣刚刷了集合的问题,今天笔试就遇到了,还是有点差别,没有做出来,太菜了。。。

    首先看一下leetcode 78.子集

    问题:

    给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

    解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

    示例 1:

    输入:nums = [1,2,3]
    输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]

    提示:

    • 1 <= nums.length <= 10
    • -10 <= nums[i] <= 10
    • nums 中的所有元素 互不相同

    思路:记原序列中的元素个数为n,序列中的每个元素有两种状态,即在子集中  不在子集中,用1,0分别表示在和不在,

    则每一个子集就对应一个长度为n的0/1序列。例如:n = 3, a = {1, 2, 3}

    000 {} 0
    001 {3} 1
    010 {2} 2
    011 {2, 3} 3
    100 {1} 4
    101 {1, 3} 5
    110 {1, 2} 6
    111 {1, 2, 3} 7

    可以看到0/1序列对应的二进制正好从0到2n-1, 枚举mask∈[0, 2n-1],mask的二进制表示是一个 0/1序列,我们可以按照这个 0/1序列在原集合当中取数。当我们枚举完所有mask,就能构造出所有的子集

    复杂度分析

    时间复杂度:O(n×2n),一共 2n个状态,每种状态需要 O(n)的时间来构造子集

    空间复杂度:O(n)。即构造子集使用的临时数组 t的空间代价。

    class Solution {
    public:
        vector<int> t;
        vector<vector<int>> res;
        vector<vector<int>> subsets(vector<int>& nums) {
            int n=nums.size();
            for(int mask = 0; mask < (1<<n); mask++){
                t.clear();
                for(int i =0; i < n; ++i){
                    if(mask & (1<<i)){//包含第i位
                        t.push_back(nums[i]);
                    }
                }
                res.push_back(t);
            }
            return res;
        }
    };

    leetcode 90.子集II

    问题:

    给你一个整数数组 nums ,其中可能包含重复元素,请你返回该数组所有可能的子集(幂集)。

    解集 不能 包含重复的子集。返回的解集中,子集可以按 任意顺序 排列。

    示例 1:

    输入:nums = [1,2,2]
    输出:[[],[1],[1,2],[1,2,2],[2],[2,2]]

    提示:

    • 1 <= nums.length <= 10
    • -10 <= nums[i] <= 10

    思路:

    考虑数组 [1,2,2],选择前两个数,或者第一、三个数,都会得到相同的子集。

    也就是说,对于当前选择的数 x,若前面有与其相同的数 y,且没有选择 y,此时包含 x 的子集,必然会出现在包含 y 的所有子集中。

    我们可以通过判断这种情况,来避免生成重复的子集。代码实现时,可以先将数组排序;迭代时,若发现没有选择上一个数,且当前数字与上一个数相同,则可以跳过当前生成的子集。

    复杂度分析:

    时间复杂度:O(n×2n),其中 n 是数组 nums 的长度。排序的时间复杂度为O(nlogn)。一共2n个状态,每种状态需要 O(n)的时间来构造子集,一共需要O(n×2n)的时间来构造子集。由于在渐进意义上 O(nlogn) 小于O(n×2n),故总的时间复杂度为 O(n×2n)。

    空间复杂度:O(n)。即构造子集使用的临时数组 t 的空间代价。

    class Solution {
    public:
        vector<int> t;
        vector<vector<int>> ans;
    
        vector<vector<int>> subsetsWithDup(vector<int> &nums) {
            sort(nums.begin(), nums.end());
            int n = nums.size();
            for (int mask = 0; mask < (1 << n); ++mask) {
                t.clear();
                bool flag = true;
                for (int i = 0; i < n; ++i) {
                    if (mask & (1 << i)) {
                        if (i > 0 && (mask >> (i - 1) & 1) == 0 && nums[i] == nums[i - 1]) {
                            flag = false;
                            break;
                        }
                        t.push_back(nums[i]);
                    }
                }
                if (flag) {
                    ans.push_back(t);
                }
            }
            return ans;
        }
    };

    本次题目:

    输入字符串s,,s中可能有重复字母,求s有多少不含重复字母的子序列,相同字母不同下标,视为不同的子序列。

    示例输入:"aabc"

    输出:12

    解析:"","a","ab","ac","abc","a","ab","ac","abc","b","bc","c"

    思路:首先把字符串遍历一遍,记录下每个字符出现的次数,并且把去除重复的字符放入一个字符数组中,然后与子集方法相同,找字符数组的子集,每枚举到一个子集的时候,判断其中的每一个字符是不是重复字符,如果是则count = count + 重复次数。比如aabc ,对于子集"a",包含字符'a',而‘a’重复的次数为2,故count = count + 2,但是如过没有出现重复,我们就正常+1.

    复杂度:

    时间复杂度:O(n×2n),其中遍历去重,记录重复字符,时间复杂度为O(n), 一共2n个状态,每种状态需要 O(n)的时间来构造子集,一共需要O(n×2n)的时间来构造子集。由于在渐进意义上 O(n) 小于O(n×2n),故总的时间复杂度为 O(n×2n)。

    空间复杂度:O(n)。即构造子集使用的临时数组 t 的空间代价,还有字符数组的代价。

    #include<iostream>
    #include<vector>
    #include<string>
    #include<unordered_map>
    using namespace std;
    int main(){
        string s;
        cin>>s;
        unordered_map<int, int> s_map;
        vector<char> res_str;
        int i = 0;
        while(i < s.size()){
            if(s_map.find(s[i]) ==  s_map.end()){
               res_str.push_back(s[i]);
               s_map[s[i]] = 1;
            }else{
                s_map[s[i]]++;
            }
            i++;
        }
        int level = res_str.size();
        int set_count = 1<<level;
        int count = 0;
        vector<char> t;
        for(int i = 0; i < set_count; ++i){
            t.clear();
            for(int j = 0; j < level; ++j){
                if(i & (1 << j)){
                    t.push_back(res_str[j]);
                }
            }
            if(t.size() > 0){
                int sign = 0;
                for(auto a : t ){
                    if(s_map[a] > 1){
                        sign++;
                        count += s_map[a] % 20210101;
                    }
                }
                if(sign == 0){
                    count++;
                }
            } else {
                count++;
            }
        }
        cout<<count;
        return 0;
    }
  • 相关阅读:
    UVa 481
    ZOJ 1108 & HDU 1160
    UVa 11450
    UVa 11242
    UVa 750
    UVa 725
    UVa 483
    UVa 10258
    UVa 793
    The Little Girl who Picks Mushrooms HDU 4422 水题类似模拟的一种感觉
  • 原文地址:https://www.cnblogs.com/doris233/p/14616655.html
Copyright © 2020-2023  润新知