leetcode384打乱数组

leetcode 384 Shuffle an Array

Posted by BY on July 2, 2020

前言

持续更新了

正文

问题来源

本问题来自leetcode上的384题。

问题描述

打乱一个没有重复元素的数组。

示例 1:

// 以数字集合 1, 2 和 3 初始化数组。
int[] nums = {1,2,3};
Solution solution = new Solution(nums);

// 打乱数组 [1,2,3] 并返回结果。任何 [1,2,3]的排列返回的概率应该相同。
solution.shuffle();

// 重设数组到它的初始状态[1,2,3]。
solution.reset();

// 随机返回数组[1,2,3]打乱后的结果。
solution.shuffle();

分析:

shuffle这个算法我是知道的,然后我写完提交发现出错了,目前还不知道为何出错

type Solution struct {
    reset []int
}

func Constructor(nums []int) Solution {
    reset := make([]int, len(nums))
    copy(reset, nums)
    return Solution{reset}
}

/** Resets the array to its original configuration and return it. */
func (this *Solution) Reset() []int {
    s := make([]int, len(this.reset))
    copy(s, this.reset)
    return s
}

/** Returns a random shuffling of the array. */
func (this *Solution) Shuffle() []int {
    rand.Seed(time.Now().Unix())
    s := make([]int, len(this.reset))
    copy(s, this.reset)
    for i := len(s)-1; i >= 0; i-- {
        index := rand.Intn(i+1)
        s[i], s[index] = s[index], s[i]
    }
    return s
}

同样的算法我用c++提交就对了,我也不知道是出现了什么问题

class Solution {
public:
    Solution(vector<int> nums): v(nums) {}
    
    /** Resets the array to its original configuration and return it. */
    vector<int> reset() {
        return v;
    }
    
    /** Returns a random shuffling of the array. */
    vector<int> shuffle() {
        vector<int> res = v;
        for (int i = res.size()-1; i >= 0; --i) {
            int t = rand() % (i+1);
            swap(res[i], res[t]);
        }
        return res;
    }
    
private:
    vector<int> v;
};

然后我改成直接调用rand.Shuffle函数就能够通过

// 其他部分没有改动,只改了这个函数
func (this *Solution) Shuffle() []int {
    a := make([]int, len(this.reset))
    copy(a, this.reset)
    rand.Seed(time.Now().UnixNano())
    rand.Shuffle(len(a), func(i, j int) { a[i], a[j] = a[j], a[i] })
    return a
}

然后看看源码

func (r *Rand) Shuffle(n int, swap func(i, j int)) {
    if n < 0 {
        panic("invalid argument to Shuffle")
    }

    // Fisher-Yates shuffle: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
    // Shuffle really ought not be called with n that doesn't fit in 32 bits.
    // Not only will it take a very long time, but with 2³¹! possible permutations,
    // there's no way that any PRNG can have a big enough internal state to
    // generate even a minuscule percentage of the possible permutations.
    // Nevertheless, the right API signature accepts an int n, so handle it as best we can.
    i := n - 1
    for ; i > 1<<31-1-1; i-- {
        j := int(r.Int63n(int64(i + 1)))
        swap(i, j)
    }
    for ; i > 0; i-- {
        j := int(r.int31n(int32(i + 1)))
        swap(i, j)
    }
}

然后我测试了一下rand.Intn()的随机性

for j := 0; j < 100; j++ {
    rand.Seed(time.Now().Unix()) // 这句话放在最外层和这里效果不一样
    for i := 2; i >= 0; i-- {
        fmt.Print(rand.Intn(i+1))           
    }
    fmt.Println()
}

随机数种子在最外面时,能够保证随机性,而放在里面不能保证随机性。可是回到使用rand.Shuffle()函数又能保证随机性,得细看int31n函数实现。
然后把代码修改一下将随机数种子放在构造时初始化,则能够成功通过。

总结:

勤思考。

结语

不管怎么样好好加油。