这道是个概率题:
题目:
给你一组整数链表,链表长度不定,让你随机取里面的 N 个数据,链表长度大于 N,保证 N 个数被从链表中等概率获得,不能计算链表长度并且只能遍历链表一次 |
这题我一开始也没有思路,经过面试官的提醒,说可以用置换的方法来解,于是解答出了解法:把链表前 N 个数先放进数组,然后取每 N + 1 个数,然后取一个 N + 1 的随机数,如果小于 N,则在取出的 N 个数中换出去第(N + 1) % N个数。这样一个一个按此算法一直到链表结束。
实际我最后一步取模的方法不对,应该是随机换出去一个。
下面算算随机换出去是否是等概率的。选出的前N个数被选中概率都为 N,第 N + 1 个数被选中的概率是 N / (N + 1),它把前面 N 个数换出去一个,每个数被换出去的概率是 1 / N,那么,前 N 个数留下的概率就为 1 - (1 / N) * (N / (N + 1)) = N / (N + 1),然后取第 N + 2 个数,照此方法进行替换,直到链表最后一个数。具体概率我就不算了,肯定是想等的。
下面把代码贴出来,BASE类只是个日志类,可以在前面的博客中找到,这里就不贴了:
import java.util.Arrays; import java.util.LinkedList; import java.util.Random;
/** * * 给你一个组整数,数据长度不定,让你随机取里面的数据,保证等概率,不能计算数据长度并且只能遍历链表一次 *
* * @author chouy */ public class EquiprobableGetNumber extends Base { public static void main(String[] args) { int NUMBERCOUNT = 10; Random random = new Random(); int max = random.nextInt(50); info("length: " + max); LinkedList<Integer> list = new LinkedList<Integer>(); for (int i = 1; i < max; i++) list.add(i); info("init: " + list.toString()); int[] result = new EquiprobableGetNumber().calc(list, NUMBERCOUNT); info("result: " + Arrays.toString(result)); }
public int[] calc(LinkedList<Integer> array, int resultLength) { Random random = new Random(); int[] result = new int[resultLength]; int i = 0; for (; i < resultLength && !array.isEmpty(); i++) result[i] = array.remove(); while(!array.isEmpty()) { int tmp = array.remove(); int rdmInt = random.nextInt(i++); if (rdmInt < resultLength) { result[random.nextInt(resultLength)] = tmp; } } return result; } }
|
我的算法有错误或有其它的算法,请和我交流。
阅读(1398) | 评论(0) | 转发(0) |