Algorithm Random

记录 Random 的算法实现

“382. Linked List Random Node”

import "math/rand"

type Solution struct {
    root *ListNode
}

func Constructor(head *ListNode) Solution {
    rand.Seed(13)
    return Solution{root: head}
}

func (this *Solution) GetRandom() (ret int) {
    for count, cur := 1, this.root; cur != nil; cur, count = cur.Next, count+1 {
        if rand.Float32() < 1.0/float32(count) {
            ret = cur.Val
        }
    }
    return ret
}

“384. Shuffle an Array”

import "math/rand"

type Solution struct {
    nums []int
    arr []int
}

func Constructor(nums []int) Solution {
    rand.Seed(time.Now().Unix())

    arr := make([]int, len(nums))
    copy(arr, nums)

    return Solution{
        nums: nums,
        arr: arr,
    }
}

func (this *Solution) Reset() []int {
    return this.nums
}

func (this *Solution) Shuffle() []int {
    for i := 0; i < len(this.arr); i++ {
        j := rand.Intn(len(this.arr)-i)
        this.arr[i], this.arr[j] = this.arr[j], this.arr[i]
    }
    return this.arr
}

“398. Random Pick Index”

import "math/rand"

type Solution []int

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

func (this *Solution) Pick(target int) (ret int) {
    for count, i := 0, 0; i < len(*this); i++ {
        if (*this)[i] == target {
            if count++; rand.Float32() < 1.0/float32(count) {
                ret = i
            }
        }
    }
    return ret
}

“470. Implement Rand10() Using Rand7()”

  • 暴力解法,100 次采样时不通过
func rand10() int {
   return (rand7()+rand7()+rand7()+rand7()+rand7()+rand7()+rand7())/7
}
  • 拒绝采样,1000 次采样时不通过
func rand10() int {
    tmp := 12
    for tmp > 11 {
        tmp = rand7()+rand7()
    }
   return tmp-1
}
  • 拒绝采样,通过
func rand10() int {
    idx := 41
    for idx > 40 {
        row, col := rand7(), rand7()
        idx = col+(row-1)*7
    }
    return 1 + (idx-1)%10
}

“478. Generate Random Point in a Circle”

import "math/rand"

type Solution struct {
    radius, x_center, y_center float64
}

func Constructor(radius float64, x_center float64, y_center float64) Solution {
    return Solution{
        radius:radius,
        x_center:x_center,
        y_center:y_center,
    }
}

func (this *Solution) RandPoint() (ret []float64) {
    for {
        x, y := rand.Float64()*2.0*this.radius, rand.Float64()*2.0*this.radius
        if (x-this.radius)*(x-this.radius) + (y-this.radius)*(y-this.radius) <= this.radius * this.radius {
            ret = append(ret, this.x_center+x-this.radius, this.y_center+y-this.radius)
            break
        }
    }
    return ret
}

“497. Random Point in Non-overlapping Rectangles”

import "math/rand"

type Solution struct {
    preSum []int
    rects [][]int
}

func Constructor(rects [][]int) Solution {
    rand.Seed(time.Now().Unix())

    preSum := make([]int, len(rects))
    sum := 0
    for i, rect := range rects {
        sum += (rect[2]-rect[0]+1)*(rect[3]-rect[1]+1)
        preSum[i] = sum
    }
    return Solution{
        preSum: preSum,
        rects: rects,
    }
}

func (this *Solution) Pick() []int {
    tarPoint := rand.Intn(this.preSum[len(this.preSum)-1])
    l, r := -1, len(this.preSum)
    for l + 1 < r {
        mid := (l+r)>>1
        if this.preSum[mid] > tarPoint {
            r = mid
        } else {
            l = mid
        }
    }

    diff := tarPoint
    if l >= 0 {
        diff = tarPoint-this.preSum[l]
    }
    tarRect := this.rects[r]
    xdiff, ydiff := diff%(tarRect[2]-tarRect[0]+1), diff/(tarRect[2]-tarRect[0]+1)

    return []int{xdiff+this.rects[r][0], ydiff+this.rects[r][1]}
}

“528. Random Pick with Weight”

type Solution struct {
    pre []int
}
func Constructor(w []int) Solution {
    rand.Seed(time.Now().UnixNano())
    for i := 1; i < len(w); i++ {
        w[i] += w[i-1]
    }
    return Solution{ w }
}
func (this *Solution) PickIndex() int {
    num := rand.Intn(this.pre[len(this.pre)-1])+1
    return sort.SearchInts(this.pre, num)
}

“837. New 21 Game” probability + dp

double new21Game(int N, int K, int W) {
    if (K == 0) return 1.0;
    vector<double> dp(N + 1);
    dp[0] = 1.0;
    double wsum = 1.0;
    for (int i = 1; i <= N; ++i) {
        dp[i] = wsum/W;
        if (i < K)
            wsum += dp[i];
        if (i >= W && i - W < K)
            wsum -= dp[i - W];
    }
    double res = 0.0;
    for (int i = K; i <= N; ++i)
        res += dp[i];
    return res;
}