从n个对象中随机取出m个

很多类似的这种问题,都有两种方案,一种以时间换空间,一种以空间换时间。

 对于方法一:这里可以计算一下其每次循环的概率是否都相同,

假设i=0,随机到元素的概率为m/n;

假设i=1,随机到元素的概率为m/n*((m-1)/(n-1))+(1-m/n)*(m/(n-1))=m/n(分别假设i=0时没有随机到和有随机到)

...

所以每次循环所随机到元素的概率都相同。

//此方法摘录于其他网站,是一种省空间省时间的方案。注意,这里返回数值是坐标,即n=3,m=1,则返回值为0~2的一个数
	public static Integer[] way1(int n, int m) {
		Integer[] output = new Integer[m];
		for (int i = 0; i < n; i++) {
			// if (m > 0 && new Random().nextInt(n - i) % (n - i) < m) {//这个也可以
			if (m > 0 && random(1, n-i) % (n - i) < m) {
				int index = output.length - m;
				output[index] = i;
				m--;
			}
		}
		return output;
	}

	public static List<String> way1(List<String> names, int m) {
		List<String> output = new ArrayList<>(m);
		int n = names.size();
		for (int i = 0; i < n; i++) {
			if (m > 0 && random(1, n - i) % (n - i) < m) {
				output.add(names.get(i));
				m--;
			}
		}
		return output;
	}

	public static final int random(int begin, int end) {
		if (begin > end) {
			throw new RuntimeException("随机开始值大于结束值");
		}

		if (begin == end) {
			return begin;
		}

		int dec = begin - 0;
		Random r = new Random();
		// nextInt(n)随机的结果为0~n-1,所以加1效果是end这个值也可以随机到
		int random = r.nextInt(end - dec + 1);// 保证开始值为0,且结束值>0,即begin-dec=0
		return random + dec;
	}

	//线程安全的随机类
	public static final int random2(int begin, int end){
		if (begin > end) {
			throw new RuntimeException("随机开始值大于结束值");
		}

		if (begin == end) {
			return begin;
		}
		return ThreadLocalRandom.current().nextInt(begin, end+1);
	}

	// 此方法以空间换时间,只需循环n次即可
	public static int[] way2(int n, int m){
		int[] sequence = new int[n];
        int[] output = new int[m];
        Random r = new Random();
        for (int i = 0; i < n; i++)
        {
            sequence[i] = i;
        }

        int end = n - 1;
        for (int i = 0; i < m; i++)
        {
            int num = r.nextInt(n);
            output[i] = sequence[num];
            sequence[num] = sequence[end];
            end--;
        }
        return output;
	}

 

另外,摘录了几个算法题,总觉得答案需要仔细琢磨一下,仅供参考:

题目2

假设你参加了一个游戏节目,现在要从三个密封的箱子中选择一个。其中两个箱子是空的,另一个箱子里面有大奖。你并不知道奖在哪一个箱子里,但主持人知道。游戏节目的主持人先要你选择一个箱子,接着他把你没有选的空箱子打开,以证明它是空的。最后主持人给你换箱子的机会,你可以把你所选择的箱子换成另一个没有打开的箱子。此时你该不该换箱子?

扫描二维码关注公众号,回复: 490653 查看本文章

分析:

要相信直觉。你当然应该换箱子!我们把三个箱子编号A,B,C,并假设你选的是A箱。显然奖品在A里的概率是1/3,在B或C里的概率是2/3。B和C可能有一个是空的,也可能两个都是空的。因此,当你选择了A箱后,主持人很可能会打开B箱或C箱,以显示里面是空的。在这种情况下,主持人的举动并不会影响奖品在A箱里面的机会。我们假设主持人打开了B箱,以告诉你它是空的。现在A箱有奖品的概率还是1/3,B箱里面有奖品的概率是0,因此C箱里面有奖品的概率是2/3。在这种情况下,你应该换到C箱,因为它使你赢的机会提高了1倍!

题目3

有一对夫妇,先后生了两个孩子,其中一个孩子是女孩,问另一个孩子是男孩的概率是多大?

答案是2/3.两个孩子的性别有以下四种可能:(男男)(男女)(女男)(女女),其中一个是女孩,就排除了(男男),还剩三种情况。其中另一个是男孩的占了两种,2/3. 之所以答案不是1/2是因为女孩到底是第一个生的还是第二个生的是不确定的。

猜你喜欢

转载自1181731633.iteye.com/blog/2367156
今日推荐