如何处理包含偶数元素的子集?(使用分而治之法找出峰值问题)



我很难用Divide&征服算法。最大的问题是,我不知道如何处理具有偶数元素的子集。

一个典型的问题是"给定一个输入数组nums,其中nums[i]≠nums[i+1],找到一个峰值元素并返回其索引"。

书上的算法说:

如果nums[n/2]<nums[n/2-1]然后只看左半部分就可以找到峰值

Else if nums[n/2]<nums[n/2+1]然后只看右半部分就可以找到峰值

其他n/2位置为峰值

当n=2时,我不知道如何处理n/2。因为算法似乎总是把集合分成两部分。当子集包含奇数个元素时,很容易理解,比如[a,b,c]。我可以找到中间的元素b并进行比较。当子集只包含两个元素时,比如[a,b]。我找不到中间的元素来比较。

为了使递归正确终止,我在python代码中添加了一些逻辑。我就是一次都做不到。我想知道有没有一种方法来思考关于像我的问题中的[a,b]这样的子集的终止条件?

class Solution:
def findPeakElement(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
def finder(start, end):
if start == end:
return start
if end - start == 1:
return end if nums[start] < nums[end] else start
N = end-start+1
if(nums[start+N//2]<nums[start+N//2-1]):
return finder(start,start+N//2-1)
elif(nums[start+N//2]<nums[start+N//2+1]):
return finder(start+N//2+1,end)
else:
return start+N//2
return finder(0,len(nums)-1)

我建议简化您的逻辑和样式,以便更容易对代码进行推理。你在重复计算N//2,这浪费了周期,而且很嘈杂,在语义上毫无意义。将工作保存在函数开头的一个名为mid的变量中,赋予它意义。在代码中添加间距,以减少视觉噪音,并使逐步执行变得愉快(并且可能)。

至于startendN,这是一个必须考虑和操作的额外变量——startend足以处理所有情况,混淆这些变量似乎是代码中的一个问题。

既然你已经知道算法,那么你就离解决方案很近了。不过,数组的奇偶性不是问题——唯一的问题是mid == 0mid == len(nums) - 1时的(字面!)边缘情况。在这两种情况下,只有一个邻居,所以如果我们分别尝试nums[mid-1]nums[mid+1],就会崩溃。解决这些问题需要在尝试这些比较之前测试mid是否不在阵列的一端或另一端。

把所有这些放在一起,函数中需要发生的就是:

def finder(start, end):
mid = (start + end) // 2
if mid > 0 and nums[mid] < nums[mid-1]:
return finder(start, mid - 1)
elif mid < end and nums[mid] < nums[mid+1]:
return finder(mid + 1, end)
else:
return mid

最新更新