Это вопрос для интервью от Google. Сам не могу решить. Может кто-нибудь пролить свет?
Напишите программу для печати последовательности нажатий клавиш так, чтобы она генерировала максимальное количество символов «А». Вам разрешается использовать только 4 клавиши: A, Ctrl+ A, Ctrl+ Cи Ctrl+ V. Допускается только N нажатий клавиш. Все Ctrlсимволы + считаются одним нажатием клавиши, поэтому Ctrl+ A- одним нажатием клавиши.
Так , например, последовательность A, Ctrl+ A, Ctrl+ C, Ctrl+ Vгенерирует два в 4 - й в нажатиях клавиша.
- Ctrl + A - выбрать все
- Ctrl + C - Копировать
- Ctrl + V - это вставить
Я немного по математике. Для любого N, используя x чисел A, one Ctrl+ A, one Ctrl+ Cи y Ctrl+ V, мы можем сгенерировать max ((N-1) / 2) 2 числа A. Для некоторого N> M, то лучше использовать , как много Ctrl+ A«s, Ctrl+ Cи Ctrl+ Vпоследовательности , как это удваивает количество в.
Последовательность Ctrl+ A, Ctrl+ V, Ctrl+ Cне перезапишет существующий выбор. Он добавит скопированный выбор к выбранному.
^A
обычно бывает «выбрать все»,^C
«копировать»,^V
«вставить». Это дает вам представление?Ответы:
Есть решение для динамического программирования. Мы начинаем с того, что 0 ключей может сделать нас 0 A. Затем мы выполняем итерацию
i
доn
, выполняя две вещи: один раз нажав A и нажав выбрать все + копировать, а затем вставитьj
время (на самом делеj-i-1
ниже; обратите внимание на трюк здесь: содержимое все еще находится в буфере обмена, поэтому мы можем вставить его несколько раз без копирование каждый раз). Нам нужно рассмотреть только до 4 последовательных вставок, поскольку select, copy, paste x 5 эквивалентно выделению, копированию, вставке, выделению, копированию, вставке, а последнее лучше, поскольку оставляет нам больше в буфере обмена. Как только мы достиглиn
желаемого результата.Сложность может показаться O (N), но поскольку числа растут экспоненциально, на самом деле это O (N 2 ) из-за сложности умножения больших чисел. Ниже представлена реализация Python. Расчет для N = 50 000 занимает около 0,5 секунды.
В коде
j
представляет собой общее количество клавиш, нажатых после нашей новой последовательности нажатий клавиш.i
На этом этапе у нас уже есть нажатия клавиш, и 2 новых нажатия клавиш переходят в режим выбора и копирования. Таким образом, мы увеличиваемj-i-2
время вставки . Поскольку вставка добавляет к существующей последовательностиdp[i]
A
, нам нужно добавить1
созданиеj-i-1
. Это объясняетj-i-1
во второй-последней строке.Вот некоторые результаты (
n
=> количество пятерок):Я согласен с @SB, что вы всегда должны высказывать свои предположения: мое заключается в том, что вам не нужно дважды вставлять, чтобы удвоить количество символов. Это дает ответ на 7, поэтому, если мое решение неверно, предположение должно быть правильным.
В случае , если кто - то удивляется , почему я не проверка последовательности вида Ctrl+ A, Ctrl+ C, A, Ctrl+ V: Конечный результат всегда будет таким же , как A, Ctrl+ A, Ctrl+ C, Ctrl+ , Vкоторую я бы рассмотреть.
источник
n => result
илиresult => n
? В любом случае, я считаю, что это неправильно. Мы можем ввести 9 As с 7 нажатиями клавиш. Еслиn => result
это определенно неправильно. Количество As, которое вы можете ввести, не может быть меньшеn
.n => result
. Вы говорите: «Мы можем ввести 9 А с помощью 7 нажатий клавиш», и я получаю это. Прочтите «трюк», в котором я только что отредактировал.n
- это сочетания клавиш, которые вам разрешено использовать. Вы должны вычислить, сколько вы можете набрать с помощьюn
нажатия клавиш. Так7 => 7
что смысла нет.O(n)
или дажеO(1)
:).Используя решение Marcog, я нашел образец, который начинается с
n=16
. Чтобы проиллюстрировать это, вот нажатия клавишn=24
доn=29
, я заменил ^ A на S (выбрать), ^ C на C (копировать) и ^ V на P (вставить) для удобства чтения:После начальных 4 As идеальный шаблон - выбрать, скопировать, вставить, вставить, вставить и повторить. Это умножит количество As на 4 каждые 5 нажатий клавиш. Если этот шаблон из 5 нажатий клавиш не может самостоятельно поглотить оставшиеся нажатия клавиш, некоторое количество из 4 шаблонов нажатий клавиш (SCPP) потребляют последние нажатия клавиш, заменяя SCPPP (или удаляя одну из вставок) по мере необходимости. Четыре комбинации нажатия клавиш умножают общую сумму на 3 каждые 4 нажатия.
Используя этот шаблон, вот некоторый код Python, который дает те же результаты, что и решение marcog, но редактирование O (1) : на самом деле это O (log n) из-за возведения в степень, спасибо IVlad за указание на это.
Вычисление e3: в конце списка нажатий клавиш всегда есть от 0 до 4 шаблонов SCPP, поскольку
n % 5 == 4
их 4,n % 5 == 1
3,n % 5 == 2
2,n % 5 == 3
1 иn % 5 == 4
0. Это можно упростить до(4 - n) % 5
.Вычисление e4: общее количество паттернов увеличивается на 1 всякий раз
n % 5 == 0
, когда оказывается, что это число увеличивается ровноn / 5
. Используя разделение этажей, мы можем получить общее количество шаблонов, общее количество дляe4
- это общее количество шаблонов за вычетомe3
. Для тех, кто не знаком с Python,//
это ориентированная на будущее нотация для разделения этажей.источник
n=3000
, так что наверное правильно. (Жаль, что у меня сегодня нет голосов: /)O(1)
поскольку возведение в степень не может быть выполнено за постоянное время. ЭтоO(log n)
.Вот как я подхожу к этому:
учитывая некоторый текст, для его дублирования требуется 4 нажатия клавиш:
Оттуда вы можете подумать о том, чтобы сделать 4 или 5 А, а затем повторить вышеописанное. Обратите внимание, что при выполнении
ctrl + a, c, v, v
будет увеличиваться ваш текст экспоненциально по мере прохождения цикла. Если оставшихся штрихов <4, просто продолжайтеCtrlVКлюч к собеседованию в таких местах, как Google, - это высказать свои предположения и передать свое мнение. они хотят знать, как вы решаете проблемы.
источник
ACVV-VVVVV
ACVV-ACVV-V
Ее можно решить за O (1): как и в случае с числами Фибоначчи, существует формула для вычисления количества напечатанных As (и последовательности нажатий клавиш):
1) Мы можем упростить описание проблемы:
равно
2) Мы можем описать последовательность нажатий клавиш как строку из N символов из {'*', 'V', 'v'}, где 'v' означает [Cv], а '*' означает [Ca] и 'V 'означает [Копия]. Пример: "vvvv * Vvvvv * Vvvv"
Длина этой строки по-прежнему равна N.
Произведение длин Vv-слов в этой строке равно количеству произведенных As.
3) Учитывая фиксированную длину N для этой строки и фиксированное количество слов K, результат будет максимальным, если все слова имеют почти одинаковую длину. Их попарная разница не более ± 1.
Итак, какое оптимальное число K, если задано N?
4) Предположим, мы хотим увеличить количество слов, добавив одно слово длины L, тогда мы должны уменьшить L + 1 раз любое предыдущее слово на одну 'v'. Пример: «… * Vvvv * Vvvv * Vvvv * Vvvv» -> «… * Vvv * Vvv * Vvv * Vvv * Vvv»
Теперь, какова оптимальная длина слова L?
(5 * 5 * 5 * 5 * 5) <(4 * 4 * 4 * 4 * 4) * 4, (4 * 4 * 4 * 4)> (3 * 3 * 3 * 3) * 3
=> Оптимально L = 4.
5) Предположим, у нас есть достаточно большое N, чтобы сгенерировать строку с большим количеством слов длиной 4, но осталось несколько нажатий клавиш; как нам их использовать?
Если осталось 5 или больше: добавьте еще одно слово длиной 4.
Если осталось 0: Готово.
Если осталось 4: мы могли бы либо
а) добавить одно слово длиной 3: 4 * 4 * 4 * 4 * 3 = 768.
б) или увеличьте 4 слова до длины 5: 5 * 5 * 5 * 5 = 625. => Лучше добавить одно слово.
Если осталось 3: мы могли бы либо
a) или добавьте одно слово длиной 3, изменив предыдущее слово с длины 4 на 3: 4 * 4 * 4 * 2 = 128 <4 * 4 * 3 * 3 = 144.
б) увеличить 3 слова до длины 5: 5 * 5 * 5 = 125. => Лучше добавить одно слово.
Если осталось 2: мы могли бы либо
a) или добавьте одно слово длиной 3, изменив предыдущие два слова с длины 4 на 3: 4 * 4 * 1 = 16 <3 * 3 * 3 = 27.
б) увеличить 2 слова до длины 5: 5 * 5 = 25. => Лучше добавить одно слово.
Если остался 1: мы могли бы либо
a) или добавьте одно слово длиной 3, изменив предыдущие три слова с длины 4 на 3: 4 * 4 * 4 * 0 = 0 <3 * 3 * 3 * 3 = 81.
б) увеличить одно слово до длины 5: 4 * 4 * 5 = 80. => Лучше добавить одно слово.
6) А что, если у нас нет «достаточно большого N», чтобы использовать правила из 5)? По возможности мы должны придерживаться плана б)! Строки для маленьких N:
1: "v", 2: "vv", 3: "vvv", 4: "vvvv"
5: «vvvvv» → 5 (план б)
6: «vvvvvv» → 6 (план б)
7: «vvv * vvv» → 9 (план а)
8: «vvvv * vvv» → 12 (план а)
9: «vvvv * Vvvv» → 16
10: «vvvv * Vvvvv» → 20 (план б)
11: «vvv * vvv * vvv» → 29 (план а)
12: «vvvv * Vvv * Vvv» → 36 (план а)
13: «vvvv * Vvvv * Vvv» → 48 (план а)
14: «vvvv * Vvvv * Vvvv» → 64
15: «vvv * Vvv * Vvv * Vvv» → 81 (план а)
…
7) Каково оптимальное количество слов K в строке длины N?
Если N <7, то K = 1, иначе если 6 <N <11, то K = 2; в противном случае: K = ceil ((N + 1) / 5)
Написано на C / C ++ / Java:
int K = (N<7)?(1) : (N<11)?(2) : ((N+5)/5);
А если N> 10, то количество слов длиной 3 будет: K * 5-1-N. Таким образом, мы можем рассчитать количество напечатанных As:
Если N> 10, количество As будет: 4 ^ {N + 1-4K} · 3 ^ {5K-N-1}
источник
Использование CtrlA+ CtrlC+ CtrlVдает преимущество только после 4 'А'.
Поэтому я бы сделал что-то вроде этого (в псевдо-BASIC-коде, поскольку вы не указали правильный язык):
редактировать
источник
Чтобы удвоить количество As, нужно нажать 3 клавиши. Имеет смысл начинать удвоение только тогда, когда у вас уже напечатано 3 или более А. Вы хотите, чтобы последнее разрешенное нажатие клавиши было a, CtrlVчтобы удвоить максимальное число, которое вы можете, поэтому, чтобы выровнять его, мы будем заполнять любые дополнительные нажатия клавиш после первых трех As в начале с большим количеством As.
Редактировать:
Это ужасно, я полностью забегал вперед и не считал несколько паст для каждой копии.
Изменить 2:
Я считаю, что вставка 3 раза является оптимальной, если для этого достаточно нажатий клавиш. За 5 нажатий клавиш вы умножаете свое число As на 4. Это лучше, чем умножение на 3 с помощью 4 нажатий клавиш, и лучше, чем умножение на 5 с помощью 6 нажатий клавиш. Я сравнил это, дав каждому методу одинаковое количество нажатий клавиш, достаточное для того, чтобы каждый из них закончил цикл одновременно (60), позволяя 3-умножителю делать 15 циклов, 4-умножителю делать 12 циклов, а 5- множитель сделать 10 циклов. 3 ^ 15 = 14 348 907, 4 ^ 12 = 16 777 216 и 5 ^ 10 = 9 765 625. Если осталось только 4 нажатия клавиши, сделать 3-множитель лучше, чем вставлять еще 4 раза, по сути, превратив предыдущие 4 множителя в 8-множитель. Если осталось только 3 нажатия клавиши, лучше всего использовать множитель 2.
источник
Предположим, у вас есть x символов в буфере обмена и x символов в текстовой области; назовем это «состояние x».
Давайте несколько раз нажмем «Вставить» (я
m-1
для удобства обозначил это как ), затем «Выбрать все» и «Копировать»; после этой последовательности мы попадаем в «состояние m * x». Здесь мы потратили в общей сложности m + 1 нажатие клавиш. Так что асимптотический рост (по крайней мере) примерно такойf^n
, где f =m^(1/(m+1))
. Я считаю, что это максимально возможный асимптотический рост, хотя я не могу это доказать (пока).Попытка различных значений m показывает, что максимум для f достигается при
m=4
.Воспользуемся следующим алгоритмом:
(не уверен, что это оптимальный вариант).
Количество нажатий A в начале равно 3: если вы нажмете его 4 раза, вы упустите возможность удвоить количество A еще тремя нажатиями клавиш.
Количество нажатий «Вставить» в конце не более 5: если у вас осталось 6 или более нажатий клавиш, вы можете вместо этого использовать «Вставить», «Вставить», «Вставить», «Выбрать все», «Копировать», «Вставить».
Итак, получаем следующий алгоритм:
(не уверен, что это оптимальный вариант). Количество символов после выполнения примерно такое:
3 * pow(4, floor((n - 6) / 5)) * (2 + (n - 1) % 5)
.Примеры значений: 1,2,3,4,5,6,9,12,15,18,24,36,48,60,72,96,144,192,240,288, ...
источник
Далее используется второе редактирование OP, при котором вставка не заменяет существующий текст.
Обратите внимание на несколько вещей:
Таким образом, каждую разумную последовательность нажатий клавиш можно интерпретировать как группу Y, разделенных X, например YYYXYXYYXY. Обозначим через V (s) количество «А», произведенных последовательностью s. Тогда V (nXm) = V (n) * V (m), потому что X по существу заменяет каждый Y в m на V (n) 'A.
Таким образом, проблема копирования и вставки изоморфна следующей проблеме: «используя m + 1 чисел, сумма которых равна Nm, максимизируйте их произведение». Например, когда N = 6, ответ будет m = 1 и числа (2,3). 6 = 2 * 3 = V (YYXYYY) = V (AA ^ A ^ C ^ V ^ V) (или V (YYYXYY) = V (AAA ^ A ^ C ^ V).)
Мы можем сделать несколько наблюдений:
Для фиксированного значения
m
выбираются числаceil( (N-m)/(m+1) )
иfloor( (N-m)/(m+1) )
(в какой бы комбинации ни вычислялась сумма; в частности, вам понадобятся(N-m) % (m+1)
ceils
и остальныеfloor
s). Это потому, что,a < b
,(a+1)*(b-1) >= a*b
.К сожалению, я не вижу простого способа определить значение
m
. Если бы это было мое интервью, я бы предложил два решения на этом этапе:Вариант 1. Перебрать все возможное
m
.n log n
Решение O ( ).Код на C ++:
Вариант 2. Дать
m
возможность получить нецелые значения и найти его оптимальное значение, взяв производную[(N-m)/(m+1)]^m
поm
и решив ее корень. Аналитического решения нет, но корень можно найти, например, методом Ньютона. Затем используйте пол и потолок этого корня в качестве значенияm
и выберите тот, который лучше.источник
источник
Вот мой подход и решение с кодом ниже.
Подходить:
Можно выполнить три различные операции.
Теперь, учитывая три различных операции и их соответствующие выходы, мы должны выполнить все перестановки этих операций.
Предположение:
В некоторой версии этой проблемы говорится, что последовательность нажатий клавиш Ctrl + A -> Ctrl + C -> Ctrl + V перезаписывает выделенное выделение. Чтобы учесть это предположение, нужно добавить только одну строку кода в решение ниже, где для печатаемой переменной в случае 2 установлено значение 0.
Для этого решения
Приведенный ниже код напечатает пару последовательностей, и последняя последовательность будет правильным ответом для любого заданного N. например, для N = 11 это будет правильная последовательность.
При предположении
A, A, A, A, A, C, S, V, V, V, V,: 20:
Без предположения
A, A, A, C, S, V, V, C, S, V, V,: 27:
Легенда нажатия клавиш:
'А' - А
'C' - Ctrl + A
'S' - Ctrl + C
'V' - Ctrl + V
Код:
источник
Используя приемы, упомянутые в ответах выше, математически решение можно объяснить одним уравнением следующим образом:
4 + 4 ^ [(N-4) / 5] + ((N-4)% 5) * 4 ^ [(N-4) / 5]. где [] - наибольший целочисленный множитель
источник
Существует компромисс между печатью мА вручную, а затем использованием Ctrl+ A, Ctrl+ Cи Нм-2 Ctrl+ V. Лучшее решение - посередине. Если максимальное количество нажатий клавиш = 10, лучшим решением будет ввод 5 или 4 А.
попробуйте использовать это. Посмотрите на это http://www.geeksforgeeks.org/how-to-print-maximum-number-of-a-using-given-four-keys/ и, возможно, немного оптимизируйте поиск результатов примерно в середине точка.
источник
Вот мое решение с динамическим программированием без вложенного цикла, которое также выводит фактические символы, которые вам нужно ввести:
Это результат ('a' означает 'CTRL + A' и т. Д.)
источник
Если разрешено N нажатий клавиш, результатом будет N-3.
А -> Н-3
CTRL+ A-> Выбор этих N символов: +1
CTRL+ C-> Копирование этих N символов: +1
Ctrl+ V-> Вставка N символов. : +1 то есть (поскольку мы выбрали все символы с помощью CTRL+ A) Замена этих существующих символов N-3 на скопированные символы N-3 (что заменяет те же символы), и результат будет N-3.
источник
→
. Это улучшит читаемость вашего ответа!