5

今、私は N 個の異なる整数を持っています。値が O(NlogN) 時間で間隔の終点の間にある数値が最も多い間隔を見つける必要があります。それは私の最終試験の「分割統治」カテゴリにあるので、私はそれを「分割統治」問題と呼んでいます。私はそれについて2週間考えていて、多くの実験を行ってきましたが、どれも正しくありません(ブルートフォースアルゴリズムと比較して)。誰かが私を助けることができますか?

例:

8,1,3,4,7. 答えは1~7です。

2,6,5,4,9,8. 答えは 2-9 または 2-8 です。

「間隔」という言葉は私の意味を表していないと思います。値がサブシーケンスのエンドポイントの間にある数値が最も多い配列のサブシーケンスを見つけることを意味します。例1: 「1,3,4,7」には2つの数字(3,4)があり、例2: 「2,6,5,4,9」と「2,6,5,4,9」の両方があります,8" には 3 つの数字 (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シーケンスの終わりのインデックスとします。

任意のパーティション index を選択するとp、最長のサブシーケンスがこのパーティションを横切るか、そのパーティションの左または右に落ちます。最長のサブシーケンスがこのパーティションにまたがる場合、s < p <= e. を見つけるには、X[s] より大きいとsの間の数が最も多いインデックスを見つけます。'e' を見つけるには、X[e] より小さいとの間の数が最も多いインデックスを見つけます。sppe

左側と右側を再帰的にチェックして、より長いサブシーケンスを見つけることができるかどうかを確認できます。

X値で並べ替えられたインデックスがある場合、どのインデックスが右側に最も大きいか、または左側に最も小さいかを見つけることは、線形時間で実行できます。

開始インデックスを見つけるには、並べ替えられたインデックス リストの最初のインデックスから始めて、それが今のところ最高であると言います。次のインデックスがこれまでの最高のインデックスよりも大きい場合、新しい最高のインデックスになるには、現在の最高のインデックスよりもさらに左側にある必要があるため、最高のインデックスから 1 を引きます (ただし、最高のインデックスが何であるかを覚えておいてください)。本当にあった)。次のインデックスが最適なインデックスの左側にある場合は、それを最適なインデックスにします。インデックスごとに、このプロセスを順番に繰り返します。

同様の手順を実行して、右側の終わりに最適なインデックスを見つけることができます。

残っている唯一のトリックは、作業中の範囲のインデックスの並べ替えられたリストを維持することです。これは、最初に数値のセット全体をソートし、それらのインデックスを見つけることで実行できます。次に、再帰の各レベルで、ソートされたインデックスを線形時間で 2 つのサブリストに分割できます。

アイデアの 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を計算します(は各半分の最大間隔の長さであり、開始点と終了点も保存されます)R2R1R2

  3. MIN前半から最小整数を取得し、後半から最大整数を取得し、結果を元の配列のからまでの距離としてMAX計算します (とはそれぞれ始点と終点です)。R3MINMAXMinMax

  4. の最大のものを返し、R1問題全体の結果としてR2R3

これが機能する理由:

最大の間隔は、1) 前半 2) 後半 3) 2 つの半分にまたがる 3 つのケースのいずれかに由来します。したがって、3 つのうち最大のものを計算すると、最適な結果が得られます。

時間の複雑さ:

再発の解決:

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

を与えT(n) = O(nlogn)ます。注: 再帰が示すように、半分の大きさの 2 つの部分問題 (<code>2T(n/2)) を解き、線形時間 ( O(n)) で 2 つの半分の最小整数と最大整数を見つけます。

于 2013-01-31T17:49:54.013 に答える