Задача №1: сложение массивов

Мы хотим складывать очень большие числа, которые превышают емкость базовых типов, поэтому мы храним их в виде массива неотрицательных чисел.

Нужно написать функцию, которая примет на вход два таких массива, вычислит сумму чисел, представленных массивами, и вернет результат в виде такого же массива.

Пример

ввод

arr1 = [1, 2, 3] # число 123
arr2 = [4, 5, 6] # число 456

вывод

res = [5, 7, 9] # число 579 (допустим ответ с первым незначимым нулем [0, 5, 7, 9])

Решение

<?php

/**
 * Calc arrays sum
 * @param array $a
 * @param array $b
 * @return array
 */
function calcSum(array $a, array $b): array
{
    $res = [];
    $ost = 0;
    while (count($a) > 0 || count($b) > 0) {
        if (count($a)) {
            $digitA = array_pop($a);
        } else {
            $digitA = 0;
        }

        if (count($b)) {
            $digitB = array_pop($b);
        } else {
            $digitB = 0;
        }

        $sum = $digitA + $digitB + $ost;
        $digit = $sum % 10;
        $res[] = $digit;
        $ost = floor($sum / 10);
    }

    if ($ost > 0) {
        $res[] = $ost;
    }

    $res = array_reverse($res);     // 71 ==> 17

    return $res;
}

/////////////////////////////////////////

$a = [1];     # число 1
$b = [2];     # число 2
$res = calcSum($a, $b);
var_dump($res);     // [3] # число 3

echo "n";

$a = [1, 2, 3];     # число 123
$b = [4, 5, 6];     # число 456
$res = calcSum($a, $b);
var_dump($res);     // [5, 7, 9] # число 579 (допустим ответ с первым незначимым нулем [0, 5, 7, 9])

echo "n";

$a = [2, 9, 2, 3];     # число 2923
$b = [7, 5, 6];     # число 756
$res = calcSum($a, $b);
var_dump($res);     // [3, 6, 7, 9] # число 3679

Оценка сложности:

  • алгоритм — О(n)

  • по памяти О(n)


Задача №2: самые популярные элементы массива

Дан массив целых чисел nums и целое число k.

Нужно написать функцию на PHP, которая вынимает из массива k наиболее часто встречающихся элементов.

Пример

ввод

nums = [1,1,1,2,2,3]
k = 2

вывод (в любом порядке)

[1, 2]

Решение #1 (рабочее, но не оптимальное)

Вот функция на PHP для выбора k наиболее часто встречающихся элементов из массива:

<?php

/**
 * AvitoTech task #2: Frequent numbers
 * (not optimal solution, see optimal in freq_nums2.php)
 *
 * Дан массив целых чисел nums и целое число k.
 * Нужно написать функцию на PHP, которая вынимает из массива k наиболее часто встречающихся элементов.
 */

function topKFrequent222($nums, $k) {
    $freq = [];

    foreach ($nums as $num) {
        $freq[$num] = isset($freq[$num]) ? $freq[$num] + 1 : 1;
    }

    arsort($freq);

    $result = array_slice(array_keys($freq), 0, $k);

    return $result;
}

/**
 * Get frequent numbers
 * @param array $arr
 * @param int $limit
 * @return array
 */
function getMaxFreqNums(array $arr, int $limit): array
{
    $freqArr = [];

    foreach ($arr as $num) {
        if (isset($freqArr[$num])) {
            $freqArr[$num] += 1;
        } else {
            $freqArr[$num] = 1;
        }
    }

    arsort($freqArr);

    $res = array_slice(array_keys($freqArr), 0, $limit);

    return $res;
}

var_dump(getMaxFreqNums([1,1,1,2,2,3,3,3,3,3], 2));     // [3, 1]

Как это работает:

  • Подсчитываем частоту каждого элемента в массиве

  • Сортируем массив частот по убыванию

  • Берем первые k ключи (элементы) из отсортированного массива

(warning) Это решение не оптимально, т.к. алг. сложность — O(Nlog(n)) из-за функции сортировки:

Функция arsort в PHP сортирует массив по значению в обратном порядке (от большего к меньшему). Алгоритмическая сложность функции arsort: O(N log N), где N — размер сортируемого массива.

Как решить задачу со временем O(N)? Смотрим решение №2.

Решение #2 (оптимизированное)

Здесь вместо сортировки строим хеш-массив вида:

[<частота> => <элементы>]

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

<?php

/**
 * AvitoTech task #2: Frequent numbers
 * (optimized solution)
 *
 * Дан массив целых чисел nums и целое число k.
 * Нужно написать функцию на PHP, которая вынимает из массива k наиболее часто встречающихся элементов.
 */

/**
 * Get frequent numbers
 * @param array $freqs
 * @param int $limit
 * @return array
 */
function getMaxFreqNums(array $freqs, int $limit): array
{
    $freqArr = [];

    if(!is_array($freqs) || !count($freqs)) {
        return [];
    }

    // [num => frequence]
    foreach ($freqs as $num) {
        if (isset($freqArr[$num])) {                // [1 => 3, 2 => 2, 3 => 4, 4 => 4, 1 => 5]
            $freqArr[$num] += 1;
        } else {
            $freqArr[$num] = 1;
        }
    }

    // [frequence => <nums_array>]
    $tmpArr = [];
    foreach ($freqArr as $num => $freq) {
        $tmpArr[$freq][] = $num;                    // [1 => [5], 2 => [2], 3 => [1], 4 => [3, 4]]
    }

    $freqArr = $tmpArr;

    // count result as slice of $maxArr
    $res = [];

    $freqArrKeys = array_keys($freqArr);
    $maxKey = max($freqArrKeys);

    for ($i = $maxKey; $i >= 0; $i--) {
        $freqs = (isset($freqArr[$i]) ? $freqArr[$i] : []);
        foreach ($freqs as $elem) {
            $res[] = $elem;
            if (count($res) >= $limit) {
                return $res;
            }
        }
    }

    return $res;
}

////////////////////////////////////

echo "n";
var_dump(getMaxFreqNums([], 2));     // []

echo "n";
var_dump(getMaxFreqNums([1], 1));     // [1]

echo "n";
var_dump(getMaxFreqNums([1,1,1,2,2,3,3,3,3,3,3,4,4,4,4,4,5], 2));     // [3, 4]
Tags

Нет Ответов

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Рубрики


Подпишись на новости
👋

Есть вопросы?