【算法】洗牌算法

碎碎念:面试的时候,让写这道题,快写完了,面试官告诉我,这是洗牌算法,

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进行随机操作,将得到的数据添加回原数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值