Удалить несортированные/выпадающие элементы в почти отсортированном массиве

Учитывая массив типа [15, 14, 12, 3, 10, 4, 2, 1]. Как я могу определить, какие элементы вышли из строя, и удалить их (в данном случае это число 3). Я не хочу сортировать список, но обнаруживаю выбросы и удаляю их.

Другой пример:

[13, 12, 4, 9, 8, 6, 7, 3, 2]

Я хочу иметь возможность удалить # 4 и # 7, чтобы в итоге я получил:

[13, 12, 9, 8, 6, 3, 2]

Там также проблема, которая возникает, когда у вас есть этот сценарий:

[15, 13, 12, 7, 10, 5, 4, 3]

Вы можете удалить 7 или 10, чтобы сделать этот массив отсортированным.

В общем, проблема, которую я пытаюсь решить, заключается в том, что у меня есть список числовых показаний (некоторые из них могут немного отличаться). Я хочу, чтобы массив включал только значения, которые следуют общей линии тренда, и удалял любые выбросы. Мне просто интересно, есть ли простой способ сделать это.


person ksloan    schedule 26.08.2015    source источник
comment
Не могли бы вы просто удалить первый элемент, который удовлетворяет: a[i] < a[i + 1]? (О(n))   -  person higuaro    schedule 26.08.2015
comment
Вы хотите удалить минимальное количество элементов или любое количество в порядке?   -  person Pham Trung    schedule 26.08.2015
comment
Мне нравится эта идея @higuaro, но как мне это сделать с несколькими элементами-выбросами?   -  person ksloan    schedule 26.08.2015
comment
Минимум @PhamTrung, если возможно   -  person ksloan    schedule 26.08.2015


Ответы (2)


Я бы свел вашу проблему к самой длинной проблеме возрастающей (убывающей) подпоследовательности.

https://en.wikipedia.org/wiki/Longest_increasing_subsequence

Поскольку ваша последовательность почти отсортирована, вы гарантированно получите удовлетворительный результат (т. е. точное следование линии тренда).

Существует ряд решений; один из них описан в бесплатной книге "Основы компьютерного программирования на C#. Светлина Накова и Веселина Колева; задача представлена ​​на странице 257, упражнение 6; решение на странице 260.

Взято из книги:

Напишите программу, которая находит максимальную последовательность возрастания элементов в массиве arr[n]. Нет необходимости, чтобы элементы располагались последовательно. Например: {9, 6, 2, 7, 4, 7, 6, 5, 8, 4} -> {2, 4, 6, 8}.

Решение:

Мы можем решить проблему с помощью двух вложенных циклов и еще одного массива len[0…n-1]. В массиве len[i] можно сохранить длину самой длинной последовательно возрастающей последовательности, которая начинается где-то в массиве (неважно, где именно) и заканчивается элементом arr[i]. Следовательно, len[0]=1, len[x] — это максимальная сумма max(1 + len[prev]), где prev ‹ x и arr[prev] ‹ arr[x]. Следуя определению, мы можем вычислить len[0…n-1] с двумя вложенными циклами: внешний цикл будет перебирать массив слева направо с переменной цикла x. Внутренний цикл перебирает массив от начала до позиции x-1 и ищет элемент prev с максимальным значением len[prev], где arr[prev] ‹ arr[x]. После поиска мы инициализируем len[x] 1 + наибольшее найденное значение len[prev] или 1, если такое значение не найдено.

Описанный алгоритм находит длины всех максимальных возрастающих последовательностей, которые заканчиваются на каждом из элементов. Наибольшее из этих значений — это длина самой длинной возрастающей последовательности. Если нам нужно найти сами элементы, составляющие самую длинную последовательность, мы можем начать с элемента, где заканчивается последовательность (с индексом x), мы можем распечатать его и найти предыдущий элемент (prev). По определению prev ‹ x и len[x] = 1 + len[prev], поэтому мы можем найти prev с помощью цикла for от 1 до x-1. После этого мы можем повторить то же самое для x=prev. Находя и печатая предыдущий элемент (prev) много раз, пока он не существует, мы можем найти элементы, составляющие самую длинную последовательность в обратном порядке (от последнего к первому).

person Igor Sowinski    schedule 26.08.2015
comment
Я думаю, это оно! Позвольте мне попробовать. - person ksloan; 26.08.2015

Простой алгоритм, описанный Игуаро, может помочь вам сгенерировать правильную последовательность:

Для каждого элемента с индексом i, если a[i] < a[i + 1], мы можем просто удалить этот элемент a[i].

for(int i = 0; i < size; i++)
    while(a[i] < a[i + 1]){
       remove a[i];
       i--;
    }

Однако этот подход не может гарантировать минимальное количество удаляемых элементов. Например, для этой последовательности [10, 9, 8, 100, 1, 0] удаление 100 будет оптимальным вместо удаления 8, затем 9, затем 10.

Чтобы найти минимальное количество удаляемых элементов, мы замечаем, что нам нужно найти самую длинную убывающую подпоследовательность, аналогичную классической самая длинная возрастающая подпоследовательность, решение которой описано здесь

person Pham Trung    schedule 26.08.2015
comment
Почему бы нам не удалить a[i+1] вместо этого? Это убрало бы 100, что было бы оптимально. Таким образом, код будет `for(int i = 0; i < size; i++) while(a[i] < a[i + 1]){ remove a[i+1]; i--; } - person Electrix; 11.10.2015
comment
@NikhilJagdale, мы можем легко привести пример, в котором ваше решение выводит неверный результат, например, эта последовательность [100, 99, 5, 98, 97, 96] -> правильное решение [100, 99, 98, 97, 96], ваш вывод [100, 99, 5] - person Pham Trung; 12.10.2015