一个"分而治之"的算法分配

Amo*_*mos 5 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
Run Code Online (Sandbox Code Playgroud)

Vau*_*ato 1

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

可以这样想:

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

如果您选择任意分区索引p,则最长的子序列要么穿过该分区,要么落在该分区的左侧或右侧。如果最长的子序列穿过该分区,则s < p <= e。要查找,请查找和s之间的数字最多且大于 X[s] 的索引。要查找“e”,请查找 和 之间的数字最多且小于 X[e] 的索引。sppe

你可以递归地检查左右两边,看看是否能找到更长的子序列。

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

要找到起始索引,请从已排序的索引列表中的第一个索引开始,并说它是迄今为止最好的。如果下一个索引大于迄今为止的最佳索引,则任何未来索引都需要比当前最佳索引更靠左才能成为新的最佳索引,因此我们从最佳索引中减去 1(但请记住最佳索引是什么)真的是)。如果下一个索引位于最佳索引的左侧,则将其设为最佳索引。按顺序对每个索引重复此过程。

您可以执行类似的过程来找到右侧末尾的最佳索引。

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

这是这个想法的 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]])
Run Code Online (Sandbox Code Playgroud)