【C++】面试101,数组中只出现一次的两个数字,缺失的第一个正整数,三数之和,没有重复数字的全排列,有重复项数字的全排列

目录

1.数组中只出现一次的两个数字

 2.缺失的第一个正整数

 3.三数之和 

 4.没有重复数字的全排列

 5.有重复项数字的全排列


1.数组中只出现一次的两个数字

 

vector<int> FindNumsAppearOnce(vector<int>& array) {
    // write code here
    map<int, int> m; //定义一个map遍历
    for (auto e : array)
        m[e]++; //把每个数字出现的次数统计一下
    vector<int> ans; //存放最后唯一出现的两个元素
    for (auto e : m)
        if (e.second == 1) ans.push_back(e.first);
    if (ans[0] > ans[1]) //题目要求返回必须升序
        swap(ans[0], ans[1]);
    return ans;
}

 2.缺失的第一个正整数

 

   int minNumberDisappeared(vector<int>& nums) {
        // write code here
        int tmp=1;
        sort(nums.begin(),nums.end());
        for( auto e:nums)
        {
            if(e<=0) continue;
            if(e==tmp) tmp++;
            else return tmp;
        }
        return tmp;
    }

 3.三数之和 

vector<vector<int> > threeSum(vector<int>& num) {
    sort(num.begin(), num.end()); //首先排序
    vector<vector<int>>ans; //ans记录答案三元组数组
    map<int, vector<int> > m;//记录找到的两个数,用这两个数去寻找第三个数
    map<pair<int, int>, int> mp; //为了去重
    for (int i = 0; i < num.size(); i++)
    {
        m[num[i]].push_back(i); //首先把num记录下来,然后把对应的下标也记录
    }
    for (int i = 0; i < num.size(); i++)
    {
        for (int j = i + 1; j < num.size(); j++)
        {
            int sum = num[i] + num[j]; //sum为前两个数之和
            if (m.count(-sum)) //-sum是第三个数,如果这个数存在
            {
                vector<int> tmp; //临时三元组,需要判断他是不是符合要求
                tmp.push_back(num[i]);
                tmp.push_back(num[j]);
                tmp.push_back(-sum);
                int a = (num[i] == -sum) + (num[j] == -sum); 
                //a记录了第三个数和前两个数中的几个相等,a=0说明第三个数和前两个都不等,a=1和其中一个等,a=2三数相等
                if (m[-sum].size() <= a) continue; //如果第三个数的下标的数目之和<=a,小于说明数组里没有第三个数
                //比如a=1,假设第三个数=第一个数=10,m[-sum].size()就是记录10的个数,若m[-sum].size()<1说明数组里连10这个数都没有
                //m[-sum].size()=1,说明数组里10这个数只有一个,就是第一个数,所以第三个数还是不存在
                sort(tmp.begin(), tmp.end()); //此时第三个数存在,给tmp排成非降序
                if (mp.count({ tmp[0],tmp[1] }) != 0) continue; //如果mp里面存在这样的三元组,说明重复
                ans.push_back(tmp); //此时满足一个三元组的所有要求,加入到答案里
                mp[{tmp[0], tmp[1]}] = tmp[2]; //用第三个数标记这个三元组
            }
        }
    }
    return ans;
}

 4.没有重复数字的全排列

这个题太容易把自己绕进去了

首先肯定是回溯的思想,如果只有一个数字全排列,直接用一个临时vector v压入这个数字,然后ans把v压入,然后把这个元素从v中pop

但是如果更复杂,不止一个数字,所以思路就是:

先把第一个数字压入,然后用一个临时vector t,储存除了v中的数字

然后开始把临时变量当做v取数字的范围


vector<vector<int> > permute(vector<int>& num) {
    vector<vector<int>> ans;
    vector<int> v;
    recursion(num, v, ans);
    return ans;
}
void recursion(vector<int> num, vector<int>& v, vector<vector<int>>& ans)
{
    if (num.size() == 1) //回溯
    {
        v.push_back(num[0]);
        ans.push_back(v);
        v.pop_back();
        return;
    }
    for (auto e : num)
    {
        v.push_back(e);
        vector<int> t;
        for (auto i : num)
            if (i != e) t.push_back(i);
        recursion(t, v, ans);
        v.pop_back();
    }
}

 5.有重复项数字的全排列

重复项那我们思路就和上一个题 稍微不一样,之前是不能重复,所以i和e不能相等

但是这次只要下标不一样就可以,但是会有重复,所以直接用set去重,然后转成vector

   vector<vector<int> > permuteUnique(vector<int> &num) {
        
    set<vector<int>> ans;
    vector<int> v;
    recursion(num, v, ans);

    return vector<vector<int>>(ans.begin(),ans.end());
}
void recursion(vector<int> num, vector<int>& v, set<vector<int>>& ans)
{
    if (num.size() == 1) //回溯
    {
        v.push_back(num[0]);
        ans.insert(v);
        v.pop_back();
        return;
    }
    for (int i=0;i<num.size();i++)
    {
        v.push_back(num[i]);
        vector<int> t;
        for (int j=0;j<num.size();j++)
           if (i != j)  t.push_back(num[j]);
        recursion(t, v, ans);
        v.pop_back();
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_71138261/article/details/129935984
今日推荐