一个“分而治之”的算法分配

时间:2013-01-29 10:14:05

标签: algorithm divide-and-conquer

现在我有N个不同的整数,我需要找到一个数字最多的区间,其值在O(NlogN)时间内的区间的端点之间。我称之为“分而治之”的问题,因为它是我期末考试中的“分而治之”类别。我已经考虑了两个星期并做了很多实验,没有一个是正确的(与蛮力算法相比)。有人能帮助我吗?

的示例:

8,1,3,4,7。答案是1-7。

2,6,5,4,9,8。答案是2-9或2-8。

我认为“间隔”这个词并不代表我的意思。我的意思是找到数组最多的子序列,其值在子序列的端点之间。例1:“1,3,4,7”有两个数字(3,4),例如2:“2,6,5,4,9”和“2,6,5,4,9” ,8“有三个数字(6,5,4)。

这是我的代码(O(n ^ 2))。 @Vaughn Cato我用它来比较你的代码。

#! /usr/bin/env python
#coding=utf-8
import itertools
def n2(numbers):
  a = [0]*len(numbers)
  ans = -1
  l = 0
  r = 0
  for j in range(1,len(numbers)):
    t = 0
      for i in range(j-1,-1,-1):
        if numbers[i]<numbers[j]:
          x = t - a[i]
          if x>ans:
            ans = x
            l = i
            r = j
          t += 1
        else:
          a[i] += 1
  return (numbers[l],numbers[r],ans)

def countBetween(numbers,left,right):
  cnt = 0
  for i in range(left+1,right):
    if numbers[left]<numbers[i]<numbers[right]:
      cnt += 1
  return cnt

for numbers in itertools.permutations(range(5)):
  ans1=n2(numbers)
  ans2=longestInterval(numbers)
if(ans1[2]!=ans2[2]):
  print ans1,ans2,numbers

2 个答案:

答案 0 :(得分:1)

注意:这实际上不起作用,但它可能会给你一些想法。

这样想:

  • X成为数字数组。
  • s成为子序列开头的索引。
  • e成为子序列结尾的索引。

如果选择任意分区索引p,则最长的子序列要么跨越此分区,要么落在该分区的左侧或右侧。如果最长的子序列遍历此分区,则s < p <= e。要查找s,请找到sp之间的数字大于X [s]的索引。要查找“e”,请找到pe之间的数字最多且小于X [e]的索引。

您可以递归检查左侧和右侧,看看是否可以找到更长的子序列。

如果您的索引X按值排序,则可以在线性时间内查找哪个索引的数字最右边或最多少于左边的数字:

要查找起始索引,请从排序的索引列表的第一个索引开始,并说它是目前为止最好的索引。如果下一个指数大于目前为止的最佳指数,那么任何未来指数都需要比我们当前最好的指数更接近新的最佳指数,因此我们从最佳指数中减去一个(但要记住最佳指数)真的是)。如果下一个索引位于我们最佳索引的左侧,则使其成为最佳索引。按顺序为每个索引重复此过程。

您可以执行类似的过程,在右侧找到最终的最佳索引。

唯一剩下的技巧是维护我们正在处理的任何范围的索引的排序列表。这可以通过最初对整个数字集进行排序并找到它们的索引来完成,然后在递归的每个级别,我们可以在线性时间内将已排序的索引拆分为两个子列表。

这是一个想法的python实现:

# Find the index from the given indices that has the most numbers to the
# right of it which are greater in value.  The indices are sorted by
# the value of the numbers at that index. We don't even need to know
# what the numbers are.
def longestLowerSequence(indices):
  best_index=indices[0]
  target_index=best_index
  for i in range(0,len(indices)):
    if indices[i]<target_index:
      best_index=indices[i]
      target_index=best_index
    else:
      target_index-=1
  return best_index

# Find the index from the given indices that has the most numbers to the
# left of it which are less in value.
def longestUpperSequence(indices):
  n=len(indices)
  best_index=indices[n-1]
  target_index=best_index
  for i in range(0,n):
    if indices[n-1-i]>target_index:
      best_index=indices[n-1-i]
      target_index=best_index
    else:
      target_index+=1
  return best_index

# Return the pair of indices which has the most values between it.
def longestRangeFromSortedIndices(numbers,indices,begin,end):
  assert end>begin
  if end-begin<=2:
    return (indices[begin],indices[end-1])
  assert type(indices) is list
  partition=(begin+end)/2
  left_indices=filter(lambda index: index<partition,indices)
  right_indices=filter(lambda index: index>=partition,indices)
  assert len(left_indices)>0
  assert len(right_indices)>0
  left=longestLowerSequence(left_indices)
  right=longestUpperSequence(right_indices)
  left_range=longestRangeFromSortedIndices(numbers,indices,begin,partition)
  right_range=longestRangeFromSortedIndices(numbers,indices,partition,end)
  best_size=countBetween(numbers,left,right)
  best_range=(left,right)
  left_size=countBetween(numbers,left_range[0],left_range[1])
  right_size=countBetween(numbers,right_range[0],right_range[1])
  if left_size>best_size:
    best_size=left_size
    best_range=left_range
  if right_size>best_size:
    best_size=right_size
    best_range=right_range
  return best_range

def sortedIndices(numbers):
  return sorted(range(len(numbers)),key=lambda i: numbers[i])

def longestInterval(numbers):
  indices=sortedIndices(numbers)
  longest_range=longestRangeFromSortedIndices(numbers,indices,0,len(numbers))
  return (numbers[longest_range[0]],numbers[longest_range[1]])

答案 1 :(得分:0)

我认为这是maximum subarray problem的变体。

可以通过如下划分和征服来解决:

  1. 将整数数组分成相等的一半

  2. 分别计算两半的结果R1R2R1R2是每一半的最大间隔长度,以及开始和终点也存储在其中)

  3. 从前半部分获取最小整数MIN,从后半部分获取最大整数MAX,并将结果R3计算为距MINMAX的距离原始数组中的MinMaxR1分别是起点和终点)

  4. 返回最大的R2R3T(n) = 2T(n/2) + O(n) 作为整个问题的结果

  5. 为什么会这样:

    最大间隔来自三种情况之一:1)前半部分2)下半部分3)跨越两半。因此,计算三者中最大的一个会产生最佳结果。

    时间复杂度:

    解决复发问题:

    T(n) = O(nlogn)

    给出2T(n/2)。注意:正如重复表示的那样,我们解决了两个半尺寸(O(n))的子问题,并在线性时间({{1}})中找到两半的最小和最大整数。