水塘抽样随机取 1 个元素,哈希表:求解《398. 随机数索引》

2022-04-25 02:38:46

水塘抽样随机取 1 个元素,哈希表,2 解法求解《398. 随机数索引》

水塘抽样随机取 1 个元素的证明公式

水塘抽样

选 1 个元素,证明如上图

[0, n) 选 目标元素,统计目标元素出现次数 j

代码模板 · 水塘抽样

选 1 个元素

function reservoirSampling = target => {
  const n = nums.length
  let  j = ans = 0
  for (let i = 0; i < n; i++) {
     if (nums[i] === target) {
        j++
        if (Math.random() * j | 0 === 0) ans = i
     }
  }
  return ans
}

例题

398. 随机数索引

给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引。 您可以假设给定的数字一定存在于数组中。 注意: 数组大小可能非常大。 使用太多额外空间的解决方案将不会通过测试。

答案

哈希表 · 哈希映射

var Solution = function(nums) {
  this.h = new Map
  for (let i = 0; i < nums.length; i++) {
    if (!this.h.has(nums[i])) this.h.set(nums[i], [i])
    else this.h.get(nums[i]).push(i)
  }
};

Solution.prototype.pick = function(target) {
  const nums = this.h.get(target)
  return nums[Math.random() * nums.length | 0]
}; 
type Solution struct {
  h map[int][]int
}

func Constructor(nums []int) Solution {
  h := map[int][]int{}
  for i, v := range nums {
    h[v] = append(h[v], i)
  }
  return Solution{h:h}
}

func (this *Solution) Pick(target int) int {
  indices := this.h[target]
  return indices[rand.Intn(len(indices))]
}
class Solution {
    protected $h;
    function __construct($nums) {
      foreach ($nums as $i => $v) {
        $this->h[$v] []= $i;
      }
    }

    function pick($target) {
      shuffle($this->h[$target]);
      return $this->h[$target][0];
    }
}

水塘抽样

var Solution = function(nums) {
  this.nums = nums
};

Solution.prototype.pick = function(target) {
  const n = this.nums.length
  let ans = 0
  for (let i = 0, j = 0; i < n; i++) {
    if (this.nums[i] === target) {
      j++
      if ((Math.random() * j | 0) === 0) {
        ans = i
      }
    }
  }
  return ans
}; 
type Solution struct {
  nums []int
}

func Constructor(nums []int) Solution {
  return Solution{nums:nums}
}

func (this *Solution) Pick(target int) int {
  j, ans := 0, 0
  for i, v := range this.nums {
    if v == target {
      j++
      if rand.Intn(j) == 0 {
        ans = i
      }
    }
  }
  return ans
}
class Solution {
    protected $nums;

    function __construct($nums) {
      $this->nums = $nums;
    }

    function pick($target) {
      $j = 0;
      $ans = 0;
      foreach($this->nums as $i => $v) {
        if ($v === $target) {
          $j++;
          if (rand(0, $j - 1) === 0) {
            $ans = $i;
          }
        }
      }
      return $ans;
    }
}

快速排序(快速选择)优化:双指针、打乱数组、随机基准元素(随机数、中间数、中位数)、三路划分三指针:求解《462. 最少移动次数使数组元素相等 II》
快速排序(快速选择)的优化:双指针、打乱数组(Fisher–Yates shuffle 洗牌算法)、随机基准元素(随机数、中间数、中位数)、三路划分(三切分 / 三指针 / 三分查找)。求解《462. 最少移动次数使数组元素相等 II》。
排序、最小值,基于排序获取中位数:求解《1887. 使数组元素相等的减少操作次数》《453. 最小操作次数使数组元素相等》和《462. 最少移动次数使数组元素相等 II》
排序、最小值,基于排序获取中位数,求解《1887. 使数组元素相等的减少操作次数》《453. 最小操作次数使数组元素相等》和《462. 最少移动次数使数组元素相等 II》
5 种方法交换变量,用绝对值和求模标记,用位图、掩码、哈希集合、哈希映射、正则、排序和暴力法:求解《442. 数组中重复的数据》
利用 5 种方法交换变量,用绝对值和求模标记,用位图、掩码、哈希集合、哈希映射、正则、排序和暴力法求解《442. 数组中重复的数据》