首页 > 其他分享 >leetcode 528/ LCR 071 按权重随机选择

leetcode 528/ LCR 071 按权重随机选择

时间:2024-03-11 10:44:49浏览次数:35  
标签:LCR 071 .# pickIndex number 数组 suffixSumArr 下标 528

leetcode 528/ LCR 071 按权重随机选择

528. 按权重随机选择

LCR 071. 按权重随机选择

题目描述

给定一个正整数数组 w ,其中 w[i] 代表下标 i 的权重(下标从 0 开始),请写一个函数 pickIndex ,它可以随机地获取下标 i,选取下标 i 的概率与 w[i] 成正比。

例如,对于 w = [1, 3],挑选下标 0 的概率为 1 / (1 + 3) = 0.25 (即,25%),而选取下标 1 的概率为 3 / (1 + 3) = 0.75(即,75%)。

也就是说,选取下标 i 的概率为 w[i] / sum(w)

示例 1:

输入:
inputs = ["Solution","pickIndex"]
inputs = [[[1]],[]]
输出:
[null,0]
解释:
Solution solution = new Solution([1]);
solution.pickIndex(); // 返回 0,因为数组中只有一个元素,所以唯一的选择是返回下标 0。

示例 2:

输入:
inputs = ["Solution","pickIndex","pickIndex","pickIndex","pickIndex","pickIndex"]
inputs = [[[1,3]],[],[],[],[],[]]
输出:
[null,1,1,1,1,0]
解释:
Solution solution = new Solution([1, 3]);
solution.pickIndex(); // 返回 1,返回下标 1,返回该下标概率为 3/4 。
solution.pickIndex(); // 返回 1
solution.pickIndex(); // 返回 1
solution.pickIndex(); // 返回 1
solution.pickIndex(); // 返回 0,返回下标 0,返回该下标概率为 1/4 。

由于这是一个随机问题,允许多个答案,因此下列输出都可以被认为是正确的:
[null,1,1,1,1,0]
[null,1,1,1,1,1]
[null,1,1,1,0,0]
[null,1,1,1,0,1]
[null,1,0,1,0,0]
......
诸若此类。

提示:

  • 1 <= w.length <= 10000
  • 1 <= w[i] <= 10^5
  • pickIndex 将被调用不超过 10000

解答

第一直觉解答(超时)

根据题目所述:需要随机取下标,但是要保证下标的比例,会很容易想到构建一个按照比例存放的数组,然后随机从中取出下标

例如:
w = [3, 1, 2]时,我构建一个下标数组:indexArr = [0, 0, 0, 1, 2, 2],再随机从indexArr 中随机取下标,就能保证012的比例为w数组所确定的3: 1: 2

代码:

class Solution {
  #indexArr: number[] = [];
  constructor(w: number[]) {
    for (let i = 0; i < w.length; i++) {
      this.#indexArr = this.#indexArr.concat(new Array(w[i]).fill(i));
    }
  }

  pickIndex(): number {
    return this.#indexArr[Math.round(Math.random() * (this.#indexArr.length - 1))];
  }
}

但是此方法在数据量特别大的时候会出现超时,导致无法通过leetcode测试用例:
image

超时的原因在于concatfill方法分别为O(n+m)O(m)的时间复杂度,再在外面套一层遍历wfor循环导致时间复杂度上升到O(n^2),而本题是有O(n)时间复杂度的解法的,所以这里无法通过测试。

前缀和+二分法

这种方法本质上也是想办法按照比例“拉长”下标数组(例如上述例子,将[3, 1, 2]拉长为[0, 0, 0, 1, 2, 2]),此方法是根据前缀和的特点将[3, 1, 2]“视作”为[1, 2, 3, 4, 5, 6],再从1至6中取随机数,当随机数为1或2或3时,返回下标0;当随机数为4时,返回下标1;当随机数为5或6时,返回下标2。这样也能保证取出的随机数比例是3: 1: 2

方法原理:

w = [3, 1, 2]时,构建前缀和数组[3, 4, 6],如果此时我们从1开始,在脑海或者草稿纸上使用虚拟的数字填满1至6,可知比例确实是3: 1: 2
image

代码逻辑

根据上面所述,我们的函数逻辑只需要构建前缀和数组,然后随机取1到前缀和的最后一项的值,然后在前缀和数组中找到刚好大于或等于该随机值的数组元素,然后返回此数组元素对应的下标即可。

class Solution {
  #suffixSumArr: number[];
  constructor(w: number[]) {
    let sum = 0;

    // 构建前缀和数组
    this.#suffixSumArr = w.map((num) => (sum += num));
  }

  pickIndex(): number {
    const randomNum = Math.random() * this.#suffixSumArr.at(-1)! - 1 + 1;

    // 寻找刚好大于randomNum的前缀和数组元素的下标
    let i = 0;
    while (true) {
      if (this.#suffixSumArr[i] >= randomNum) return i;
      i++
    }
  }
}

此时方法还有优化空间,可以采用二分法将“寻找刚好大于随机数的前缀和数组元素的下标”这一步的时间复杂度由O(n)进一步优化到O(logn)

class Solution {
  #suffixSumArr: number[];
  constructor(w: number[]) {
    let sum = 0;

    // 构建前缀和数组
    this.#suffixSumArr = w.map((num) => (sum += num));
  }

  pickIndex(): number {
    const randomNum = Math.random() * this.#suffixSumArr.at(-1)! - 1 + 1;
    let l = 0;
    let r = this.#suffixSumArr.length;

    // 二分法查找刚好大于或等于randomNum大的值的下标
    while (true) {
      const middle = (l + r) >> 1;
      const middleNum = this.#suffixSumArr[middle];
      const middleLeftNum = this.#suffixSumArr[middle - 1] ?? -Infinity;

      if (middleNum < randomNum) {
        // middle下标对应值过小
        l = middle + 1;
        continue;
      } else if (middleLeftNum >= randomNum) {
        // middle下标对应值过大
        r = middle - 1;
        continue;
      }

      return middle;
    }
  }
}

标签:LCR,071,.#,pickIndex,number,数组,suffixSumArr,下标,528
From: https://www.cnblogs.com/CatCatcher/p/18065570

相关文章

  • nrf52832蓝牙开发踩过的坑-京鸿通信科技-15507589165
    转自:http://www.manongjc.com/detail/26-htjapkxksqidwuo.html本文章向大家介绍nrf52832蓝牙开发踩过的坑,主要包括nrf52832蓝牙开发踩过的坑使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。接触nrf52832芯片已经有一段时间了......
  • 【蔚来汽车】蔚来20220713第三题-旅游规划
    【蔚来汽车】蔚来20220713第三题-旅游规划牛牛对n个城市旅游情况进行了规划,已知每个城市有两种属性x和y,其中x表示去第i号城市的花费,y表示在第i号城市游玩后会得到的开心值。  现在牛牛希望从中挑选出一些城市去游玩,但挑选出的城市必须满足任意两个城市之间花费差......
  • 230718B3-path 题解
    感谢cn_ryh大佬的怂恿(否则我真不会动这个题感谢cszhpdx的指导帮助qwq(让我们膜拜一下场切的浩杨哥orz解决这个题让人很有成就感(题意给定一个基环树,边有长度l、限速v、价值w(每单位时间)已知起点s、终点t、最高速度u,求最小花费边数、询问次数$10^5$解法首先学习一下基......
  • 初中英语优秀范文100篇-071Changes in my school-我的学校发生的变化
    PDF格式公众号回复关键字:SHCZFW071记忆树1Whentalkingaboutourschool,weusuallyhavealottosay,includingtheteachers,thestudentsandsoon.翻译当谈论我们的学校时,我们通常有很多话要说,包括老师、学生等等。简化记忆谈论句子结构主语:we谓语:have宾......
  • 一机三芯! 中国服务器“销冠”NF5280G7率先支持
    近日,国际数据公司(IDC)数据显示,2023年前三季度,浪潮信息双路2U服务器夺得中国市场服务器全型号的销售冠军。作为浪潮信息双路2U服务器的旗舰产品NF5280G7,在业界率先以创新的系统架构支持三大处理器平台,包括IntelSapphireRapids/EmeraldRapids、AMDEPYC™及AmpereOne™,实现在AI大模......
  • 基于单片机的篮球计分器系统设计(#0528)
    功能描述1、采用51/52单片机作为主控芯片;2、采用1602液晶显示:两方比分、12分钟倒计时、当前节数、24秒倒计时;3、按键控制:比赛开始/继续/暂停、24s复位、加3分、加2分、加1分;4、每节比赛结束,蜂鸣器提醒;电路设计采用Altium Designer作为电路设计工具。Altium Designer通过把原理......
  • 基于单片机的烘手器仿真设计(#0071)
    功能描述1、采用51单片机作为主控芯片;2、采用1602液晶显示出风温度、设置阈值;3、采用18B20传感器检测出风温度;4、仿真中使用按键按下模拟检测到人体;5、可切换热风模式、常温模式;6、可设置热风模式的温度阈值;7、只有在热风模式下检测有人且温度低于阈值时才会加热;8、有人在则......
  • macOS Sonoma 14 beta 3 (23A5286i) ISO、IPSW、PKG 下载,公共测试版现已推出
    macOSSonoma14beta3(23A5286i)ISO、IPSW、PKG下载,公共测试版现已推出本站下载的macOS软件包,既可以拖拽到Applications(应用程序)下直接安装,也可以制作启动U盘安装,或者在虚拟机中启动安装。另外也支持在Windows和Linux中创建可引导介质。作者主页:sysin.orgmacOSSonom......
  • P4528 题解
    这篇题解并不做任何形式上的理论推导,而是在于引导像我一样的蒟蒻,如何在遇到这样的题时,不会陷入数据结构暴力分别求三种形态的深渊里无法自拔。看到这道题我们的第一想法应该是把三种形态的数量都求出来,如果可以的话,这题马上就秒掉了。那么我们尝试着去求——比较简单的可能是高......
  • KEYSIGHT LCR使用visa通信的几个问题
    C#中使用visa网口与LCR通信1.在Keysight官网上下载IOLibrariessuite并安装,将C:\ProgramFiles\IVIFoundation\VISA\Win64\ktvisa\include\visa32.csC:\ProgramFiles\IVIFoundation\VISA\Win64\agvisa\agbin\visa32.dll拷贝到自己工程中,此dll为非托管,属性设置资......