刷题笔记:Random专题 在某大厂的3轮面试中遇到了2次本类型的题!!

#470 用Rand7()实现Rand10()

// The rand7() API is already defined for you.
// int rand7();
// @return a random integer in the range 1 to 7

class Solution {
public:
    int rand10() {
        while(true){
            int a=rand7();
            int b=rand7();
            int index=b+(a-1)*7;
            if(index<=40){
                return 1+index%10;
            }
            //(1,9)
            a=index-40;
            b=rand7();
            index=b+(a-1)*7;
            if(index<=60){
                return 1+index%10;
            }
            //(1,3)
            a=index-60;
            b=rand7();
            index=b+(a-1)*7;
            if(index<=20){
                return 1+index%10;
            }
        }
    }
};

#528.按权重随机选择

记得数学中常用的赋予数字几何意义!!!!

lower_bound(起始地址,结束地址,要查找的数值) 返回的是数值 第一个 出现的位置。

upper_bound(起始地址,结束地址,要查找的数值) 返回的是数值 最后一个 出现的位置。

class Solution {
public:
    vector<int> presum;
    Solution(vector<int>& w) {
        if(w.size()==1){
            presum.push_back(w[0]);
            return;
        }
        presum.push_back(w[0]);
        for(int i=1;i<w.size();i++){
            presum.push_back(presum[i-1]+w[i]);
        }
    }
    
    int pickIndex() {
        int i=rand()%presum[presum.size()-1] +1;
        int index=lower_bound(presum.begin(),presum.end(),i)-presum.begin();
        return index;
    }
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution* obj = new Solution(w);
 * int param_1 = obj->pickIndex();
 */

#519.随机反转矩阵

 


class Solution {
public:

    unordered_map<int,int> V;
    int nr, nc, rem;

    //c++11 random integer generation
    mt19937 rng{random_device{}()};
    Solution(int n_rows, int n_cols) {
        nr = n_rows, nc = n_cols, rem = nr * nc;
    }

    vector<int> flip() {
         //uniform random integer in [0, bound]
        uniform_int_distribution<int> uni(0,--rem);
        int r=uni(rng);
        int x = V.count(r) ? V[r] : r;
        V[r] = V.count(rem) ? V[rem] : rem;
        return {x / nc, x % nc};
    }

    void reset() {
        V.clear();
        rem = nr*nc;
    }
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution* obj = new Solution(n_rows, n_cols);
 * vector<int> param_1 = obj->flip();
 * obj->reset();
 */

#497.非重叠矩形中的随机点

rand()伪随机 :  感觉算法逻辑是正确的,但leetcode上会不通过,因为随机数算法不同输出和预期会不同

class Solution {
public:
    vector<int> presum;
    vector<vector<int>> _rects;
    Solution(vector<vector<int>>& rects) {
        this->_rects=rects;
        if(rects.size()==1){
            int h=rects[0][2]-rects[0][0]+1;
            int w=rects[0][3]-rects[0][1]+1;
            presum.push_back(h*w);
            return;
        }
        int h=rects[0][2]-rects[0][0]+1;
        int w=rects[0][3]-rects[0][1]+1;
        presum.push_back(h*w);
        for(int i=1;i<rects.size();i++){
            //第i个矩形面积
            h=rects[i][2]-rects[i][0]+1;
            w=rects[i][3]-rects[i][1]+1;
            presum.push_back(presum[i-1]+h*w);
        }
    }
    
    vector<int> pick() {
        int r=rand()%presum.back();
        //随机选矩形
        int index=lower_bound(presum.begin(),presum.end(),r)-presum.begin();
        //选中矩形后随机选x,y
        int newx=rand()%(_rects[index][2]-_rects[index][0]+1)+_rects[index][0];
        int newy=rand()%(_rects[index][3]-_rects[index][1]+1)+_rects[index][1];
        return {newx,newy};
    }
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution* obj = new Solution(rects);
 * vector<int> param_1 = obj->pick();
 */

 用mt19937生成器和uniform_int_distribution<int> uni;

class Solution {
public:

    vector<vector<int>> rects;
    vector<int> psum;
    int tot = 0;
    //c++11 random integer generation
    mt19937 rng{random_device{}()};
    uniform_int_distribution<int> uni;

    Solution(vector<vector<int>> rects) {
        this->rects = rects;
        for (auto& x : rects) {
            tot += (x[2] - x[0] + 1) * (x[3] - x[1] + 1);
            psum.push_back(tot);
        }
        uni = uniform_int_distribution<int>{0, tot - 1};
    }

    vector<int> pick() {
        int targ = uni(rng);

        int lo = 0;
        int hi = rects.size() - 1;
        while (lo != hi) {
            int mid = (lo + hi) / 2;
            if (targ >= psum[mid]) lo = mid + 1;
            else hi = mid;
        }

        auto& x = rects[lo];
        int width = x[2] - x[0] + 1;
        int height = x[3] - x[1] + 1;
        int base = psum[lo] - width * height;
        return {x[0] + (targ - base) % width, x[1] + (targ - base) / width};
    }
};

 

#478.在圆内随机生成点

对于单位圆随机分别生成半径 和  角度(0-2Pi)

class Solution {
public:
    double rad, xc, yc;
    //c++11 random floating point number generation
    mt19937 rng{random_device{}()};
    uniform_real_distribution<double> uni{0, 1};

    Solution(double radius, double x_center, double y_center) {
        rad = radius, xc = x_center, yc = y_center;
    }

    vector<double> randPoint() {
        double d = rad * sqrt(uni(rng));
        double theta = uni(rng) * (2 * M_PI);
        return {d * cos(theta) + xc, d * sin(theta) + yc};
    }
};

拒接采样法:在外接矩形随机选点,在圆内就输出

class Solution {
public:
    double rad, xc, yc;
    //c++11 random floating point number generation
    mt19937 rng{random_device{}()};
    uniform_real_distribution<double> uni{0, 1};

    Solution(double radius, double x_center, double y_center) {
        rad = radius, xc = x_center, yc = y_center;
    }

    vector<double> randPoint() {
        double x0 = xc - rad;
        double y0 = yc - rad;

        while(true) {
            double xg = x0 + uni(rng) * 2 * rad;
            double yg = y0 + uni(rng) * 2 * rad;
            if (sqrt(pow((xg - xc), 2) + pow((yg - yc), 2)) <= rad)
                return {xg, yg};
        }
    }
};

#710.黑名单中的随机数

这题有点难啊!!!光写个相对好理解的方法,利用哈希表进行映射

官方题解:

class Solution {
public:

    unordered_map<int, int> m;
    int wlen;

    Solution(int n, vector<int> b) {
        wlen = n - b.size();
        unordered_set<int> w;
        for (int i = wlen; i < n; i++) w.insert(i);
        for (int x : b) w.erase(x);
        auto wi = w.begin();
        for (int x : b)
            if (x < wlen)
                m[x] = *wi++;
    }

    int pick() {
        int k = rand() % wlen;
        return m.count(k) ? m[k] : k;
    }
};

 自己写的:

class Solution {
public:
    Solution(int N, vector<int>& blacklist) {
        //计算白名单长度
        wlen=N-blacklist.size();
        unordered_set<int> w;
        //将长度后的元素都放到白名单中
        for(int i=wlen;i<N;i++){
            w.insert(i);
        }
        //将黑名单中大于wlen的元素在白名单中剔除
        for(int i=0;i<blacklist.size();i++){
            if(blacklist[i]>=wlen){
                w.erase(blacklist[i]);
            }
        }
        auto iter=w.begin();
        for(int i=0;i<blacklist.size();i++){
            if(blacklist[i]<wlen){
                hash[blacklist[i]]=*iter;
                iter++;
            }
        }

    }
    
    int pick() {
        int i=rand()%wlen;
        return hash.count(i)?hash[i]:i;
    }
private:
    int wlen;
    unordered_map<int,int> hash;
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution* obj = new Solution(N, blacklist);
 * int param_1 = obj->pick();
 */

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值