leetcode528.按权重随机选择

leetcode528.按权重随机选择

  • 题目:给你一个 下标从 0 开始 的正整数数组 w ,其中 w[i] 代表第 i 个下标的权重。

请你实现一个函数 pickIndex ,它可以 随机地 从范围 [0, w.length - 1] 内(含 0 和 w.length - 1)选出并返回一个下标。选取下标 i 的 概率 为 w[i] / sum(w) 。

  • 思路:利用二分查找和前缀和的知识;

  • 声明一个前缀和数组preSum;利用前缀和给数组w的每个下标不同权重的值赋予不同的权重长度,前缀和数组preSum的第i个元素的两个相邻下标值之差则为w[i]的权重;

  • 利用随机数生成范围为0-最后一个前缀和的值即(0-w[i]所有权重和),则随机生成的值则为目标值;利用二分搜索范围目标值的下标(此处可能没有与之恰好相等匹配的目标值,所以利用左侧二分搜索方法进行匹配)

class Solution {
        private Random random = new Random();
        private int[] preSum;
        private int n;
        public Solution(int[] w) {
            this.n = w.length;
            // 前缀数组,下标0就是原数组w[0]
            preSum = new int[n];
            // 下标0就是原数组w[0]
            preSum[0] = w[0];
            for (int i = 1; i < n; i++) {
                preSum[i] = preSum[i-1] + w[i];
            }
        }
​
        public int pickIndex() {
            // 保证取到[1, preSum[n-1]]的闭区间
            int target = random.nextInt(preSum[n-1]) + 1;
            // right可以从n-1开始,也可以从n开始,对结果的正确性没有影响
            int left = 0, right = n;
            while (left < right) {
                int mid = left + (right - left) / 2;
                // 如果找到了,直接去当前的下标
                if (preSum[mid] == target) {
                    left =mid;
                    break;
                } else if (preSum[mid] > target) {
                    // 向左找,因为当前mid的值大于target,可能是"第一个大于target"的值,所以不能丢弃mid
                    // 如果mid的值不再需要了(最终不会取到现在的mid),那么就可以right=mid-1;
                    right = mid;
                } else {
                    // 向右找,因为当前的mid的值比target小,永远不会取到了。所以left=mid+1;
                    left = mid + 1;
                }
            }
            // left代表的含义:
            // 当目标元素 target 不存在数组 nums 中时,搜索左侧边界的二分搜索的返回值可以做以下几种解读:
            // 1、返回的这个值是 nums 中大于等于 target 的最小元素索引。
            // 2、返回的这个值是 target 应该插入在 nums 中的索引位置。
            // 3、返回的这个值是 nums 中小于 target 的元素个数。
            return left;
        }
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值