Разделить массив на две части [закрыт]
Скорее всего, данный вопрос не соответствует тематике Stack Overflow на русском, согласно правилам описанным в справке.
Закрыт 6 лет назад .
Разделить массив на две части, поместив в первую элементы, больше среднего арифметического их суммы, а во вторую меньшие. Помогите, пожалуйста.
Если задача, получить новый массив, в котором сначала идут элементы больше среднего арифметического, затем остальные, то достаточно отсортировать массив по убыванию:
В результата в массиве a сначала будут идти элементы больше средне арифметического.
Разделение массива
На входе массив a[0]. a[N] и опорный элемент p, по которому будет производиться разделение.
1. Введем два указателя: i и j. В начале алгоритма они указывают, соответственно, на левый и правый конец последовательности.
2. Будем двигать указатель i с шагом в 1 элемент по направлению к концу массива, пока не будет найден элемент a[i] >= p. Затем аналогичным образом начнем двигать указатель j от конца массива к началу, пока не будет найден a[j] <= p.
3. Далее, если i <= j, меняем a[i] и a[j] местами и продолжаем двигать i,j по тем же правилам.
4. Повторяем шаг 3, пока i <= j.
Рассмотрим работу процедуры для массива a[0], . , a[6] и опорного элемента p = a[3].
Теперь массив разделен на две части: все элементы левой меньше либо равны p, все элементы правой — больше, либо равны p. Разделение завершено.
Общий алгоритм
quickSort ( массив a, верхняя граница N ) <
Выбрать опорный элемент p — середину массива
Разделить массив по этому элементу
Если подмассив слева от p содержит более одного элемента,
вызвать quickSort для него.
Если подмассив справа от p содержит более одного элемента,
вызвать quickSort для него.
Реализация на Си для int.
void quickSortR(int* a, long N) <
// На входе — массив a[], a[N] — его последний элемент.
long i = 0, j = N; // поставить указатели на исходные места
p = a[ N>>1 ]; // центральный элемент
while ( a[i] < p ) i++;
while ( a[j] > p ) j—;
temp = a[i]; a[i] = a[j]; a[j] = temp;
// рекурсивные вызовы, если есть, что сортировать
if (j > 0) quickSortR(a, j);
if (N > i) quickSortR(a+i, N-i);
Количество шагов деления (глубина рекурсии) составляет приблизительно log n, если массив делится на более-менее равные части. Таким образом, общее быстродействие: O(n log n), что и имеет место на практике.
Однако, возможен случай таких входных данных, на которых алгоритм будет работать за O(n 2 ) операций. Такое происходит, если каждый раз в качестве центрального элемента выбирается максимум или минимум входной последовательности. Если данные взяты случайно, вероятность этого равна 2/n. И эта вероятность должна реализовываться на каждом шаге. Вообще говоря, малореальная ситуация.
Метод неустойчив. Поведение довольно естественно, если учесть, что при частичной упорядоченности повышаются шансы разделения массива на более равные части.
Сортировка использует дополнительную память, так как приблизительная глубина рекурсии составляет O(log n), а данные о рекурсивных подвызовах каждый раз добавляются в стек.
1. Из-за рекурсии и других «накладных расходов» Quicksort может оказаться не столь уж быстрой для коротких массивов. Поэтому, если в массиве меньше C элементов (константа зависит от реализации, обычно равна от 3 до 40), вызывается сортировка вставками. Увеличение скорости может составлять до 15%.
2. В случае явной рекурсии в стеке сохраняются не только границы подмассивов, но и ряд совершенно ненужных параметров, таких как локальные переменные. Если эмулировать стек программно, его размер можно уменьшить в несколько раз.
3. Чем на более равные части будет делиться массив – тем лучше. Потому в качестве опорного целесообразно брать средний из трех, а если массив достаточно велик – то из девяти произвольных элементов.
4. Пусть входные последовательности очень плохи для алгоритма. Например, их специально подбирают, чтобы средний элемент оказывался каждый раз минимумом. Можно просто выбирать в качестве опорного случайный элемент входного массива. Тогда любые неприятные закономерности во входном потоке будут нейтрализованы. Другой вариант — переставить перед сортировкой элементы массива случайным образом.
5. Быструю сортировку можно использовать и для двусвязных списков. Единственная проблема — отсутствие непосредственного доступа к случайному элементу. Так что в качестве опорного приходится выбирать первый элемент, и либо надеяться на хорошие исходные данные, либо случайным образом переставить элементы перед сортировкой.
6. Можно заменить рекурсию на итерации, реализовав стек на основе массива. Процедура разделения будет выполняться в виде цикла. Каждый раз, когда массив делится на две части, в стек будет направляться запрос на сортировку большей из них, а меньшая будет обрабатываться на следующей итерации. Запросы будут выбираться из стека по мере освобождения процедуры разделения от текущих задач. Сортировка заканчивает свою работу, когда запросы кончаются.
4. Сортировка слиянием
Сортировка слиянием также построена на принципе «разделяй-и-властвуй», однако реализует его несколько по-другому, нежели quickSort. А именно, вместо разделения по опорному элементу массив просто делится пополам.
//a — сортируемый массив, его левая граница lb,правая граница ub
void mergeSort(int a[], long lb, long ub) <
long split; // индекс, по которому делим массив
mergeSort(a, lb, ub); // сортировать левую половину
mergeSort(a, split+1, last);// сортировать правую половину
merge(a, lb, split, ub);
Функция merge на месте двух упорядоченных массивов a[lb]. a[split] и a[split+1]. a[ub] создает единый упорядоченный массив a[lb]. a[ub].
Пример работы алгоритма на массиве 3 7 8 2 4 6 1 5.. (split – трещина, раскол)

Рекурсивный алгоритм обходит получившееся дерево слияния в прямом порядке. Каждый уровень представляет собой проход сортировки слияния — операцию, полностью переписывающую массив. Обратим внимание, что деление происходит до массива из единственного элемента. Такой массив можно считать упорядоченным, а значит, задача сводится к написанию функции слияния merge (мэдж).
Один из способов состоит в слиянии двух упорядоченных последовательностей при помощи вспомогательного буфера, равного по размеру общему количеству имеющихся в них элементов. Элементы последовательностей будут перемещаться в этот буфер по одному за шаг.
merge ( упорядоченные последовательности A, B , буфер C ) <
пока A и B непусты <
cравнить первые элементы A и B
переместить наименьший в буфер
если в одной из последовательностей еще есть элементы
дописать их в конец буфера, сохраняя имеющийся порядок
Хорошо запрограммированная внутренняя сортировка слиянием работает немного быстрее пирамидальной, но медленнее быстрой, при этом требуя много памяти под буфер. Поэтому mergeSort используют для упорядочения массивов, лишь если требуется устойчивость метода (которой нет ни у быстрой, ни у пирамидальной сортировок). Сортировка слиянием является одним из наиболее эффективных методов для односвязных списков и файлов, когда есть лишь последовательный доступ к элементам.
Как оптимально разделить массив на два подмассива, чтобы сумма элементов в обоих была одинаковой, иначе возникнет ошибка?

Совет для любителей взлома. Трещины хиропрактики. S3: E3
Как оптимально разделить массив на два подмассива, чтобы сумма элементов в обоих подмассивах была одинаковой, иначе выдала ошибку?
Пример 1
Его можно разделить на
Сумма каждого подмассива составляет до 105.
Пример 2
Массив нельзя разделить на 2 массива равной суммы.
- В интересах читателя я проголосовал против всех фрагментов кода без объяснения возможной правильности соответствующего реализованного алгоритма.
- 1 Гарантируется ли неотрицательность элементов? Уникальный? Разделить массив (в голова а также хвост) или найти разделение на два подмножества?
Существует решение, которое включает динамическое программирование, которое работает в O(n*TotalSum) , где n это количество элементов в массиве и TotalSum — их общая сумма.
Первая часть состоит в вычислении набора всех чисел, которые можно создать, добавляя элементы в массив.
Для массива размером n мы назовем это T(n) ,
(Доказательство правильности проводится по индукции, как и в большинстве случаев рекурсивных функций.)
Также помните для каждой ячейки в динамической матрице элементы, которые были добавлены для ее создания.
Простой анализ сложности покажет, что это делается в O(n*TotalSum) .
После расчета T(n) , найдите в наборе элемент точно размером TotalSum / 2 .
Если такой элемент существует, то элементы, которые его создали, сложенные вместе, равны TotalSum / 2 , и элементы, которые не были частью его создания, также равны TotalSum / 2 ( TotalSum — TotalSum / 2 = TotalSum / 2 ).
Это псевдополиномиальное решение. AFAIK, эта проблема не известна п.
- Что означает «Первая часть состоит в вычислении набора всех чисел, которые можно создать, добавляя элементы в массив». подлый? «. набор всех чисел, которые можно создать». Цифры можно создать или установить? «. добавляя элементы в массив», какой массив?
- «Для массива размера n мы будем называть это T (n)». Вы называете массив размером n T (n)? Зачем? Что логически представляет собой T (n)?
- «Кроме того, помните для каждой ячейки в динамической матрице элементы, которые были добавлены для ее создания». Не для всех алгоритмов динамического программирования требуется матрица. Иногда бывает достаточно вектора. Вы можете объяснить, зачем здесь нужна матрица? Как бы выглядела эта матрица и почему? Какая связь между рекурсивной формулировкой и реализацией динамического программирования?
- «После вычисления T (n) найдите в наборе элемент, размер которого равен TotalSum / 2». Вы хотите сказать, что нам нужно искать число = TotalSum / 2?
- 1 Пожалуйста, отредактируйте этот ответ, добавив Чисто и еще более исчерпывающее объяснение «своего» алгоритма!
Это называется проблемой перегородки. Есть оптимальные решения для некоторых частных случаев. Однако в целом это NP-полная проблема.
В обычном варианте эта задача накладывает 2 ограничения, и ее можно решить более простым способом.
- Если разделение может быть выполнено только где-то по длине массива (мы не считаем элементы вышедшими из строя)
- Нет отрицательных чисел.
Затем работает следующий алгоритм:
- Есть 2 переменные, leftSum и rightSum
- Начните увеличивать leftSum слева, а rightSum — справа от массива.
- Попытайтесь исправить любой дисбаланс в нем.
Следующий код делает то же самое:
Конечно, если элементы могут быть объединены не по порядку, это действительно превращается в проблему разделения со всей ее сложностью.
- 3 @Shankar Пожалуйста, прочтите весь ответ перед тем, как комментировать. Я упоминал, что это более простой вариант той проблемы, которая не NP-Complete. [1,3,2] не имеет решения, когда вы рассматриваете этот вариант, потому что его нельзя разделить по длине на подмножества с равной суммой. Это НЕ проблема раздела. Я не имею в виду, что существует решение проблемы NP-Complete за полиномиальное время.
- canBalance (<1, 3, 3, 4, 5>) должно быть истинным, но возвращает ложь .
- @ AdilH.Raza В соответствии с ограничением — «разделение может быть выполнено только где-то по длине массива», которое указано в начале, (< 1, 3, 3, 4, 5 >) ожидается ложным.
Эта проблема говорит, что если массив может иметь два подмассива с одинаковой суммой элементов. Таким образом, должно быть возвращено логическое значение. Я нашел эффективный алгоритм: Алгоритм: Процедура Шаг 1. Возьмите пустой массив в качестве контейнера, отсортируйте исходный массив и сохраните его в пустом. Шаг 2: теперь возьмите два динамически распределяемых массива, возьмите самый высокий и второй по высоте из вспомогательного массива и сохраните его в двух подмассивах соответственно и удалите из вспомогательного массива. Шаг 3: Сравните сумму элементов в подмассивах, меньшая сумма будет иметь шанс получить самый высокий оставшийся элемент в массиве, а затем удалить его из контейнера. Шаг 4: Повторяйте шаг 3, пока контейнер не опустеет. Шаг 5: Сравните сумму двух подмассивов, если они одинаковы, верните true, иначе false.
// Сложность этой проблемы заключается в том, что может быть много возможных комбинаций, но у этого алгоритма есть один уникальный способ.
- Несмотря на то, что это NP Complete, это доказывает. Например, тестовый пример: установите S = <3,19,17,8,16,1,2>. Первоначальный чек (сумма% 2) == 0.
Задача @Gal Subset-Sum является NP-Complete и имеет псевдополиномиальный алгоритм динамического программирования O (n * TotalSum). Но эта проблема не NP-Complete. Это особый случай, и его можно решить за линейное время.
Здесь мы ищем индекс, по которому мы можем разделить массив на две части с одинаковой суммой. Проверьте следующий код.
Анализ: O (n), поскольку алгоритм выполняет только итерацию по массиву и не использует TotalSum.
Пробовал другое решение. кроме решений Wiki (Проблема с разделением).
Я тестировал. (Он хорошо работает с положительным числом больше 0), пожалуйста, дайте мне знать, если возникнут какие-либо проблемы.
Это рекурсивное решение проблемы, одно нерекурсивное решение может использовать вспомогательный метод для получения суммы индексов 0 для текущего индекса в цикле for, а другое может получить сумму всех элементов из того же текущего индекса для конец, который работает. Теперь, если вы хотите получить элементы в массив и сравнить сумму, сначала найдите точку (индекс), которая отмечает разлит, где сумма обеих сторон равна, затем получите список и добавьте значения перед этим индексом и другим списком для перехода. после этого индекса.
Вот мой (рекурсия), который только определяет, есть ли место для разделения массива, чтобы сумма чисел на одной стороне была равна сумме чисел на другой стороне. Беспокойство по поводу indexOutOfBounds, которое может легко произойти при рекурсии, небольшая ошибка может оказаться фатальной и привести к множеству исключений и ошибок.
Нашел решение здесь
- 4 Добро пожаловать в Stack Overflow! Пожалуйста, не отвечайте только исходным кодом. Постарайтесь дать хорошее описание того, как работает ваше решение. См .: Как мне написать хороший ответ ?. Благодарность
- Как это решает проблему? Небольшое объяснение действительно улучшит ваш ответ.
Эта функция Python3 разделит и сбалансирует список чисел на два отдельных списка, равных по сумме, если сумма четная.
Неоптимальное решение на питоне,
Во-первых, если элементы являются целыми числами, убедитесь, что общая сумма делится на два без остатка — в противном случае успех невозможен.
Я бы поставил задачу в виде двоичного дерева, где уровень 0 определяет, в какой набор входит элемент 0, уровень 1 определяет, в какой набор входит элемент 1 и т. Д. В любое время, если сумма одного набора составляет половину от общей суммы, вы ' повторно сделано- успех. В любое время, если сумма одного набора превышает половину общей суммы, это поддерево является ошибочным, и вам необходимо выполнить резервное копирование. В этот момент это проблема обхода дерева.
Мне задали этот вопрос в интервью, и я дал ниже простое решение, так как раньше я НЕ видел этой проблемы ни на одном веб-сайте.
Допустим, массив A = <45,10,10,10,10,5>Тогда разделение будет по индексу = 1 (индекс с отсчетом от 0), так что у нас будет два равных набора сумм <45>и
/ * Перемещаем два указателя индекса к середине массива до currentRightIndex! = CurrentLeftIndex. Увеличьте leftIndex, если сумма левых элементов все еще меньше или равна сумме элементов справа от 'rightIndex'. В конце проверьте, если leftSum == rightSum. Если true, мы получили индекс как currentLeftIndex + 1 (или просто currentRightIndex, поскольку currentRightIndex в этом случае будет равен currentLeftIndex + 1). * /
Шаг 1) Разделите массив на два
Шаг 2) Если сумма равна, разделение завершено
Шаг 3) Поменяйте местами один элемент из array1 на array2, руководствуясь четырьмя правилами:
ЕСЛИ сумма элементов в массиве 1 меньше суммы элементов в массиве 2
Правило 1:
Найдите число в массиве 1, которое меньше числа в массиве 2, чтобы при перестановке этих элементов сумма массива 1 не превысила ожидаемую сумму. Если найдено, поменяйте местами элементы и вернитесь.
Правило 2:
Если Rule1 не выполняется, найдите число в array1, которое больше числа в array2, таким образом, чтобы разница между любыми двумя числами в array1 и array2 была не меньше, чем разница между этими двумя числами.
ELSE
Правило 3:
Найдите число в массиве 1, которое больше числа в массиве 2, таким образом, чтобы поменять местами эти элементы, не уменьшая сумму массива 1 сверх ожидаемой суммы. Если найдено, замените
элементы и возврат.
Правило 4:
Если Rule3 не выполняется, найдите число в array1, которое меньше числа в array2, таким образом, чтобы разница между любыми двумя числами в array1 и array2 была не меньше, чем разница между этими двумя числами.
Шаг 5) Переходите к Шагу 2 до тех пор, пока в результате подкачки не будет получен массив с тем же набором элементов, которые уже встречались. Setp 6) Если происходит повторение, этот массив не может быть разделен на две половины с равной суммой. Текущий набор массивов ИЛИ набор, который был сформирован непосредственно перед этим повторением, должен быть лучшим разбиением массива.
Примечание. Используемый подход состоит в том, чтобы поменять местами элементы из одного массива в другой таким образом, чтобы результирующая сумма была как можно ближе к ожидаемой сумме.
Программа Java доступна на Java Code
Пожалуйста, попробуйте это и дайте мне знать, если не сработает. Надеюсь, это поможет вам.
ПЛОХАЯ жадная эвристика для решения этой проблемы: попробуйте отсортировать список от наименьшего к наибольшему и разделить этот список на два, указав list1 = нечетные элементы и list2 = четные элементы.
Как разделить массив
Когда текущий символ не равен предыдущему, ставим дефис.
вообще очень похоже на пример для state-машины, мне, признаться честно, писать её имплементацию лень)
Копировать по одному символу на другую строку, проверять значение, запомнить в двух переменных наличие одного и другого символа. Как только появились оба — в ту другую строку добавить дефис, обе переменные обнулить.
*сделай стринговую переменную со значением «», скажем результат
*конвертни в стринг свой ряд (надо полагать входную)
*сделай 2 перменные равные 0 для «1» и для «0», скажем это ловушки
*разложи стринг в массив
*перебери массив делая +=1 к ловушке в зависимости что попалось и конкатенируй значение к результату, проверяй условие если обе перменные >0 конкать «-» к результату и обнуляй ловушки (всё в одном цикле).
// тут можно и без ловушек, можно начать перебор с не с 0-го а с 1-го элемента массива и проверять предыдущий элемент на похожесть, если непохоже — конкатить «-«
*принти по желанию результат (Тут нет гарантии что последний блок будет держать и 0 и 1, если это не будет «обязательно» во входном ряде)

Помощь с макросом
Дамы и господа, добрый день.
Есть макрос который берет выделенные ячейки и сохраняет их в папку с файлом в виде картинки JPG. Мне надо чтоб сохранял заранее заданный диапазон. Сердцем чую, что ответ довольно прост, но мозгом пока не допер. Вся надежда на ваши светлые умы.


VBA для создания прайс-листа с изображениями
Доброго времени суток!
Не могу не поделиться результатами своих двухнедельных мучений (ну и похвастацца, конечно).
Макрос создаёт прайс (а может и не прайс, смотря какая у вас потребность приключится) с изображениями и их именами из выбранной папки. Высота изображений определяется пользователем на листе и конечные размеры картинок в готовом файле изменяются пропорционально, ячейки подстраиваются под их размер.

Это суть. Дальше — предыстория и вопрос.
Вообще это мой первый макрос. С Excel'ем я давно на "ты", и давно "облизывалась" на макросы, но все к случаю не приходилось. Все эти If'ы и Then'ы повергали меня в ужас. Ну серьёзно, проще формулой.
Но тут подвернулась работа, в которой моих знаний стало явно не хватать, нужен макрос. Пришлось осваивать. И вот, спустя две недели ночных свиданий с ноутом, макрос готов и все пожелания заказчика учтены.
Код, конечно, кривой, хоть и рабочий; большая часть его кусков скопипастщена с разных форумов, но связана воедино и адаптирована лично мной. Поэтому я сияю, как медный таз — "ОНО РАБОТАЕТ!", а поделиться не с кем — домашние спят — не будить же, пошлют ещё.
Ну все, похвасталась, теперь, собственно, вопрос. Пока сидела с этим макросом, суть работы VBA в общих чертах и понятиях, конечно, уловила. Но слишком сумбурно. Если кто знает хорошую литературу или ресурсы, полезные начинающим, посоветуйте, пожалуйста, буду очень благодарна!
Пы.Сы. Фотографировала на бессонницу, уж не обессудьте)
Ответ на пост «Про perl и годовой баланс»

Как сисадмин задумал на бухгалтерше жениться.
Я со своей будущей супругой тогда работал в одной конторе и в одном кабинете. Она бухгалтер, я — сисадмин. Мы только начали как-то общаться и слегка проявлять симпатию. Однажды пили чай вместе, болтали, и она рассказала, что уже неделю делает какую-то нудятину а-ля сведение нескольких огромных таблиц в Excel.
Конкретную задачу за давностью лет уже не вспомню, но примерно суть была в чем: берем строку из первого файла, там есть код транзакции. Во втором и последующих документах есть одна или несколько соответствующих строк этой транзакции, но с другими данными (платеж там на несколько разбит или еще что), при этом код этой строки содержит в себе код исходной, но формат у него другой, и даже несколько разных видов. Нужно найти эти соответствующие строки, посчитать по формуле числа из разных колонок, и если результат не сошелся с исходным файлом — значит чего-то там не бьется, и нужно по этим транзакциям уточнять.
Собственно задачей супруги и было составление списка транзакций и контрагентов, по которым чего-то не хватает. Документы по несколько сотен строчек каждый, и задача повторяется каждый квартал. Времени она на это обычно тратила около недели, головные боли и красные глаза прилагались.
Расспросив подробности и смекнув, что задача абсолютно рутинная, и ее грех не автоматизировать, я ей это и предложил. В итоге получил несколько примеров старых файлов с уже известным результатом потренироваться, приступил к исполнению.
Ну и короче моих знаний VBA и макросов Excel хватило на то, чтобы через пару дней я презентовал ей первый вариант «программы», где достаточно было положить все файлы в одну папку, обозвать нужными именами и нажать кнопочку «Сделать красиво» на форме — и спустя пару минут был готов итоговый файл, удовлетворяющий искомому результату. Список появился, нужные строчки в исходных файлах выделялись цветом, чтобы их можно было легко найти.
Девушка была в восторге, еще бы, потратить две минуты времени на то, что она раньше делала неделю!
Конечно потом нашлось несколько косяков, потом пришла новая форма исходников, я еще несколько раз дорабатывал свой макрос, а потом я уволился с той конторы, мы поженились, стали жить поживать, да иногда эту историю с макросом вспоминать.
Мораль: знание даже основ программирования может пригодиться вам в совершенно непредсказуемых обстоятельствах. Или нет.