题目

该题是中文网站的 LeetCode 的 1227题,题目如下:

思路

自己想的情况还是有欠缺的地方,最后是看题解后总结出来的,记录一下。

思路1:

假设第一位没票的客人先上飞机,整体分3种情况:

  • 1.第一位客人选的是他本来应该座的位置,其他人都有票,对号入座即可。
    第 n 位乘客坐在自己的座位上的概率是: 1 / n * 1。

  • 2.第一位客人选的是第n位客人的位置,这样第n位客人无论无何都座不到自己本来的位置。
    第 n 位乘客坐在自己的座位上的概率是: 1 / n * 0。

  • 3 第一位客人即没选本来应该的位置,也没选第n位客人应该座的位置。那这种情况下 第2位到第n-1位客人肯定有1个人的位置是被第1位客人座了,设这个人是第i位客人。
    那这时第i位客人的选择也会影响到第n位客人是否能做到自己本来的位置,情况也是以上分析的3种情况。
    我们可以这样想:
    把第i位客人当着这轮的“第1位客人”来看待,整个座位的个数是n-1个。也就是把问题的范围缩小了,由原来的n个人,缩小到现在的n-1人。
    先暂且假设知道这时候 “第 i 位乘客坐在自己的座位上的概率” 是dp[n-1]。
    所以: 这第3种情况下:第 n 位乘客坐在自己的座位上的概率是: (n-2) / n * dp[n-1]

    所以,最后总的概率就是把以上3种情况的概率加起来即可。

思路2:
  • 一:先看大于 2 个客人时的情况:
    因为题目没有说 n 个客人是以什么要的顺序来上飞机选座位的。
    我们就先让 第 2 位 到 第 n-1 位的客人上飞机,因为他们都是有票的,100% 会做到自己的位置。
    那么就只剩下了 第 1 位 、 第 n 位客人了,就是简化到了只有2个客人的情况,概率是 0.5
  • 二:再看只有 1 个人的情况,概率是 1
  • 三:最后,直接用代码判断返回即可。

代码

    public double nthPersonGetsNthSeat(int n) {
   
        // dp 矩阵,不用下标为 0 的位置 。
        // dp[i] : 代表总共由 i 个客人时,第 i 位乘客坐在自己的座位上的概率为 dp[i] 。
        double[] dp = new double[n + 1];
        dp[1] = 1;      // 最基本的情况。

        for (int i = 2; i < dp.length; i++) {
   
            // 第 1 种情况 + 第 3 种情况的概率。 第 2 种情况的概率为 0
            dp[i] = 1.0 / i + (double) (i - 2) / i * dp[i - 1];
        }

        // 直接返回总共 n 个人时的情况下的概率。
        return dp[n];
    }