洗牌算法、蓄水池抽样算法

洗牌算法 
 

应用场景 Link

  1. 知道数组的长度N
  2. 将数组随机打散

算法实现

  1. 按照下标 i 从后向前遍历,在 [0, i] 随机选择一个下标 rand_idx
  2. 将 arr[rand_idx] 与 random_i[i] 进行交换

代码实现 

void shuffle(vector<int>& arr) {
	for (int i = arr.size()-1; i >= 0; i--){
		int rand_idx = rand() % (i+1); // [0,i] 随机选择下标
		swap(arr[i], arr[rand_idx]);   // 交换
	}
}

力扣

  • 384 打乱数组

算法推理(见下图)

蓄水池抽样算法

应用场景:在长度为N的数据流中,等概率选取M个数 (N > M)

  • N的长度未知,是一个数据流

算法实现

  1. 初始化蓄水池M:
    1. 将前M个元素,放入蓄水池 for (i=0; i<M; i++) pool.push(arr[i])
    2. 那么,蓄水池存放的下标范围: [0, M-1]
  2. 下标 i 从第M+1个元素,继续向后遍历
    1. 在 [0, i] 随机选择一个下标 rand_idx
    2. 如果 rand_idx 的下标在蓄水池存放的下标范围内,即:rand_idx ∈ [0, M-1],则:将当前元素random_i[i] 与 蓄水池中的元素 arr[rand_idx] 交换

代码实现

/*
 * @brief 蓄水池抽样算法: 在数据流data[n]中, 等概率选出m个数据
 * @param   [in] nums  数据流
 * @param   [in] n     数据流中数据总个数
 * @param   [in] m     采样数据总个数
 * @return 采样到m个数据
 */
vector<int> Sampling(vector<int> nums, int n, int m) {
    // 前m个元素,构成蓄水池
    vector<int> pool;
    for (int i=0; i<m; i++) {
        pool.push_back(nums[i]);
    }
    
    // 后m个元素
    for (int i=m; i<n; i++) {
         int rand_idx = randIdx(0, i); // 返回[0,i]中的随机下标
         if (0 <= rand_idx < m) { // 如果idx是在蓄水池中,则交换
            swap(nums[i], nums[rand_idx]);
         }
    }
    
    // 蓄水池中的数据,就是等概率选出来的m个数
    return pool;
}

力扣

  • 382链表随机节点
  • 398 随机数索引
  • 497 非重叠矩形中的随机点
  • 519 随机翻转矩阵

算法推理(见下图)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值