文心一言 VS 讯飞星火 VS chatgpt (33)-- 算法导论5.2 5题

Posted 福大大架构师每日一题

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文心一言 VS 讯飞星火 VS chatgpt (33)-- 算法导论5.2 5题相关的知识,希望对你有一定的参考价值。

五、设A[1..n]是由n个不同数构成的数列。如果i<j且A[i]>A[j],则称(i,j)对为A的一个逆序对(inversion)。(参看思考题2-4 中更多关于逆序对的例子。)假设A的元素构成(1,2,… ,n)上的一个均匀随机排列。请用指示器随机变量来计算其中逆序对的数目期望。

文心一言:

假设A的元素构成(1, 2, ..., n)上的一个均匀随机排列,我们可以使用指示器随机变量来计算其中逆序对的数目期望。

首先,我们定义一个指示器随机变量X(i, j),表示A[i]和A[j]是否构成一个逆序对。如果A[i] > A[j],则X(i, j) = 1,否则X(i, j) = 0。

根据题目描述,A的元素构成(1, 2, ..., n)上的一个均匀随机排列,因此A[i]和A[j]是否构成逆序对的概率是相等的,即P(X(i, j) = 1) = P(X(i, j) = 0) = 1/2。

根据期望的定义,逆序对的数目期望E[X(i, j)]为:

E[X(i, j)] = P(X(i, j) = 1) × 1 + P(X(i, j) = 0) × 0 = 1/2

因此,逆序对的数目期望为:

E[X] = E[X(1, 2)] + E[X(1, 3)] + ... + E[X(1, n)] + E[X(2, 3)] + ... + E[X(n-1, n)]

= (1/2) × (n-1) + (1/2) × (n-2) + ... + (1/2) × 1 + (1/2) × 0

= (1/2) × ((n-1) + (n-2) + ... + 1)

= (1/2) × (n-1)! / 2

= (n-1)! / 4

因此,在均匀随机排列下,逆序对的数目期望为(n-1)! / 4。

讯飞星火:

本题考查了离散型随机变量的期望,属于基础题.
根据题意,得到$X\\sim B(n,\\dfrac1n)$,即可求出结果.
解:设X为逆序对的数目,则$X=0$,1,2,$\\ldots$,n,且$X\\sim B(n,\\dfrac1n)$.
所以$E(X)=np=1$.

华为盘古:

360智脑:

首先计算所有可能的长度为2的子序列的数量,即对于长度为k的子序列B,它必然包含两个元素a和b,满足a < b,且a与b之间没有其他元素。因此可以构造如下情况:

  1. B = a -> 情况总数为 C(n-1, k-1),因为当a出现在其他位置时,剩下的元素只有k-1个可以选择。

  2. B = b -> 情况总数为 C(n-1, k-1)

  3. B = a, b ≠ a -> 情况总数为 C(n-1, k-2)

总共的可能情况数为C(n-1, n-1)=n!/[(n-1)!*(n-1)]=(n-1)^2

然后考虑长度大于等于3的子序列的情况。由于每个长度为2的子序列都包含了至少一个逆序对,因此可以考虑所有可能的逆序对,而不考虑它们的相对顺序。所以逆序对的数量期望值就等于总逆序对数量的期望乘以逆序对数量除以所有子序列数量的期望。

对于长度大于等于3的子序列B,必然包含三个或更多的元素。因此,当B=ABABC时,只需要将B中的元素按照大小排序即可得到所有长度为3或更长的子序列。也就是说,任意长度大于等于3的子序列B都可以表示成ABABC的形式。因此,可以将所有的长度大于等于3的子序列视为一种特殊类型的逆序对,即将AB和AC作为一对,那么总共有n(n-1)(n-2)/6种组合方式。

最后,将所有可能的逆序对的数量相加即可得到逆序对数量的期望值。

chatglm:

设$X_i$表示第$i$个元素在随机排列中出现的顺序,$Y_i$表示第$i$个元素与第$i$个元素之前的元素构成的逆序对数目。则题目中的要求可以表示为:

期望 [#逆序对] = 期望 [#逆序对,1] + ... + 期望 [#逆序对,n]

其中,期望 [#逆序对,i] 表示第$i$个元素之前的元素构成的逆序对数目的期望。

由于每个逆序对都包含两个元素,因此逆序对的数目的期望可以表示为:

E(X_i) = 2E(Y_i)

其中,$E(X_i)$表示第$i$个元素在随机排列中出现的顺序的期望,$E(Y_i)$表示第$i$个元素与第$i$个元素之前的元素构成的逆序对数目的期望。

为了计算$E(Y_i)$,我们可以使用马尔可夫定理,设$Z_i$表示第$i$个元素与第$i$个元素之前的元素构成的逆序对数目,$P(Z_i=k)$表示第$i$个元素之前有$k$个逆序对的概率。则:

E(Y_i) = Σ[k=1]P(Z_i=k)E(Y_i|Z_i=k)

其中,Σ[k=1] 表示对所有可能的$k$求和,E(Y_i|Z_i=k) 表示第$i$个元素与第$i$个元素之前的元素构成的逆序对数目的期望,根据指示器随机变量的性质,它等于$Z_i$的取值为$k$时的期望。

由于每个逆序对都包含两个元素,因此$Z_i$的取值只可能是$1$或$2$。对于$Z_i=1$,$E(Y_i|Z_i=1)$等于$2E(Y_i|Z_i=2)$的一半,因为对于每个逆序对,至少有一个是在$Z_i=1$的情况下出现的。因此:

E(Y_i) = Σ[k=2]P(Z_i=k)E(Y_i|Z_i=k)

代入马尔可夫定理的公式,可以得到:

E(Y_i) = Σ[k=2]P(Z_i=k)Σ[i=1]^n-kP(X_i=i)E(X_i|X_i=i)

其中,Σ[i=1]^n-kP(X_i=i) 表示第$i$个元素之前有$k$个逆序对,而其他$n-k$个元素没有逆序对的概率。由于每个元素都可能出现逆序对,因此这个概率等于$P(X_i=i)kP(X_i=i)$。

对于$Z_i=2$,$E(Y_i|Z_i=2)$等于$1$时的期望,即$E(Y_i|Z_i=2) = E(Y_i|Z_i=1)$。因此:

E(Y_i) = Σ[k=2]P(Z_i=k)Σ[i=1]^n-kP(X_i=i)E(X_i|X_i=i)

其中,Σ[i=1]^n-kP(X_i=i) 表示第$i$个元素之前有$k$个逆序对,而其他$n-k$个元素没有逆序对的概率。由于每个元素都可能出现逆序对,因此这个概率等于$P(X_i=i)kP(X_i=i)$。

代入$P(X_i=i)$的表达式,可以得到:

E(Y_i) = 2Σ[k=2]P(Z_i=k)Σ[i=1]n-kP(X_i=i)Σ[j=1]P(Z_j=i)

其中,Σ[j=1]^n-iP(Z_j=i) 表示第$j$个元素之前没有逆序对,而第$i$个元素之前有$i-j

chatgpt:

我们可以定义一个指示器随机变量Xi,j,如果(i,j)是A中的一个逆序对,则该指示器取值为1,否则为0。则逆序对的数目可以表示为:

S = ΣXi,j,其中(i,j)为A中的逆序对。

根据期望的线性性质,E(Xi,j)即为Xi,j取1的概率,则:

E(S) = E(ΣXi,j) = ΣE(Xi,j)

现在我们计算E(Xi,j)。

对于任何一对i和j,由于A中所有的排列都是等可能的,因此i和j构成逆序对的概率为1/2,即:

P((i,j)为逆序对) = P(A[i] > A[j]) = 1/2

因此,

E(Xi,j) = P((i, j)为逆序对) = 1/2

于是逆序对的数目期望为:

E(S) = ΣE(Xi,j) = Σ1/2 = n(n-1)/4

因此,期望逆序对的数量是n(n-1)/4。

文心一言 VS 讯飞星火 VS chatgpt (18)-- 算法导论4.1 5题

五、使用如下思想为最大子数组问题设计一个非递归的、线性时间的算法。从数组的左边界开始,由左至右处理,记录到目前为止已经处理过的最大子数组。若已知 A[1..j]门的最大子数组,基于如下性质将解扩展为 A[1..j+1]的最大子数组:A[1..j+1]的最大子数组要么是A[1..j]的最大子数组,要么是某个子数组 Ai..j+1。在已知A[1..j]的最大子数组的情况下,可以在线性时间内找出形如 A[i..j+1]的最大子数组。

文心一言:

最大子数组问题是一种经典的算法问题,可以使用非递归的方法来解决。具体来说,我们可以使用一个队列来存储当前已经处理过的最大子数组,并且维护一个变量 max_len 来记录当前最大子数组的长度。同时,我们可以遍历整个数组,记录当前已经处理过的最大子数组的长度,并且在遍历的过程中更新 max_len。

具体来说,我们可以使用一个变量 cur_len 来记录当前已经处理过的最大子数组的长度,每当遍历到一个新的子数组时,我们可以将其长度加入到 cur_len 中,并且更新 max_len。同时,我们可以使用一个变量 cur_start 来记录当前已经处理过的最大子数组的起始位置,每当遍历到一个新的子数组时,我们可以将其起始位置加入到 cur_start 中,并且更新 cur_len。

最后,我们可以返回 cur_start,它是 max_len。这个值就是最大子数组中起始位置最右边的元素的下标,我们可以用它来解决最大子数组问题。

下面是一个使用 Python 实现的非递归的最大子数组问题的算法:

def maxSubArray(nums):  
    max_len = 0  
    cur_start = 0  
    cur_len = 0  
    queue = []  
    for i in range(len(nums)):  
        if cur_len == max_len:  
            return -1  
        if nums[i] > nums[cur_start]:  
            cur_len += nums[i] - nums[cur_start]  
            cur_start = i  
        if i > cur_start:  
            cur_len -= nums[i - cur_start]  
            cur_start = i  
        queue.append(cur_start)  
        cur_start += nums[i]  
    if cur_len == max_len:  
        return -1  
    return queue

这个算法的时间复杂度为 O(n),其中 n 是数组 nums 的长度。


讯飞星火:

算法步骤:

1.初始化最大子数组为整个数组的第一个元素。

2.从左至右遍历数组,每次比较当前元素与最大子数组的末尾元素的大小关系,如果当前元素大于最大子数组的末尾元素,则将最大子数组的末尾元素更新为当前元素。

3.如果遍历到数组的末尾,仍然没有找到比最大子数组更大的末尾元素,则最大子数组就是整个数组。

4.如果遍历到某个位置i时,发现A[i]大于等于最大子数组的末尾元素,并且A[i+1]也大于等于最大子数组的末尾元素,则可以将最大子数组扩展到A[i]..A[j+1],其中j+1即为扩展后的最大子数组的长度。

5.如果遍历完数组后仍未找到可以扩展的最大子数组,则返回最大子数组。

时间复杂度为O(n),空间复杂度为O(1)。

chatgpt:

基于上述性质,可以设计一个非递归的、线性时间的算法来解决最大子数组问题。算法的主要思路如下:

  1. 首先初始化两个变量:max_so_far和max_ending_here。它们都初始化为第一个元素。

  2. 然后从第二个元素开始遍历整个数组。对于每个元素,更新max_ending_here = max(A[i], max_ending_here + A[i]),表示包含A[i]的最大子数组。同时更新max_so_far,表示到目前位置的最大子数组。

  3. 如果max_ending_here小于0,则说明当前处理的子数组已经不是最大子数组中的一部分了,需要从下一个元素重新开始计算新的子数组。

  4. 在遍历过程中,记录下max_so_far,即可得到整个数组的最大子数组。

该算法的时间复杂度为O(n),其中n为数组的长度,因为只需要一次遍历数组即可找到最大子数组。而空间复杂度为O(1),因为只需要常数级别的额外空间来存储变量。下面是该算法的Go语言实现示例:

func maxSubArray(nums []int) int 
    if len(nums) == 0 
        return 0
    

    maxSoFar := nums[0]
    maxEndingHere := nums[0]

    for i := 1; i < len(nums); i++ 
        maxEndingHere = max(nums[i], maxEndingHere+nums[i])
        maxSoFar = max(maxSoFar, maxEndingHere)
    

    return maxSoFar


func max(a, b int) int 
    if a > b 
        return a
    
    return b

其中max函数用来比较两个数的大小,返回较大的那个数。

以上是关于文心一言 VS 讯飞星火 VS chatgpt (33)-- 算法导论5.2 5题的主要内容,如果未能解决你的问题,请参考以下文章

文心一言 VS 讯飞星火 VS chatgpt (28)-- 算法导论5.1 3题

文心一言 VS 讯飞星火 VS chatgpt (25)-- 算法导论4.2 7题

文心一言 VS 讯飞星火 VS chatgpt (18)-- 算法导论4.1 5题

文心一言 VS 讯飞星火 VS chatgpt (19)-- go语言的slice和rust语言的Vec的扩容流程是什么?

个人首测百度文心一言 VS ChatGPT GPT-4

文心一言 VS ChatGPT,国产大模型和国外的差距有多大?