碎碎念:面试的时候,让写这道题,快写完了,面试官告诉我,这是洗牌算法,
1 介绍
洗牌算法是将原来的数组进行打散,使原数组的某个数在打散后的数组中的每个位置上等概率的出现,刚好可以解决该问题。
2 洗牌算法
力扣链接:力扣
Knuth算法
从后往前尝试填充,通过随机当前下标与(剩余的)哪个下标进行值交换来实现。对于下标 x而言,从[0,x - 1] 中随机出一个位置与 x 进行值交换,当所有位置都进行这样的处理后,便得到了一个公平的洗牌方案。(也可以从前往后遍历)
class Solution {
public:
vector<int> m_nums; // 当前状态
vector<int> m_orig; // 保存原状态
// 初始化
Solution(vector<int>& nums) {
this->m_nums = nums;
this->m_orig = nums;
}
// 重设数组到它的初始状态并返回
vector<int> reset() {
this->m_nums = m_orig;
return this->m_orig;
}
// 返回数组随机打乱后的结果
vector<int> shuffle() {
for (int i = this->m_nums.size() - 1; i >= 0; i--) {
// 获得随机下标,范围在[0,i]
int index = random() % (i + 1);
// 交换
swap(this->m_nums[index], this->m_nums[i]);
}
return this->m_nums;
}
};
/**
* Your Solution object will be instantiated and called as such:
* Solution* obj = new Solution(nums);
* vector<int> param_1 = obj->reset();
* vector<int> param_2 = obj->shuffle();
*/
从前往后交换
class Solution {
public:
vector<int> m_nums; // 当前状态
vector<int> m_orig; // 保存原状态
// 初始化
Solution(vector<int>& nums) {
this->m_nums = nums;
this->m_orig = nums;
}
// 重设数组到它的初始状态并返回
vector<int> reset() {
this->m_nums = m_orig;
return this->m_orig;
}
// 返回数组随机打乱后的结果
vector<int> shuffle() {
for (int i = 0; i < this->m_nums.size(); i++) {
// 获得随机下标,范围在[0,i+1]
int index = random() % (i + 1);
// 交换
swap(this->m_nums[index], this->m_nums[i]);
}
return this->m_nums;
}
};
/**
* Your Solution object will be instantiated and called as such:
* Solution* obj = new Solution(nums);
* vector<int> param_1 = obj->reset();
* vector<int> param_2 = obj->shuffle();
*/
时间复杂度:O(n)
空间复杂度:O(n)
面试题
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// 交换函数
void swap(unsigned int* arr, unsigned int i, unsigned int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
void random_song(unsigned int *song_list, unsigned int list_len)
{
srand((unsigned)time(NULL)); // 随机数种子
for (int i = list_len - 1; i >= 0; i--) {
// 得到随机下标[0, i]
int index = rand() % (i + 1);
// 交换
swap(song_list, index, i);
}
}
int main()
{
unsigned int i;
unsigned int song_list[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
unsigned int list_len = sizeof(song_list) / sizeof(int);
random_song(song_list, list_len);
for (i = 0; i < list_len; i++)
printf("%d, ", song_list[i]);
system("pause");
return 0;
}
运行结果,每次的值都是随机的。
总结:现在再来看具体代码,其实并不是很难, 但是这个思路当时是没想到的,我还想着再申请一块空间temp将原数据存起来,然后对temp进行随机操作,将得到的数据添加回原数据。