leetcode382. Linked List Random Node

題目要求

Given a singly linked list, return a random node's value from the linked list. Each node must have the same probability of being chosen.

Follow up:
What if the linked list is extremely large and its length is unknown to you? Could you solve this efficiently without using extra space?

Example:

// Init a singly linked list [1,2,3].
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
Solution solution = new Solution(head);

// getRandom() should return either 1, 2, or 3 randomly. Each element should have equal probability of returning.
solution.getRandom();

要求從單鏈表中,隨機返回一個節點的值,要求每一個節點被選中的機率是相等的。java

思路和代碼

在等機率隨機選擇算法中,最經典的算法就是蓄水池算法。能夠參考同類型題目398 random pick index。這裏再次整理一下蓄水池算法的思路和簡單證實。node

假如一共有N個物品,須要從其中挑選出K個物品,要求確保N個物品中每一個物品都可以被等機率選中。對於這種等機率問題,簡答的作法是經過隨機數獲取選中物品的下標。可是蓄水池算法容許咱們從數據流的角度來隨機得到K個物品,即在並不知道整體的樣本數有多少的狀況下,隨機抽取K個物品。算法

蓄水池算法的思路以下:segmentfault

  1. 選中前K個物品放入蓄水池
  2. 對於第K+1個物品,其被選中並替換蓄水池中任意一個物品的機率爲K/(K+1)
  3. 對於第K+i個物品,其被選中並替換蓄水池中任意一個物品的機率爲K/(K+i)
  4. 重複這個步驟直到K+i=N

對於這個算法,咱們能夠採用概括法進行簡單證實。已知對於前K個物品,每一個物品的被選中的機率爲1,知足了K/K=1的機率。
對於K+i-1個物品,假設每一個物品被選中的機率爲K/(K+i-1)。證實對於前K+i個物品,每一個物品被放入蓄水池中的機率爲K/(K+i)dom

  1. 對於第K+i個物品,其被選中並替換蓄水池中任意一個物品的機率爲K/(K+i)
  2. 對於以前在蓄水池中的物品,其仍在蓄水池中的機率爲以前被選中在蓄水池中機率乘以這一次未被換出蓄水池的機率,即P = P(上一輪在蓄水池中) * P(這一輪沒有被替換掉)。對此進行計算,P(上一輪在蓄水池中) * P(這一輪沒有被替換掉) = P(上一輪在蓄水池中) * (1-P(這一輪被替換掉)) = (K / (K+i-1)) * (1 - (P * 1/K)),算出P = K/(K+i)
  3. 證實對於前K+i個物品,每一個物品被放入蓄水池中的機率爲K/(K+i),當K+i等於N時,每一個物品被選中的機率爲K/N

在本題中,使用蓄水池算法的N爲單鏈表的長度,K爲1。this

代碼以下:spa

private ListNode head;
    private Random r;
    /** @param head The linked list's head.
    Note that the head is guaranteed to be not null, so it contains at least one node. */
    public Solution(ListNode head) {
        this.head = head;
        this.r = new Random();
    }

    /** Returns a random node's value. */
    public int getRandom() {
        ListNode tmp = this.head;
        int result = 0;
        int index = 1;
        do{
            if(r.nextInt(index) == 0) {
                result = tmp.val;
            }
            tmp = tmp.next;
            index++;
        }while(tmp != null);
        return result;
    }
相關文章
相關標籤/搜索