PTA-Python题目 第2章-5 求奇数分之一序列前N项和

该博客介绍了如何使用Python计算序列1 + 1/3 + 1/5 + ...的前N项和。通过输入一个正整数N,程序将输出精确到小数点后6位的和。博主推荐使用列表推导式来实现,认为这种方法更简洁高效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单易懂【PTA-Python题库】第2章-5 求奇数分之一序列前N项和

本题要求编写程序,计算序列 1 + 1/3 + 1/5 + … 的前N项之和。

输入格式:

输入在一行中给出一个正整数N。

输出格式:

在一行中按照“sum = S”的格式输出部分和的值S,精确到小数点后6位。题目保证计算结果不超过双精度范围。

输入样例:

23

输出样例:

sum = 2.549541

思路:

我用的是列表推导式,我之前看也有人用循环,但是个人感觉列表推导式更为简洁。

代码如下:

n = int(input())
a = sum(
<think>好的,我现在要解决的问题是如何找到两个已排序数组合并后的中位数。首先,我需要明确中位数的定义。对于一个有序数组来说,如果长度是奇数,中位数就是中间的那个数;如果是偶数,就是中间两个数的平均值。那对于两个数组合并后的情况,应该也是同样的逻辑,但合并后的数组可能很大,直接合并的话时间复杂度会很高,特别是当数组很大时,这样的方法效率太低。 我记得用户提到过最有效的方法是使用二分查找,这可能涉及到分治或者类似的策略。让我先想想直接合并的方法。假设数组nums1的长度是m,nums2的长度是n,合并后的数组长度是m+n。如果我能找到第k小的元素,那么当m+n是奇数时,k就是(m+n)//2 +1,偶数的话可能需要找到第kk+1的元素取平均。但直接合并需要O(m+n)的时间,对于大数组来说可能不够高效。 那如何用更高效的方法呢?比如二分查找。这里可能需要比较两个数组的中位数,然后排除不可能的部分。例如,比较两个数组的中位数,假设nums1的中位数是mid1,nums2的是mid2。如果mid1 <= mid2,那么nums1的半部分可能可以排除,反之亦然。这样每次可以排除掉一部分元素,从而减少需要处理的数据量。这种方法的时间复杂度应该是对数级别的,比如O(log(min(m,n)))。 不过具体的实现细节可能比较复杂。比如,如何确定每次排除多少个元素?如何确保在数组长度不同的情况下正确处理边界条件?例如,当其中一个数组的所有元素都被排除后,如何处理剩下的数组? 另外,需要处理奇偶长度的问题,以及如何找到第k小的元素。可能需要递归或循环地调整k的值,每次排除一部分元素,直到k减到1或者某个基本情况。 例如,假设要找两个数组中第k小的元素,可以比较两个数组中第k/2个元素的大小。如果A[k/2-1] < B[k/2-1],那么可以排除A的k/2个元素,因为它们不可能是第k小的元素。然后将问题转化为在剩下的元素中找第k -k/2小的元素。这样的过程需要处理当某个数组长度不足k/2的情况,这时候可能需要取最后一个元素进行比较,然后排除可能的元素。 举个例子,假设A的长度是m,B的长度是n,且m <=n。要找第k小的元素。比较A[i]B[j],其中i = min(k//2, m),j = k -i。如果A[i-1] <= B[j-1],则排除A的i个元素,k -=i,否则排除B的j个元素,k -=j。这样不断缩小范围,直到k=1或者其中一个数组被排除完。 这样的算法需要处理很多边界情况,比如当其中一个数组为空时,直接返回另一个数组的第k个元素。或者当k=1时,返回两个数组当剩余元素中的较小者。 那在具体实现时,可能需要编写一个辅助函数来递归或迭代地处理这个问题。此外,需要考虑奇偶合并后的长度来确定需要找的是第几个元素。 例如,合并后的总长度是m+n,如果总长度是奇数,中位数是第(m+n+1)//2小的元素;如果是偶数,则是第(m+n)//2第(m+n)//2 +1的两个元素的平均值。 所以整个算法的步骤可能如下: 1. 确定总长度是奇数还是偶数,决定要找的位置。 2. 使用二分查找的方法找到相应的第k小元素。 3. 处理各种边界情况,如某个数组为空,或者k超出某个数组长度的情况。 现在,我需要考虑如何将这个思路转化为具体的代码,比如Python实现。可能需要处理索引的问题,避免越界,同时正确排除元素。 举个例子,假设nums1 = [1,3], nums2 = [2]。合并后的数组是[1,2,3],中位数是2。使用二分的方法,k=2(因为总长度3,奇数是第2个元素?可能需要再确认索引的计算)。 或者另一个例子,nums1 = [1,2], nums2 = [3,4],合并后的中位数是(2+3)/2=2.5。这时需要找到第2第3个元素。 可能需要注意,当总长度是偶数时,需要两次调用找第kk+1的函数,或者是否有更高效的方式? 不过在实际中,可能可以将两种情况合并处理,比如不管奇偶都计算两个位置,然后取平均。如果总长度是奇数,两次调用的结果可能相同,或者只需要计算一次。 然后,关于代码实现,可能需要写一个函数来找到第k小的元素。例如: def find_kth(nums1, nums2, k): # 处理边界情况,其中一个数组为空的情况 if len(nums1) == 0: return nums2[k-1] if len(nums2) == 0: return nums1[k-1] # 其他情况,比较ij的元素 # 确保i + j =k,这里i取min(k//2, len(nums1)), j =k -i 这样的函数需要处理递归或迭代的情况。或者,可以用循环来不断缩短数组的搜索范围。 不过,这样的递归可能导致栈溢出,如果数组很大,但log级别应该没问题。 另一个问题是如何处理当k比两个数组的长度之还大,但根据问题设定,中位数的位置不会超过总长度,所以调用时应该没问题。 现在,我需要验证这个思路是否正确。例如,测试一些例子: 测试案例1: nums1 = [1,3], nums2 = [2], 总长度3,中位数是2。 调用函数找第2小的元素: 初始k=2. 比较i=1(k//2=1), nums1[0] =1, nums2[0] =2。因为1<=2,排除nums1的1个元素,剩下的nums1是[3],k=2-1=1。现在找第1小的元素,比较nums1[0]nums2[0],取较小的,即32中的2,所以最终得到2,正确。 测试案例2: nums1 = [1,2], nums2 = [3,4], 总长度4,需要找第2第3小的元素。 找第2小的元素:k=2. 比较i=1,nums1[0]=1,nums2[0]=3,排除nums1的1个元素,k=1。剩下nums1=[2], nums2=[3,4]。找第1小的元素是23中的2,所以第2小的是2。然后找第3小的元素,k=3。比较i=1,nums1的i=1(可能超出长度?或者需要处理i不超过nums1的长度)。此时nums1的长度是1,所以i=1,但nums1的索引是0到0。所以可能这里需要调整。或者,原数组已经被缩短,所以在这种情况下,i可能取min(k//2, len(nums1))。 假设现在要找第3小的元素,初始两个数组是[1,2][3,4]。总长度是4,中位数是第2第3的平均,即2.5。当找第3小的元素,k=3。比较i =3//2=1,所以i=1,nums1[0]=1, nums2[3-1-1=1?或者 j =k -i=3-1=2,但nums2的长度是2,所以nums2的索引是1。此时nums2[j-1] = nums2[1]=4。比较1 <=4,所以排除nums1的i=1个元素,此时剩下的nums1是[2],k=3-1=2。然后现在找第2小的元素,在两个数组[2][3,4]中。此时i=2//2=1,nums1的长度是1,所以i=1,j=2-1=1。nums1[0]=2,nums2[0]=3。比较2 <=3,所以排除nums1的1个元素,此时nums1为空,剩下的k=2-1=1。此时返回nums2的k-1=0索引,即3。所以第3小的元素是3,而第2小的是2,所以平均是2.5,正确。 看起来这样的逻辑是正确的。那在代码实现时,如何处理这些情况? 可能的Python代码大致结构如下: def findMedianSortedArrays(nums1, nums2): m, n = len(nums1), len(nums2) total = m + n if total % 2 ==1: return find_kth(nums1, nums2, total//2 +1) else: return (find_kth(nums1, nums2, total//2) + find_kth(nums1, nums2, total//2 +1))/2 def find_kth(a, b, k): if len(a) > len(b): a, b = b, a # 保证a是较短的数组 if not a: return b[k-1] if k ==1: return min(a[0], b[0]) # 取ij,其中i +j =k i = min(k//2, len(a)) j = k -i if a[i-1] <= b[j-1]: # 排除a的i个元素 return find_kth(a[i:], b, k -i) else: # 排除b的j个元素 return find_kth(a, b[j:], k -j) 这样,每次递归调用时,较短的数组会被优先处理,可能更快缩小问题规模。这里可能需要注意数组的切片是否正确,以及递归终止条件。 例如,当a为空时,直接返回b的第k-1个元素。当k=1时,返回两个数组首元素的较小者。 测试这个函数是否正确: 测试案例1: nums1 = [1,3], nums2 = [2] findMedianSortedArrays([1,3], [2])调用时,总长度3,奇数,返回find_kth([1,3], [2], 2). 在find_kth函数中,a是[1,3],b是[2]. len(a)=2, len(b)=1. 进入函数后,i = min(2//2=1, 2) →1. j=2-1=1. 比较a[0]=1b[0]=2。因为1<=2,所以排除a的1个元素,即a变为[3],k=2-1=1。再次调用find_kth([3], [2], 1)。此时k=1,返回min(3,2)=2。正确。 测试案例2: nums1 = [1,2], nums2 = [3,4] 总长度4,偶数,需要找第2第3个元素。find_kth两次调用: 第一次k=2,第二次k=3. 当k=2时,i=1,比较a[0]=1b[1-1]=b[0]=3。1<=3,排除a的1个元素,k=1。调用find_kth([2], [3,4],1) →min(2,3)=2。 当k=3时,i=3//2=1,j=3-1=2。比较a[0]=1b[1]=4。1<=4,排除a的1,k=2。此时a为空,所以返回b[2-1]=b[1]=4?这不对啊,因为合并后的数组是[1,2,3,4],第3小的元素应该是3。这时候哪里出错了? 哦,看来我的算法可能有问题。当处理k=3时,原数组是nums1=[1,2], nums2=[3,4]. 在find_kth的第一次调用中,a是[1,2], b是[3,4]. i=3//2=1,j=3-1=2。比较a[0]=1b[1]=4。因为1<=4,所以排除a的1个元素,即a变为[2],k=3-1=2。然后递归调用find_kth([2], [3,4], 2). 在第二次调用中,a是[2], b是[3,4]. i=2//2=1,j=2-1=1。比较a[0]=2b[0]=3。2 <=3,所以排除a的1个元素,此时a变为空,k=2-1=1。现在调用find_kth([], [3,4],1),返回b[0]=3。所以最终结果是3,正确。这样,两次调用的结果分别是23,平均为2.5,正确。 所以,之的例子中的错误可能是我在分析过程中的误解,但实际代码是正确的。 这说明这个算法是正确的。那这样的实现应该能够解决问题,时间复杂度是O(log(min(m,n))),因为每次递归调用都会减少问题规模,且每次处理的数组是较短的数组,所以时间效率较高。 总结来说,解决这个问题的关键在于利用二分查找的思想,每次排除掉不可能的部分,从而快速缩小搜索范围。需要注意的是处理各种边界条件,如数组为空、k=1等情况,以及正确计算索引以避免越界错误。</think>### 两个已排序数组的合并中位数算法 要高效解两个已排序数组的合并中位数,可采用基于二分查找的分治策略,时间复杂度为$O(\log(\min(m, n)))$,避免直接合并数组的低效操作[^1]。 #### 算法步骤 1. **确定中位数位置**: - 若合并后总长度$m+n$为奇数,中位数为第$\frac{m+n+1}{2}$小的元素。 - 若为偶数,则为第$\frac{m+n}{2}$$\frac{m+n}{2}+1$小元素的平均值。 2. **二分查找核心思想**: - 每次比较两个数组的第$\frac{k}{2}$个元素,排除较小元素的半部分,缩小问题规模[^1]。 - 递归调整$k$的值,直到$k=1$或某数组为空。 #### Python实现 ```python def findMedianSortedArrays(nums1, nums2): def find_kth(a, b, k): if len(a) > len(b): a, b = b, a # 确保a是较短的数组 if not a: return b[k-1] if k == 1: return min(a[0], b[0]) # 计算分割点 i = min(k // 2, len(a)) j = k - i if a[i-1] <= b[j-1]: return find_kth(a[i:], b, k - i) else: return find_kth(a, b[j:], k - j) total = len(nums1) + len(nums2) if total % 2 == 1: return find_kth(nums1, nums2, total // 2 + 1) else: left = find_kth(nums1, nums2, total // 2) right = find_kth(nums1, nums2, total // 2 + 1) return (left + right) / 2 ``` #### 示例分析 - **输入**: $nums1 = [1, 3]$, $nums2 = [2]$ **输出**: $2.0$ **解析**: 合并后数组为$[1, 2, 3]$,中位数是第2小的元素$2$[^2]。 - **输入**: $nums1 = [1, 2]$, $nums2 = [3, 4]$ **输出**: $2.5$ **解析**: 合并后数组为$[1, 2, 3, 4]$,中位数为$(2 + 3) / 2 = 2.5$[^2]。 #### 关键点 - **边界处理**:当数组为空或$k=1$时直接返回结果。 - **复杂度控制**:每次递归排除约一半数据,时间复杂度为$O(\log(\min(m, n)))$。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值