如何处理包含偶数个元素的子集?(使用分治法解决峰值问题)

时间:2019-01-18 05:40:29

标签: algorithm

我很难用Divide&Conquer算法编写代码。最大的问题是我不知道如何处理偶数个元素的子集。

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

书上的算法说:

如果nums [n / 2]

否则,如果nums [n / 2]

其他n / 2位是峰值

当n = 2时,我不知道如何处理n / 2。因为该算法似乎总是将集合分为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)

1 个答案:

答案 0 :(得分:0)

我建议简化您的逻辑和样式,以便更轻松地推断代码。您正在反复计算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