определение алгоритма «разделить и властвовать»

Теперь у меня есть N разных intergers, мне нужно найти интервал, который имеет наибольшее число, значение которого находится между конечными точками интервала времени O (NlogN). Я называю это проблемой «разделяй и побеждай», потому что она находится в моей категории «разделяй и властвуй» моего выпускного экзамена. Я думал об этом в течение 2 недель и провел много экспериментов, ни один из них не является правильным (по сравнению с алгоритмом грубой силы). Может кто-нибудь мне помочь?

Примеры:

8,1,3,4,7. Ответ 1-7.

2,6,5,4,9,8. Ответ 2-9 или 2-8.

Я думаю, что слово «интервал» не выражает моего значения. Я хочу найти подпоследовательность массива с наибольшим числом, значение которого находится между конечными точками подпоследовательности. Например: «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]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]
5
nl ja de
Что относительно массива вроде 5666667 1229223 ? (Я знаю, речь идет о разных целых числах, так что просто подумайте 50, 61, 62, 63 и т. Д.). В первом тайме лучшим решением является 5-7, а во второй половине лучшим решением является 1- 3, но в целом, лучшим решением будет 5-9. Принимая только решения подзадач, т. Е. 5-7 и 1-3, как вы могли объединить их с 5-9?
добавлено автор tobias_k, источник
Покажите нам свой код, пример проблемы с ожидаемым решением и сообщите нам какие-либо проблемы/ограничения, о которых вы не упомянули.
добавлено автор Alexey Frunze, источник
Если вы были у него в течение 2 недель, вы, вероятно, что-то пробовали. Не стесняйтесь делиться.
добавлено автор keyser, источник
Любые ограничения на интервал? В противном случае вы можете вывести [MIN_INT, MAX_INT] в O (1).
добавлено автор Henrik, источник
@ cupidon4uk нет, перед редактированием можно было интерпретировать вопрос таким образом, что вам не нужно вообще смотреть на элементы, просто выведите максимальный представляемый интервал. Но теперь вопрос несколько поясняется примерами.
добавлено автор Henrik, источник
добавьте некоторые объяснения для первого и второго примеров.
добавлено автор ivan.mylyanyk, источник
о, теперь я понял. Хе-хе, действительно, это очень интересная проблема.
добавлено автор ivan.mylyanyk, источник
кто-нибудь получил примеры? Если да, поделитесь им с другими, потому что я не могу получить его вообще.
добавлено автор ivan.mylyanyk, источник
@henrik, возможно, вы имеете в виду в O (n), не так ли? По крайней мере, вам нужно просмотреть все элементы массива.
добавлено автор ivan.mylyanyk, источник
на самом деле это не так плохо, потому что это не требует перетасовки #s. все, что вам нужно сделать, это отрегулировать конечные точки подстроки. Подсказка: скажите, что вы разделите список на два, и у вас есть правильный ответ для левого и правильного ответа для правильного. Как бы вы объединили их? это ключ .
добавлено автор thang, источник
@amos, что вы пробовали? предположим, что у меня есть массив a [1..N] (wlog, предположим, что N четный), и я знаю, что решение для [1 ... N/2] равно i, j (i
добавлено автор thang, источник
@thang Я потратил много времени на поиск такого метода слияния. Однако это кажется невозможным. Это не похоже на проблему RMQ.
добавлено автор Amos, источник
@tobias_k Я не думаю, что мы могли бы объединить две подзадачи только с использованием этой информации. Я пытался сохранить массив как (aftersmaller): поскольку [i] означает, что после i есть числа [i], которые меньше i. Аналогичным образом мы можем построить другие 3 массива: ab, bs, bb. Но я все еще не мог найти способ эффективно их использовать.
добавлено автор Amos, источник
Эта проблема была решена на stackoverflow.com/ вопросы/22952096/& hellip; Дэвида Эйзенстата.
добавлено автор Amos, источник
Извините, но я упростил эту проблему, поэтому мой код не является явным. Надеюсь, что примеры ясно объясняют это.
добавлено автор Amos, источник
@thang, интересная отправная точка. Тем не менее слияние случая, когда j = k-1 является ключом к проблеме (и кажется мне особенно сложным).
добавлено автор Rerito, источник
По моему мнению, ваша проблема заключается в том, чтобы найти min и max вашего целочисленного списка. Сортировка слияния (которая имеет сложность O (N.log (N)), и вы закончили ... Я не думаю, что это так просто, поэтому объясните свой предмет четко
добавлено автор Rerito, источник

2 ответы

ПРИМЕЧАНИЕ. Это на самом деле не работает, но может дать вам некоторые идеи.

Подумайте об этом так:

  • Пусть X - массив чисел.
  • Пусть s будет индексом начала подпоследовательности.
  • Пусть e - индекс конца подпоследовательности.

If you pick an arbitrary partition index p, then the longest subsequence either goes across this partition or it falls to the left or right of that partition. If the longest subsequence goes across this partition, then s < p <= e. To find s, find the index with the most numbers between s and p which are greater than X[s]. To find 'e', find the index with the most numbers between p and e which are less than 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[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)
  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
добавлено
@amos: Я согласен. Это делает предположение, что вы можете найти начальный и конечный индексы независимо друг от друга на каждой стороне раздела, но они фактически взаимосвязаны.
добавлено автор Vaughn Cato, источник
Благодаря! Но я думаю, что этот метод может быть неправильным. Я сравнил ваш код с кодом грубой силы и нашел это: (1, 3, 4, 0, 2). Вы код дает (1,2), а ans - (1,4).
добавлено автор Amos, источник

Я считаю, что это вариант проблемы с максимальным подмассивом .

Его можно решить, используя divide и conquer следующим образом:

  1. Разделите целочисленный массив на равные половины

  2. Вычислить результаты R1 , R2 на обеих половинах соответственно ( R1 , R2 - это длины максимальных интервалов для каждой половины, а также начальная и конечная точки)

  3. Получите минимальное целое число MIN из первой половины и максимальное целое число MAX со второй половины и вычислите результат R3 как расстояние от MIN до MAX в исходном массиве ( Min и Max ) являются начальной и конечной точкой соответственно)

  4. Возвратите самый большой из R1 , R2 и R3 как результат всей проблемы

Почему это работает:

Наибольший интервал исходит из одного из трех случаев: 1) первая половина 2) вторая половина 3) через две половины. Таким образом, вычисление наибольшего из трех дает оптимальный результат.

Сложность времени:

Решение проблемы:

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

дает T (n) = O (nlogn) . Примечание: по мере повторения мы решаем две подзадачи с половинным размером ( 2T (n/2) ) и находим минимальные и максимальные целые числа в двух половинах в линейном времени ( O (n) ).

0
добавлено
@amos Я думаю, я проигнорировал тот факт, что целое число в интервале может не быть в диапазоне. Я оставлю ответ так, как он есть, если кто-то должен получить от него вдохновение. Я продолжу работать над этим.
добавлено автор Terry Li, источник
Благодаря! Но мне интересно, понимаете ли вы эту проблему. «Получите минимальное целое число MIN от первой половины и максимальное целочисленное значение MAX со второй половины и вычислите результат R3 как расстояние от MIN до MAX в исходном массиве (Min и Max - это начальная и конечная точки соответственно)» неверно ,
добавлено автор Amos, источник