leetcode:根据权重随机选择

此题来自力扣,题目主要标签为二分搜索

题目描述:

给定一个正整数数组 w ,其中 w[i] 代表位置 i 的权重,请写一个函数 pickIndex ,它可以随机地获取位置 i,选取位置 i 的概率与 w[i] 成正比。

解题思路:
思路1:

初看到这道题时,我的最基本思路就是根据权重数组w[]构建扩展数组extenedArray[],如果位置i的权重为k,则在扩展数组包含k个i.基于此,我们在范围[0, 权重和)之间生成随机值i, 返回extenedArray[i]即可.

算法分析:
该算法时间复杂度为O(1),但其空间复杂度则与位置i的权重大小相关,扩展数组所需的空间为权重和.假设位置1,2权重分别为1, 1000000, 则扩展数组所需空间为1000001,空间复杂度上限可能为无穷大.因此算法在最坏情况下是不切实际的.

思路2:

思路2是基于官方题解整理出的思路.
与思路1类似,我们可以生成在范围[0, 权重和)之间的随机值i,但我们并不直接构建扩展数组,而是考虑如何将随机值i映射到权重数组的对应下标.这便是该方法最关键的一步.

要点:
1.根据权重数组,构建累加数组.
假设权重数组w = {1, 4, 2}, 则权重数组的累加数组为cumSum = {1, 5, 7}.
2. 使用二分搜索搜索随机值i在累加数组的对应下标.
注意到此处二分搜索不同于基本的二分搜索方法, 对于累加数组{1, 5, 7}, 搜索3, 4, 5都应当返回1,类似地,搜索6, 7都应当返回2.当然对于二分搜索的代码只需要微小的改动即可实现.

分析:
该算法空间复杂度主要分析构建累加数组所需额额外空间, 为O(n);
时间复杂度与二分搜索一致, 为O(lgN);

java实现
class Solution {
    int totalCount; //纪录权重和
    int[] cumSum; //权重权重累加数组
    Random rand = new Random();
    public Solution(int[] w) {
        cumSum = new int[w.length];
        for(int i = 0; i < w.length; i++){
            if(i == 0)
                cumSum[i] = w[i];
            else
                cumSum[i] = w[i] + cumSum[i-1];
        }
        totalCount = cumSum[cumSum.length-1];
    }
    
    public int pickIndex() {
        //从区间[1, totalCount]中返回一个随机值,查找该随机值在前缀数组中的位置
        int randIndex = rand.nextInt(totalCount) + 1;
        return binarySearch(cumSum, randIndex);
    }

    private int binarySearch(int[] cumSum, int x){
        int lo = 0;
        int hi = cumSum.length;
        while(lo < hi){
            int mid = lo + (hi-lo)/2;
            if(cumSum[mid] == x)
                return mid;
            else if(cumSum[mid] < x){
            //可以肯定, 此时x的对应下标一定大于mid, 所以在[mid+1, hi)中搜索
                lo = mid;
            }
            else
            //x的对应下标可能等于mid, 先在[lo, mid)中搜索, 如果搜索不到, 则while循环退出, 返回hi即可
                hi = mid;
        }
        return hi;
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值