5

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

例子:

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

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

我认为“间隔”这个词并不能表达我的意思。我的意思是找到数组的一个子序列,它的值在子序列的端点之间的数字最多。eg.1:“1,3,4,7”有两个数字(3,4),eg.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
4

2 回答 2

1

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

这样想:

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

如果你选择一个任意的分区索引p,那么最长的子序列要么穿过这个分区,要么落在那个分区的左边或右边。如果最长的子序列穿过这个分区,那么s < p <= e. 要查找,请查找和之间大于 X[s]s的数字最多的索引。要找到 'e',请找到介于两者之间且小于 X[e] 的数字最多的索引。sppe

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

如果您有按值排序的索引,则可以在线性时间内找到哪个索引在右侧具有最大的数字或在左侧具有最大的数字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]])
于 2013-01-30T16:47:38.930 回答
0

我相信这是最大子数组问题的一个变种。

可以使用分治法来解决,如下所示:

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

  2. R1分别计算R2两半的结果(是每一半的最大间隔的长度R1R2并存储起点和终点)

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

  4. 返回最大的R1,R2R3作为整个问题的结果

为什么这样有效:

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

时间复杂度:

解决复发:

T(n) = 2T(n/2) + O(n)

T(n) = O(nlogn). 注意:正如递归所示,我们解决了两个一半大小的子问题(<code>2T(n/2)),并在线性时间(O(n))中找到两半中的最小和最大整数。

于 2013-01-31T17:49:54.013 回答