Решение нескольких задач от Amazon на примере JavaScript
Доброго времени суток.
Представляю вашему вниманию перевод статьи «Amazon Coding Interview Questions» автора Trung Anh Dang.
В этой статье автор приводит несколько (три, если быть точнее) задач от Amazon (как он утверждает) и свои варианты решений.
После ознакомления с условиями задачи, попробуйте решить ее самостоятельно. Затем сравните свое решение с авторским. Мои решения оказались близкими к авторским, но немного хуже. Если вам покажется, что ваше решение лучше, прошу поделиться им в комментариях.
Итак, поехали.
Задача № 1
Кодирование длин серий или кодирование повторов (run-length encoding) — это быстрый и простой способ кодирования строк. Суть этого алгоритма заключается в замене повторяющихся символов (серии) на один символ и число его повторов. Серией называется последовательность, состоящая из нескольких одинаковых символов. При кодировании строка одинаковых символов, составляющих серию, заменяется строкой, содержащей сам повторяющийся символ и количество его повторов.
Например, строка "AAAABBBCCDAA"
после кодирования повторов будет выглядеть как "4A3B2C1D2A"
.
Реализуйте кодирование и декодирование повторов. Строка для кодирования состоит только из букв, не содержит чисел. Строка для декодирования является валидной.
Решение
Кодирование строки
Решение довольно простое:
const encoding_string = function(string) {
if(string.length === 0) return ''
let currChar = string.charAt(0)
let count = 1
let encoding = ''
for(let i = 1; i < string.length; i++) {
const char = string.charAt(i)
if(char === currChar) count++
else {
encoding += count + currChar
// сброс
count = 1
currChar = char
}
}
encoding += count + currChar
return encoding
}
Декодирование строки
Нам необходимо реализовать две вспомогательные функции:
1. Функцию, проверяющую является ли символ числом:
const isNumber = function(str) {
return /^\d+$/.test(str)
}
2. Функцию, возвращающую количество символов до конца строки:
const addCountAmount = function(string, char, count) {
for(let i = 1; i <= count; i++) {
string += char
}
return string
}
Вот решение:
const decoding_string = function(string) {
if(string.length === 0) return ''
let currCount = 0
let i = 0
let decoding = ''
while(i < string.length) {
const char = string.charAt(i)
if(isNumber(char)) {
const num = +char
currCount = currCount * 10 + num
} else {
decoding = addCountAmount(decoding, char, currCount)
currCount = 0
}
i++
}
return decoding
}
Проверяем решение:
1. Строка "AAAABBBCCDAA"
должна быть преобразована в "4A3B2C1D2A"
:
console.log(encoding_string("AAAABBBCCDAA")) // 4A3B2C1D2A
2. Обратное преобразование:
console.log(decoding_string("4A3B2C1D2A")) // AAAABBBCCDAA
Задача № 2
Есть лестница с N количеством ступеней. За один шаг можно подняться на одну или две ступени. Дано N. Напишите функцию, возвращающую количество уникальных способов подняться по лестнице. Порядок преодоления ступеней не важен.
Например, если N = 4, то существует 5 уникальных способов:
1, 1, 1, 1 2, 1, 1 1, 2, 1 1, 1, 2 2, 2
Что если убрать ограничение на количество ступеней? Например, если X = {1, 3, 5}, мы можем подняться на 1, 3 или 5 ступеней за раз.
Решение
Функция, возвращающая количество уникальных способов подняться по лестнице (с ограничением):
const climb_stairs_1 = function(stairs) {
if(stairs === 1) return 1
if(stairs === 2) return 2
let prev = 1
let curr = 2
for(let i = 2; i < stairs; i++) {
const sum = prev + curr
prev = curr
curr = sum
}
return curr
}
Функция, возвращающая количество уникальных способов подняться по лестнице (без ограничения):
const climb_stairs_2 = function(stairs, nums) {
const dp = Array(stairs + 1).fill(0)
for(let i = 1; i <= stairs; i++) {
// получаем общее количество f(i - x), где x - каждое число в nums
let total = 0
for(let j = 0; j < nums.length; j++) {
const num = nums[j]
// проверяем попадание в диапазон
if(i - num > 0) total += dp[i - num]
}
dp[i] += total
// если i имеется в nums, увеличиваем значение
if(nums.indexOf(i) !== -1) dp[i] += 1
}
// получаем последнее число в dp
return dp[dp.length - 1]
}
Проверяем решение:
console.log(climb_stairs_1(4)) // 5
console.log(climb_stairs_2(4, [1, 3, 5])) // 3
Задача № 3
Дано целое число K и строка S. Нужно найти длину самой длинной подстроки, содержащей не более K разных символов.
Например, дана s = "abcba"
и k = 2
. Самой длинной подстрокой с не более K разных символов является "bcb"
.
Решение
Вот мое решение:
const k_longest_substring = function(string, k) {
let l = 0
let r = 0
const charCount = new Map()
let longestSubstring = ''
while(r < string.length) {
const char = string.charAt(r)
// обновляем счетчик
if(charCount.has(char)) {
charCount.set(char, charCount.get(char) + 1)
} else {
charCount.set(char, 1)
}
// размер charCount равен k
// начинаем двигаться влево до тех пор, пока подстрока не будет содержать не более k разных символов
if(charCount.size > k) {
while(charCount.size > k && l < r) {
const leftChar = string.charAt(l)
const count = charCount.get(leftChar)
if(count === 1) charCount.delete(leftChar)
else charCount.set(leftChar, count - 1)
l++
}
}
const substring = string.substring(l, r + 1)
longestSubstring = substring.length > longestSubstring.length ? substring : longestSubstring
r++
}
return longestSubstring
}
Проверяем решение:
console.log(k_longest_substring("abcba", 2)) // bcb
Легко, не правда ли?
Благодарю за внимание.