Русский
Русский
English
Статистика
Реклама

Задачи

Из песочницы Как и к чему готовиться на собеседование начинающему iOS-разработчику и не только

21.06.2020 16:16:20 | Автор: admin
Эй, Хаброжитель, приветствую тебя! Буду признателен ко всем твоим фидбэкам.

image

Небольшая предыстория


В 2019 году увлёкся iOS-разработкой и решил попробовать попасть на курс от Mail.ru в их Технопроект с нашим ВУЗом. Закончил данный курс с отличием. Огромное спасибо Диме и Гена за отличный курс. После этого курса начал активно посещать митапы iOS-разработчиков. Летом особо не прогал под iOS. Осенью все же надумал найти работу в этой сфере и развиваться дальше. Решил начать с небольших компаний, поэтому нагуглил топ-100 аутсорс компаний по разработке приложений. Написал всем компаниям, которые находились в Москве.

Из приблизительно 70 компаний ответили около 15 и где-то 3-4 пригласили на интервью.

Первое интервью как и полагалось завалил, ибо не знал, что там будет и как готовиться. На втором интервью выдали тестовое задание, не сложное, но т.к. особого опыта не было, больше времени убил на то, чтобы разобраться как это реализовать и к дедлайну не успел написать полностью рабочий код. Огромное спасибо ребят, с которыми было первое интервью, потому что они скинули материалы и список теоретических вопросов, которые нужно знать. На третьем собесе ребята сказали, что у них сейчас нет возможности, т.к. им срочно нужно закончить проект и что они готовы взять где-то через месяц, если захочу или же не найду другую работу.

В это время нашел курс по iOS-разработке от Яндекса и прошел его.

Собеседования в Яндексе


В начале декабря был на митапе в Яндексе для джунов. Всем гостям раздали QR-коды для прохождения первого алгоритмического собеса. Там было 3 задачи на 2 часа без перерыва.

Задачи:

  1. Вводится n и нужно посчитать сумму всех чисел от 1 до n < 1000000, где цифры не встречаются более одного раза.
  2. Есть доска M x N (2<M,N<1000000) есть белая и черная лошадь. На входе начальная точка черной и белой лошади. Нужно совершить минимальное кол-во ходов, чтобы они оказались в одной точке и вывести это кол-во.
  3. Вводиться 2 числа N-кол-во чисел в массиве и M-сумма подмассива. Нужно найти подмассив с минимальным кол-во чисел, сумма которой равнялась M, в противно случае нужно вывести что-то другое (не помню).

Есть ограничения по времени и по памяти.

Пока ждал результаты получил оффер в другую компанию, попросил у них неделю на обдумывание, и в последний день этой недели получил письмо от Яндекса. В письме говорилось, что успешно прошел первый этап и приглашают на второй собес. К большому сожалению, не уточнили какая секция будет алгоритмическая или платформенная. Т.к. поверил в свои силы решил отказаться от оффера и приостановить все другие собесы и отдаться на подготовку и прохождения в Яндекс. Достал книжку cracking coding interview, из которой решал задачки в ноябре и стал прорешивать все задачи без ноута на листочке, и забил на универ, чтобы успеть за эту недели. Не хватило времени на все задачи, а последний день перед интервью поботал платформенную часть.

Второе собеседование: В начале собеса сказали, что сейчас будет алгоритмическая секция. Интервью проводил Валера из команды Диска. Собес был суперским, очень понравилось.

Задачи: Сначала поговорили обо всем о чем можно было бы пообщаться на эту тему (Чем отличаются статические языки от динамических?, пару вопрос про каждый тип языков, классы, структуры, стек, куча, массив, список, хеш-таблица, очереди, деревья, графы, про сложности алгоритма, и т.д.). Потом перешли на решение задач.

  1. Есть пять человек: Т, М, А, Л, Д. Они стоят в очереди за магической колой, т.е. тот, кто выпивает его удваивается. На входе n номер следующего, кто должен выпить колу. Нужно найти того, кто будет n-ным.

    Идея решения
    Лучшее решение это hashmap, сам решил через арифметику, т.е. вывел формулу, которая посчитала бы это. //Рассказал всю идею того, как решал бы, потом дал оценку по времени и по памяти, а когда начал писать код, то интервьюер сказал, что он все понял и что код я ему точно напишу так, что давай перейдём к следущей задаче, т.к. у нас осталось чуть больше 20 минут
  2. Есть бинарное дерево поиска. Нужно найти сумму элементов лежащих в сегменте от L до R. Функция на вход получает корневой элемент, левую и правую границу. Тогда уточнил и узнал, что элементы не повторяются и границы включены.

    Идея решения
    Делал через рекурсию. (можно через цикл, но рекурсия проще), опять же сложность алгоритма и т.д.

Где-то ближе к новому году получил письмо об успешном прохождении данного этапа. В 20х числах января связался с HR-ом она сказала, что осталось последнее собеседование (платформенная секция) и назначили дату на следущий день после последнего экзамена. В новогодние праздники и во время сессии готовился еще к собесу. Одним словом было сложно готовится и к экзамена, и к собесу.

Пришел на собес, его проводил Слава из Браузера. Немного пообщались об алгоритмической секции. Дальше он попросил написать схематично код, который реализовывал бы работу многопоточности. Так как до это особо не приходилось работать с многопоточностью, то за счет неожиданности попал в ступор минут на 20-30, просто не думал, что придется писать код. По теории отвечал не плохо, но были проблемы с реализацией. При всем при этом собес очень понравился. Мы не успели реализовать то, что он просил, поэтому Слава предложил дорешать, и нам пришлось сделать это в коридоре, потом немного пообщались. Это было суперски, потому что некоторые ребята ориентируются строго по времени. Через недели две написали, что провалил собес. Было очень обидно т.к. готовился и очень-очень сильно хотел попасть.

Огромный минус собеседований в Яндексе заключается в том, что им неважно попадешь ли ты к ним или нет. Из-за чего они часто игнорят тебя или забывают написать письмо с результатом/(о назначении) собеседования и тебе самому приходится постоянно писать/звонить, чтобы что-то узнать.

Собеседование в МегаФоне


Самое лайтовое и немного не понятное собеседование из всех, что приходилось проходить в крупных компаниях. Собес длился где-то минут 20-30. Пообщались о том, что умею, чем увлекаюсь, какие оценки получаю в универе и т.д. Не было ни одного вопроса по платформе и алгоритмам. Этот собес, скорее всего, тоже не прошел, ибо никакой информации не получил.

Потом общался со многими, компаниями, но из-за того, что нет коммерческого опыта большинство компании теряли интерес и не приглашали на интервью. Наконец-то, где-то в 20х числах марта некоторые компании назначили собес, но потом из-за сложившейся ситуации с самоизоляцией пришлось их приостановить на неопределенное время.

Самоизоляция говорит: Нет очным собеседованиям!

image

Собеседование в Сбербанк


Было два телефонных интервью, где рассказывал о своих интересах, о том почему решил попробовать попасть в Сбербанк, пару теоретических вопросов связанных с iOS и в общем о программировании. Первое и второе интервью прошел, назначили дату для прохождения очного (последнего этапа) собеса, который из-за режима самоизоляции провели по скайпу. Отлично провели собес со Славой, просто пообщались полностью по платформенной части. Через пару дней пришло письмо о том, что успешно прошел собес, но в данной команде нет месте, поэтому предложат кандидатуру в другую команду. Через 2-3 дня пришло еще одно письмо о том, что набор на стажировку у них закрылся.

Собеседование в ВТБ


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

Прошел их успешно, потом провели заключительный этап собеседования с Мишей. Т.к. сказали, что будет просто платформенная часть и вряд ли будет что-то еще, то особо не готовился. На интервью общались с Мишей об алгоритмах, о структурах, о сети, о многопоточности и т.д. Интервью проходило больше часа, но было очень интересно и классно.

Где-то через неделю позвонили и поздравили с успешным прохождением отбора на стажировку.
На днях подписал договор и получил пропуск и технику. Стажировка должна была пройти в офисе, но в поседений момент все же, к огромному сожалению, перевели на удаленку.

Заключение


Параллельно проходил курс по iOS-разработке на CoursEra, но из-за того, что сейчас началась сессия и стажировка, пришлось приостановить активность на CoursEra.

Советы, которые могут помочь при поиске первой работы в IT


  1. Нужно хорошо разбираться в теории, ибо научиться кодить не сложно.
  2. Откликайтесь на вакансии middle/senior, т.к. найти вакансию intern/junior почти невозможно найти.
  3. Если есть возможность попасть на собеседование, то идите, потому что это поможет вам поднять ваши скилы. (Даже если мало что знаете)
  4. Изучите компанию, в которой будете проходить собеседование и покажите интервьюеру свою заинтересованность работать у них.
  5. Обязательно спрашивайте о том, что вас лично интересует и что хотели бы узнать о рабочем процессе.
  6. Когда чего-то не знаете или не помните, то задавайте уточняющие вопросы, они вам помогут. Если не смогли вспомнить, то просто скажите об это.
  7. Думайте открыто, ведь интервьюер больше смотрит на то, как вы думаете и как ищете выход при сложившихся ситуациях. Если вы просто скажете ответ, то это ни о чем не говорит. Когда вы открыто рассуждаете, то интервьюер видит где вы ошиблись и помогает вам, задавая наводящие вопросы.
  8. Прежде чем пойти на собеседование отрепетируйте его. Задавайте себе всякие вопросы связанные с тем, что должно быть и постарайтесь внятно ответить на них.

Совет компаниям


Когда вы проводите собеседования у стажеров/джунов, то давайте им какие-нибудь ссылки, где как минимум есть темы, в которых начинающий разработчик и не только должен хорошо разбирать. Из своего опыт скажу, что мне очень сильно помогли материалы, скинуты ребятами у которых было самое первое интервью. Там были только не расписанные темы, которые являются основами и ребята сказали в какой последовательность лучше изучить их.

Если будут желающие, то сделаю еще пост с самыми популярными и важными вопросами + ответы и материалы к ним.
Подробнее..

50200 вопросов по JavaScript

06.07.2020 10:05:56 | Автор: admin


Доброго времени суток, друзья!

Предлагаю Вашему вниманию небольшой интерактив своего рода викторину по JavaScript, на данный момент состоящую из 50 вопросов.

На мой взгляд, решение подобных задач лучший способ определить свой уровень мастерства.

Предисловие


Данная часть основана на этом репозитории. Его автор, Lydia Hallie, позиционирует свой проект как список продвинутых вопросов и, действительно, среди них есть такие, которые, как мне кажется, даже опытному JavaScript-разработчику покажутся непростыми. Однако среди этих вопросов есть и такие, для ответа на которые достаточно владеть базовыми знаниями. В репозитории имеется русский перевод, но, мягко говоря, он оставляет желать лучшего, поэтому большую часть ответов (объяснений) пришлось переводить заново.

Следует отметить, что приводимые пояснения (ответы) не всегда в полной мере раскрывают суть проблемы. Это объясняется формой проекта он представляет собой чеклист, а не учебник. Ответы, скорее, являются подсказкой для дальнейших поисков на MDN или Javascript.ru. Впрочем, многие из объяснений содержат исчерпывающие ответы.

Несмотря на то, что код неоднократно протестирован, никто не застрахован от ошибок, разумеется, кроме тех, кто ничего не делает. Поэтому при обнаружении ошибок, опечаток, неточностей, некорректности формулировок и т.п., а также при желании улучшить перевод, прошу писать в личку, буду признателен (активность на GitHub также приветствуется).

Собственно, это все, что я хотел сказать в качестве предисловия.

Правила


Правила простые: 50 вопросов, 3-4 варианта ответа, рейтинг: количество правильных и неправильных ответов, прогресс: номер и количество вопросов.

По результатам определяется процент правильных ответов и делается вывод об уровне владения JavaScript: больше 80% отлично, больше 50% неплохо, меньше 50% ну, Вы понимаете.

К каждому вопросу прилагается пояснение. При неправильном ответе данное пояснение раскрывается.

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

Но довольно слов, пора переходить к делу.

Викторина



Код проекта находится здесь.

Механика


Несколько слов о том, как реализована викторина для тех, кому интересно.

Разметка выглядит так:

<head>    <meta charset="UTF-8">    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <title>200+ вопросов по JavaScript</title>    <!-- шрифт -->    <link href="http://personeltest.ru/aways/fonts.googleapis.com/css2?family=Ubuntu&display=swap" rel="stylesheet">    <!-- стили -->    <link rel="stylesheet" href="style.css">    <!-- основной скрипт с типом "модуль" -->    <script type="module" src="script.js"></script></head><body></body>

Добавляем минимальные стили.
CSS:
* {    margin: 0;    padding: 0;    box-sizing: border-box;    font-family: Ubuntu, sans-serif;    font-size: 1em;    text-align: center;    letter-spacing: 1.05px;    line-height: 1.5em;    color: #111;    user-select: none;}@media (max-width: 512px) {    * {        font-size: .95em;    }}html {    position: relative;}body {    padding: 1em;    min-height: 100vh;    background: radial-gradient(circle, skyblue, steelblue);    display: flex;    flex-direction: column;    justify-content: start;    align-items: center;}h1 {    margin: .5em;    font-size: 1.05em;}output {    margin: .5em;    display: block;}.score {    font-size: 1.25em;}form {    text-align: left;}form p {    text-align: left;    white-space: pre;}form button {    position: relative;    left: 50%;    transform: translateX(-50%);}button {    margin: 2em 0;    padding: .4em .8em;    outline: none;    border: none;    background: linear-gradient(lightgreen, darkgreen);    border-radius: 6px;    box-shadow: 0 1px 2px rgba(0, 0, 0, .4);    font-size: .95em;    cursor: pointer;    transition: .2s;}button:hover {    color: #eee;}label {    cursor: pointer;}input {    margin: 0 10px 0 2em;    cursor: pointer;}details {    font-size: .95em;    position: absolute;    bottom: 0;    left: 50%;    transform: translateX(-50%);    width: 90%;    background: #eee;    border-radius: 4px;    cursor: pointer;}details h3 {    margin: .5em;}details p {    margin: .5em 1.5em;    text-align: justify;    text-indent: 1.5em;}.right {    color: green;}.wrong {    color: red;}


Исходники (assets) представляют собой массив объектов, где каждый объект имеет свойства question (вопрос), answers (ответы), rightAnswer (правильный ответ) и explanation (объяснение):

[{    question: `        function sayHi() {            console.log(name);            console.log(age);            var name = "Lydia";            let age = 21;        }        sayHi();    `,    answers: `        A: Lydia и undefined        B: Lydia и ReferenceError        C: ReferenceError и 21        D: undefined и ReferenceError    `,    rightAnswer: `D`,    explanation: `        Внутри функции мы сначала определяем переменную name с помощью ключевого слова var. Это означает, что name поднимется в начало функции. Name будет иметь значение undefined до тех пор, пока выполнение кода не дойдет до строки, где ей присваивается значение Lydia. Мы не определили значение name, когда пытаемся вывести ее в консоль, поэтому будет выведено undefined. Переменные, определенные с помощью let (и const), также поднимаются, но в отличие от var, не инициализируются. Доступ к ним до инициализации невозможен. Это называется "временной мертвой зоной". Когда мы пытаемся обратиться к переменным до их определения, JavaScript выбрасывает исключение ReferenceError.    `},...]

Основной скрипт.
JavaScript
// импортируем массив объектов - исходникиimport assets from './assets.js'// IIFE;((D, B) => {    // заголовок - вопрос    const title = D.createElement('h1')    B.append(title)    // рейтинг: количество правильных и неправильных ответов    const score = D.createElement('output')    score.className = 'score'    B.append(score)    // прогресс: порядковый номер вопроса    const progress = D.createElement('output')    progress.className = 'progress'    B.append(progress)    // контейнер для вопроса, вариантов ответа и кнопки для отправки формы    const div = D.createElement('div')    B.append(div)    // получаем значения правильных и неправильных ответов из локального хранилища    // или присваиваем переменным 0    let rightAnswers = +localStorage.getItem('rightAnswers') || 0    let wrongAnswers = +localStorage.getItem('wrongAnswers') || 0    // получаем значение счетчика из локального хранилища    // или присваиваем ему 0    let i = +localStorage.getItem('i') || 0    // рендерим вопрос    showQuestion()    // обновляем рейтинг и прогресс    updateScoreAndProgress()    function showQuestion() {        // если значение счетчика равняется количеству вопросов        // значит, игра окончена,        // показываем результат        if (i === assets.length) {            return showResult()        }        // заголовок-вопрос зависит от значения счетчика - номера вопроса        switch (i) {            case 4:                title.textContent = `Что не является валидным?`                break;            case 9:                title.textContent = `Что произойдет?`                break;            case 12:                title.textContent = `Назовите три фазы распространения событий`                break;            case 13:                title.textContent = `Все ли объекты имеют прототипы?`                break;            case 14:                title.textContent = `Каким будет результат?`                break;            case 20:                title.textContent = `Чему равно sum?`                break;            case 21:                title.textContent = `Как долго будет доступен cool_secret?`                break;            case 23:                title.textContent = `Каким будет результат?`                break;            case 25:                title.textContent = `Глобальный контекст исполнения создает две вещи: глобальный объект и this`                break;            case 27:                title.textContent = `Каким будет результат?`                break;            case 29:                title.textContent = `Каким будет результат?`                break;            case 30:                title.textContent = `Что будет в event.target после нажатия на кнопку?`                break;            case 33:                title.textContent = `Каким будет результат?`                break;            case 34:                title.textContent = `Какие из значений являются "ложными"?`                break;            case 38:                title.textContent = `Все в JavaScript это`                break;            case 39:                title.textContent = `Каким будет результат?`                break;            case 40:                title.textContent = `Каким будет результат?`                break;            case 41:                title.textContent = `Что возвращает setInterval?`                break;            case 42:                title.textContent = `Каким будет результат?`                break;            case 42:                title.textContent = `Каково значение num?`                break;            case 49:                title.textContent = `Каким будет результат?`                break;            default:                title.textContent = `Что будет выведено в консоль?`                break;        }        // поскольку каждый элемент массива - это объект,        // мы можем его деструктурировать, получив вопрос, правильный ответ и объяснение        const {            question,            rightAnswer,            explanation        } = assets[i]        // поскольку варианты ответа - это input type="radio",        // строку необходимо преобразовать в массив (критерием является перенос строки - \n)        // первый и последний элементы - пустые строки,        // избавляемся от них с помощью slice(1, -1),        // также удаляем пробелы        const answers = assets[i].answers            .split('\n')            .slice(1, -1)            .map(i => i.trim())        // HTML-шаблон        const template = `        <form action="#">            <p><em>Вопрос:</em><br> ${question}</p>            <p><em>Варианты ответов:</em></p><br>            ${answers.reduce((html, item) => html += `<label><input type="radio" name="answer" value="${item}">${item}</label><br>`, '')}            <button type="submit">Ответить</button>        </form>        <details>            <summary>Показать правильный ответ</summary>            <section>                <h3>Правильный ответ: ${rightAnswer}</h3>                <p>${explanation}</p>            </section>        </details>`        // помещаем шаблон в контейнер        div.innerHTML = template        // находим форму        const form = div.querySelector('form')        // выбираем первый инпут        form.querySelector('input').setAttribute('checked', '')        // обрабатываем отправку формы        form.addEventListener('submit', ev => {            // предотвращаем перезагрузку страницы            ev.preventDefault()            // определяем выбранный вариант ответа            const chosenAnswer = form.querySelector('input:checked').value.substr(0, 1)            // проверяем ответ            checkAnswer(chosenAnswer, rightAnswer)        })    }    function checkAnswer(chosenAnswer, rightAnswer) {        // индикатор правильного ответа        let isRight = true        // если выбранный ответ совпадает с правильным,        // увеличиваем количество правильных ответов,        // записываем количество правильных ответов в локальное хранилище,        // иначе увеличиваем количество неправильных ответов,        // записываем количество неправильных ответов в локальное хранилище        // и присваиваем индикатору false        if (chosenAnswer === rightAnswer) {            rightAnswers++            localStorage.setItem('rightAnswers', rightAnswers)        } else {            wrongAnswers++            localStorage.setItem('wrongAnswers', wrongAnswers)            isRight = false        }        // находим кнопку        const button = div.querySelector('button')        // если ответ был правильным        if (isRight) {            // сообщаем об этом            title.innerHTML = `<h1 class="right">Верно!</h1>`            // выключаем кнопку            button.disabled = true            // через секунду вызываем функции            // обновления рейтинга и прогресса и рендеринга следующего вопроса            // отключаем таймер            const timer = setTimeout(() => {                updateScoreAndProgress()                showQuestion()                clearTimeout(timer)            }, 1000)            // если ответ был неправильным        } else {            // сообщаем об этом            title.innerHTML = `<h1 class="wrong">Неверно!</h1>`            // выключаем инпуты            div.querySelectorAll('input').forEach(input => input.disabled = true)            // раскрываем объяснение            div.querySelector('details').setAttribute('open', '')            // меняем текст кнопки            button.textContent = 'Понятно'            // по клику на кнопке вызываем функции            // обновления рейтинга и прогресса и рендеринга следующего вопроса            // удаляем обработчик            button.addEventListener('click', () => {                updateScoreAndProgress()                showQuestion()            }, {                once: true            })        }        // увеличиваем значение счетчика        i++        // записываем значение счетчика в локальное хранилище        localStorage.setItem('i', i)    }    function updateScoreAndProgress() {        // обновляем рейтинг        score.innerHTML = `<span class="right">${rightAnswers}</span> - <span class="wrong">${wrongAnswers}</span>`        // обновляем прогресс        progress.innerHTML = `${i + 1} / ${assets.length}`    }    function showResult() {        // определяем процент правильных ответов        const percent = (rightAnswers / assets.length * 100).toFixed()        // объявляем переменную для результата        let result        // в зависимости от процента правильных ответов        // присваиваем result соответствующее значение        if (percent >= 80) {            result = `Отличный результат! Вы прекрасно знаете JavaScript.`        } else if (percent > 50) {            result = `Неплохой результат, но есть к чему стремиться.`        } else {            result = `Вероятно, вы только начали изучать JavaScript.`        }        // рендерим результаты        B.innerHTML = `        <h1>Ваш результат</h1>        <div>            <p>Правильных ответов: <span class="right">${rightAnswers}</span></p>            <p>Неправильных ответов: <span class="wrong">${wrongAnswers}</span></p>            <p>Процент правильных ответов: ${percent}</p>            <p>${result}</p>            <button>Заново</button>        </div>        `        // при нажатии на кнопку        // очищаем хранилище        // и перезагружаем страницу,        // удаляем обработчик        B.querySelector('button').addEventListener('click', () => {            localStorage.clear()            location.reload()        }, {            once: true        })    }})(document, document.body)


Благодарю за внимание, друзья.

Продолжение следует
Подробнее..

Тотальный JavaScript изучаем JS с акцентом на практической составляющей

22.02.2021 16:14:10 | Автор: admin


Доброго времени суток, друзья!

Когда речь заходит об изучении JavaScript, будь то первое знакомство с языком или углубление имеющихся знаний, найти в интернетах теоретические материалы не составляет особого труда. Мой топ-5:


Однако, когда дело касается практических аспектов JavaScript, информацию приходится собирать буквально по крупицам. Собственно, этим я и занимался на протяжении последних 4-5 месяцев.

Предлагаю вашему вниманию Тотальный JavaScript.

Вот что вы найдете в этом репозитории:

  • Огромное количество сниппетов (утилит, вспомогательных функций), разделенных по типам данных не могу назвать точного количества (порядка 4000 строк кода без комментариев и пробелов). Следует отметить, что не все функции являются настоящими сниппетами с точки зрения возможности их использования (как есть) в реальных приложениях, некоторые всего лишь эксперименты, демонстирующие те или иные (безграничные?) возможности языка. Коллекция все время пополняется
  • 230 практических вопросов приводится пример кода, необходимо выполнить его в уме и решить, что будет выведено в консоль. Конечно, на практике мы редко занимается чем-то подобным, ведь гораздо легче и, главное, быстрее законсолить кусок подозрительного кода. Однако, на мой взгляд, умение решать подобные задачи как нельзя лучше демонстрирует понимание основных принципов и характерных особенностей работы JavaScript. В качестве недостатка этого раздела отмечу почти полное отсутствие вопросов по классам и this. Постараюсь в ближайшем будущем его устранить
  • 68 задач разного уровня сложности подборка задач из учебника Ильи Кантора (большинство), немного адаптированных под нужды реальных приложений. Структура раздела, в основном, следует структуре учебника с небольшими лирическими отступлениями
  • Паттерны проектирования подробное описание и примеры всех паттернов, которые называет Банда Четырех в своей книге Паттерны объектно-ориентированного программирования, на JavaScript (также в разделе имеются примеры на TypeScript смотрите исходный код). При подготовке данного раздела многое позаимствовано у Refactoring Guru, за что ему (или им) огромное спасибо
  • Что за черт, JavaScript? список тонких моментов работы JavaScript. Этот раздел не слишком актуален, учитывая возможности современного JS, однако интересен тем, что позволяет узнать, каким был язык раньше, до того, как завоевал мир веб-разработки. Де факто, он остается прежним, но следование простым правилам (например, использование const или let вместо var или "===" вместо "==") позволяет решить большую часть проблем, с которыми сталкивались разработчики в прошлом

Уверен, что каждый найдет для себя что-нибудь интересное.

Также в репозитории имеется ссылка на приложение с вопросами (список и интерективная викторина) и задачами. Оно вполне работоспособное (и даже прогрессивное), но, признаюсь, нуждается в существенной переработке. Займусь этим, когда появится свободное время.

Как всегда, буду рад любой форме обратной связи. При обнаружении опечаток, ошибок, неточностей и, особенно, неработающего кода (код протестирован, но никто не застрахован от ошибок) не стесняйтесь писать в личку и делать пуллы.

Благодарю за внимание. Всех, кому дым отечества и сладок, и приятен, с наступающим праздником.
Подробнее..

Opener 2020 Самый сок

23.06.2020 16:19:11 | Автор: admin

Введение


На протяжении всего апреля мы с командой после учёбы и работы решали увлекательные задачи в рамках конкурса Opener от компании Itransition. Вместе с конкурсом закончился наш лучший месяц на самоизоляции. Теперь, отдохнув, я готов спокойно поделиться этим опытом с вами.

Opener это ежегодный открытый интеллектуальный конкурс для студентов, аспирантов и магистрантов Республики Беларусь (по крайней мере на призы претендовать могут только они), а участвовать все, кто захочет. Данный конкурс проходит уже 8 лет. В этом году был добавлен командный зачёт со своими дополнительными задачами.

Призовой фонд конкурса составил 12 Apple Ipad Pro для личного и $4000 для командного зачётов. Наша команда, состоящая из Артура (petuhovskiy), Вячеслава, Игоря (lodthe), Кирилла и меня выиграла 4 Ipada.

Мы добрались практически до самого конца конкурса, и я бы хотел показать вам, какие задачи показались нам самыми интересными. Надеюсь, что прочитав ход решения, посмотрев на командную работу в Google таблицах, увидев скриншоты, вы осознаете уровень проработки задач и не сможете не сказать: Вау!

В конце статьи вас ждёт задача попробуйте её решить!



Основная часть


Как всё начиналось


Стоит заметить, что я уже принимал участие в данном конкурсе в 2019 году. Узнал о нём я совершенно случайно и решил первых задач 10 на парах. Спустя год мне на почту пришло письмо-приглашение. Теперь я знал чего ожидать и меня это не заинтересовало, ведь конкурс самый настоящий марафон на месяц. Я просто поделился письмом и ссылкой на регистрацию с подписчиками своего канала в Telegram.

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

Команды от трёх человек, максимум пять. Мы поставили в чат себе уведомление на день начала конкурса и успешно про всё забыли. В последний день регистрации хотелось укомплектовать команду полностью, но на примете никого не было. Игорь написал своим знакомым с предложением поучаствовать, не надеясь на положительный ответ, однако, именно так к команде присоединился Артур и Кирилл. Примечательно то, что последний участник зарегистрировался за минуту до окончания формирования команд.

Артур, Игорь, Кирилл и Слава учатся в Высшей Школе Экономики, в школьные годы увлекались спортивным программированием в Республике Беларусь.

Организационные моменты


Официальная группа конкурса находится в ВК. Именно там, в обсуждениях, можно было попросить помощи от организаторов, если совсем был ступор. Подсказки были совершенно разными. Это и музыкальные отрывки, и четверостишия, и просто какие-то намёки, отсылки. Все конкретные и важные подсказки переносились в отдельную тему, а на стене мелькали полезные ссылки. Только погрузившись в общение с другими участниками и организаторами в этой группе, можно было получить максимальное количество полезной информации. Этим я и занимался, сидя с фейка и максимально прикалываясь. Я рофлил, добавляя креатива в сообщения, команда рофлила с моих сообщений и сама их иногда не понимала, организаторы награждали меня подсказками. Родились мемные фразы, которые мы употребляем до сих пор. Вот некоторые из них:

  • Опять таблетки забыли принять?
  • Последовательность бык
  • Где???
  • Вы вопрос задайте
  • Подумать, нет?


Telegram бот, координирование команды


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

Мало того, что это очень удобно (ведь мы получали уведомления и были в курсе всего), так ещё и получилась система логирования всех исправлений как участников, так и организаторов. Это помогало получить дополнительную информацию, так как организаторы затирали в вопросах участников слова, которые могли хоть как-то намекнуть куда копать. Подсказки вообще могли молча обновляться, а бот всегда держал нас в курсе.

Общение команды шло через чат. К тому времени я написал бота для интеграции Zoom в Telegram, он был на хайпе и мы им активно пользовались, но где-то в середине месяца они опять вернули своё ограничение на 40 минут конференции и мы перешли в Discord, так как любили засесть ночью на часика четыре.

Все записи, касающиеся задач, были представлены отдельными страницами в таблице Notion. Это было удобно: когда кто-то уходил спать, утром он смотрел, что другие решили ночью. Так же без этих заметок не получилось бы написать эту статью.



Задачи


Как я уже упомянул во введении, задачи делятся на два типа: командные и личные. Одновременно можно было решать задачи обоих типов, но командные задачи были заблокированы для просмотра, пока не решены предыдущие из личного или командного зачётов. Удивительно то, что организаторы не запрещали, а даже открыто заявляли, что задачи личного зачёта можно решать вместе с командой (при её наличии, конечно же). Ими было введено ограничение, которое не позволяло забрать больше четырёх айпадов на одну команду. Мы посчитали, что решать всем вместе будет рациональнее. Так и поступили.

Конечно, выходило и так, что мы застревали на командных задачах, но продолжали решать их из личного зачёта. Чаще всего выходило, что они были более интерактивными и многоэтапными. Все задачи, описанные ниже, с выездом на локацию в Минске, как раз и являются командными. Олимпиадникам больше понравились личные задачи, тогда как я просто тащился от командных. На протяжении всего конкурса я ждал реквизит, про который говорилось в правилах конкурса, но эти задачи были заменены на примитивные из-за пандемии, которые решались за несколько минут. Поняли мы это благодаря открытой корневой папки CloudFronta, получив все приложения задач ещё в самом начале конкурса. Так же это дало нам понимание о количестве задач, что предстоит решить. После конкурса я узнал, что никто не справился с абсолютно всеми задачами, а именно на последней и нужен был реквизит.

Ниже я описываю ход решения четырёх интересных задач, которые состоят только из изображений без дополнительного текстового сопровождения. А в конце статьи вас ждёт увлекательная и несложная задачка, на которую мы потратили около суток, несмотря на то, что Python является моим основным языком. При должных знаниях, решение придумывается сразу. По крайней мере понятно, что и как будет, но вот до конца довести сложнее.

Задача с 104 гифками


Исходными данными к задаче является архив, содержащий в себе 104 GIF файла с разными названиями. Название каждого файла имеет префикс part_. Название архива by8_128x128px_2layers.zip. Сразу замечаем, что это никакие не гифки, а просто изображения. Перегоняем в другой формат:


Разбираемся с названием файла и трактуем его следующим образом: здесь 2 слоя по 4 картинки. Замечаем рамки у изображений, пишим код на Python с использованием PIL, который без пересечений будет склеивать изображения, получаем 52 уголка:


Отказываемся от идеи пытаться склеить это автоматически и рейдим всей командой Google таблицу. Слава загружает все эти изображения, а мы их растаскиваем по 4 углам, а потом пытаемся соединить:


Подсказка: Если вы дошли до слов, то нужно найти одинокие буквы по столбикам

Слишком очевидная подсказка, к счастью, коих было мало. Составляем куски фразы, а потом и саму фразу:


Получаем: самое малое положительное с количеством разных делителей более десяти млрд, находим в интернете замечательную табличку:


Собираем число, вставляем в любимый Python и получаем ответ!

2**9 * 3**5 * 5**3 * 7**2 * 11**2 * 13**2 * 17**2 * 19**1 * 23**1 * 29**1 * 31**1 * 37**1 * 41**1 * 43**1 * 47**1 * 53**1 * 59**1 * 61**1 * 67 * 71 * 73 * 79 * 83 * 89 * 97 * 101

Ответ: 2054221614063184107682218077003539824552559296000

Задача с девочками



Подсказка: Цвета какие-то ненатуральные, явно отфотошопил девчонок кто-то

Отличная подсказка, с неё мы и начали решать эту задачу, сами незаметив. Я начал со стенографии, усердно пытаясь достать хоть что-то, но все попытки были тщетны. Была идея поиграться с ползунками в фотошопе, как-то выровнять баланс цветов, приблизить к натуральным, но нет. Заметили, конечно, и пятна из разных цветов. Выделили их более яркими не помогло.


Спустя некоторое время получаем подсказку в качестве кода на Ruby:

def h(a);     a.reduce(Hash.new(0)) {|h,e|h[e]+=1;h};end

Наш лучик надежды. Разбираемся в коде, понимаем, что это ничто иное, как функция, которая возвращает словарь с количеством вхождений чисел в массиве. Недолго думая, понимаем в картинке считать нечего, кроме как пиксели, но продолжаем сидеть без малейшего понятия как это делать правильно.
Подсказка: А что это за такое? А такое есть у картинки? Три? А имя файла?

Получив эти вопросы после кода выше, стараемся дать на них вразумительные ответы. Под тем, что это за такое, подразумеваем количественную характеристику. У картинки, как мы и думали, есть пиксели, а три это три канала: red, green, blue. На имена файлов мы всегда обращали внимание, в данной задаче оно z.png, однако это нам абсолютно ничего не дало, кроме как трёх букв. Только потом мы осознали, что это отсылка к координатам Когда ты в тупике иди в Google. Слава так и поступил: начал вбивать поисковые запросы на подобии: количественная характеристика и как-то связывать это с изображением. Так он пришёл на сайт с генератором гистограммы по изображению. Загрузив наше исходное изображение он заметил интересную картину и поделился сразу с нами:


Это правда выглядит очень необычно. Вооружившись Python с PIL заводим три словаря под каждый канал, проходимся по каждому пикселю изображения, получая RGB и в каждый словарь инкрементим значение, ключ которого наш канал. Например, для словаря red вы возьмём от RGB R за ключ, а в значение добавим +1. Прям как тот код, что дали нам на Ruby. Так проделаем с остальными двумя каналами и О чудо!, Вы только взгляните на это! Практически везде идеальная картина, количество цветов в каждом канале совпадает!


Весь полученный файл доступен тут. Меньше, чем в пяти местах, значения отличались, но мы посчитали, что, возможно, у авторов задачи не получилось сделать идеальное совпадение. Ведь то, что мы увидели, уже величие! Не останавливаясь, видим отсутствие цветов, ведь не все идут по порядку. А почему бы не выписать: какие есть, а каких нет? Так и делаем, дописав к нашему прошлому коду цикл! Для трёх каналов получаем три бинарные строки длиной в 255, где цвет отсутствует 0, а где есть 1:

Red
0000111100000000000000000000000000001111000000001111000011110000111111111111111100001111000011111111000011110000111111110000000000001111111111110000000000001111000000000000000011111111000000001111000011111111000000001111000011110000000011110000111111110000

Green
0000111100000000000000000000000000000000111111111111000011111111111100000000111100001111000011110000111100001111000011110000111100000000000011111111111100001111000011111111000011110000000000001111111100000000000011111111000011110000000011110000000011111111

Blue
0000111100000000000000000000000000001111111100001111111100000000000011111111000000000000000000000000000000000000000011110000000000000000000011111111000000000000111100000000111100000000111111110000111111111111000011110000000011110000111111111111111100000000

Выглядит страшно и непонятно, но вы ведь тоже видите, что везде количество единиц кратно 4? А ведь с нулями такая же картина сжимаем!

Red
0100000001001010111101011010110001110001000011001011001010010110

Green
0100000000111011100101010101010100011101011010001100011010010011

Blue
0100000001101100011000000000010000011000100100110111010010111100

Вот Уже и не так страшно, легко влезает в поле зрения. Нужно думать дальше, чем это может быть, но тут олимпиадное предположение играет нам на руку: А что, если это double?. И правда, а ведь что если? Пробуем перевести двоичные последовательности в тип double (делаем reinterpret_cast в даблы), получаем следующие значения:

53.919325
27.58333
227.0005

Посещая уроки географии в школе, понимаем, что наше первое число: плюс-минус наша широта, а в целом, три числа как раз и обозначают координаты. Тут и должна была сыграть подсказка в имени файла, но мы уже пулей летим в Google карты:


Получилось! Координаты соответствуют углу офиса компании-организатора конкурса. Понимаем, что скорее всего придется туда приехать. Первый этап прошли.

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

Жарко стоять уже :(
Только что прошел кашляющий человек( он был без маски

Ответ организаторов не заставил долго ждать:
Там видео секунд на 30, не больше
Никуда заходить не нужно, можно приехать/прийти одному и повтыкать. Там три координаты, три, Карл, не две (как и две первые, третья отсчитывается от некого выбранного начала, а не от подошв кед). Не ходите, не спрашивайте, нужно рассмотреть со стороны.

Эти ответы перевернули всё. Проверяем высоту над уровнем моря, на которой находится офис, это где-то ~200. Предполагаем, что координата 227 плюс-минус может быть на крыше офиса. В это же время один из нас находился неподалёку он и отправился на локацию. Достигнув угла здания, как на Google карте, поднимаем глаза. Анимированный логотип это не то, что на аватарке в группе у компании. Вместо логотипа тетрис:


Для уточнения, то ли это, что нам надо, задаём следующий вопрос: Фигурки, падающие с небес, связаны с блоками, которые закрывают девочек? Во-первых: получаем положительный ответ, а во-вторых: редактирование нашего вопроса со стороны организаторов на о-ла-ла, падающие с тру-ла-ла, связаны с блоками, которые закрывают облади-облада?.

Мы на правильном пути. Дело Google таблиц! Покадрово разбираем отснятый материал, восстанавливаем блоки, цвета, записываем порядок появления блоков на видео. За счёт равной задержки между появлением фигур узнаём о наличии других, внутри отсутствующей части логотипа.


Учитывая текущий пазл, понимаем, что это пентамино, т.е. все фигуры состоят из пяти отдельных квадратов (пикселей). Находим буквенное обозначение данных фигур, пытаемся, опираясь на цвета, заполнить клетки на исходном изображении с девочками ничего не выходит. От организаторов приходят подсказки с количеством уникальных фигур в пентамино решаем задачку, заполнив весь прямоугольник уникальными блоками:


В очередной раз пытаемся вписать буквы в клетки, уже сомневаемся в правильности данного подхода, пытаемся найти что-то ещё. По цветам очень сложно понять: что куда, поэтому, во-первых: улучшаем нашу палитру в таблице, получив фотографию лучшего качества; а во-вторых: начинаем выписывать множество подходящих букв под каждую клетку.

Я получаю 3 читабельных слова из 4, но считаю это за совпадение, ухожу делать перестановку букв по словарю, с учётом тех, в которых был уверен по цветам. Таким цветом являлся синий и обозначал букву Т. Засылаю огромную пачку различных комбинаций в чатик. Почитав их все вместе, забываем про эту идею. Спустя некоторое время я со Славой возвращаюсь к расстановке букв, имея справа на экране свой первый вариант. Присоединяется Артур, который чутка отсутствовал на задаче, разбирается в том, чем мы тут занимаемся. Спустя некоторое время Артур обращает внимание на мой прошлый вариант, где найденные три слова выделены зелёным цветом, а под последним написано слово input. Это то слово, что очень хотелось собрать, но не сходилось по одной букве. Артур просто читает строку полностью: Input fifty pi int.

Умножаем число Пи на 50 в целочисленном типе, отсылаем в систему Получаем положительный вердикт: задача длинною в дней 5 решена!


Задача с ответами и вопросами



Подсказка: Где же поблизости найти вопросы, ответы на которые нужно вписать в матрицы?

Вспомним тот факт, что всё общение с организаторами проходит через обсуждения в группе ВК, следовательно, сейчас мы в обсуждениях, а максимальное близкое к нам место с вопросами или другая страница текущей темы, или другой раздел.

Так как первое является невозможным, то мы поднимаемся на уровень выше и смотрим на список обсуждений. Их не много, всего 4: обсуждение задач, подсказки, обсуждение конкурса, правила. Первые два откидываем сразу, к остальным присматриваемся. Зайдя в правила конкурса, видим вторым сообщением секцию с часто задаваемыми вопросами. Вот они, вопросы! Ответы у нас даны в задаче (подписи к матрицам) по ключевым словам ищем их и выписываем!


Подсказка: Зеленые начало укладки

Отлично, выходит что-то надо куда-то уложить. Куда это очевидно, так как знаем начало. Под Что, принимаем вопросы, которые нашли на первом шаге. Проверим свою догадку: все матрицы 10х10 (что даёт нам 100 клеток для символов). Посмотрим на длину строк ответов: все они больше 100. Попробуем откинуть знаки пунктуации и символ пробела, посчитаем просто количество букв у всех вопросов по 100 букв!


Остаётся последний шаг: узнать как укладывать. Там уже посмотрим на буквы в жёлтых клетках и может, что понятнее станет. Ломаем голову, от меня проскальзывает предложение: Давайте рассматривать, как граф, которое успешно игнорируется всеми остальными. Через некоторое время предлагается загуглить по изображению: вырезаем первую матрицу, скармливаем Google ничего, идём в Яндекс что-то есть!


Вчитываемся в найденное условие, понимаем, что необходимо найти гамильтонов цикл, даже не пытаемся сделать это руками, думаем об автоматизации, прикидываем сложность и сложно. Олимпиадники говорят, что решать задачу самым наивным перебором смысла нет. А использовать оптимизации лень, но есть надежда на то, что можно решить задачу проще. Для подтверждения того, что наивное решение будет отрабатывать слишком долго, пишем его. Убеждаемся, что работает долго.

Идём в Google, находим программу для решения оригинальной головоломки поиска цикла, а не путей, как в статье, которую мы нашли. Программа оказалась только для Windows, ни у кого её не оказалось под рукой, пошли поднимать виртуалку. Подняли, запустили, программа моментально находила решения.

Решение представляет собой обход поля:


Заходим всей командой в Google таблицу, накладываем скриншоты полученных решений на наши, перенесённые с задания, матрицы. В инструментах для разработчиков браузера задаём элементам с скриншотами прозрачность и заполняем матрицы буквами из ранее найденных вопросов.


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

Получив с каждой матрицы по кусочку фразы, читаем: Самое большое белла в лонге джавы минус сто. Понимаем, что от нас хотят самое большое число Белла, которое помещается в тип Long из Java.

Это в точности 4638590332229999253 и является ответом к задаче.



Задача с монетой


Самая сложная для меня задача для объяснения. Не представляю просто, как можно передать все те дней 10, что мы над ней сидели. Поэтому, давайте считать краткость и отсутствие подробностей за фишку. В задании, как и в прошлых, у нас только изображение:


В какие дебри мы только не зашли без подсказок. Это и деноминация в Беларуси, и состав монеты, и её размеры. Не оставили без внимания и словое opener с опечаткой. Я сразу же перевёл орёл и решка на английский несколькими способами, гуглил, пришёл к компании Open Retail, которая в 2009 году что-то там, а владеет она торговой сетью монетка. Смотрели на конкурсы прошлых лет. В общем дошли до тупика и пошли заваливать вопросами организаторов:
В 19 надо учитывать номинал?
да, и слово там не опечатка

монета или монета Республики Беларусь?
вопрос непонятен, скорее это не важно (слово монета не важно), важно то, что нарисовано

В 19ой есть что-то связанное с английской розницей?
только на втором этапе, на первом важны только буквы и числа на монетах

можно еще что-нибудь по 19, цифры буквы деньги, ничего не складывается?
деньги на втором этапе, на первом нужно соотнести числа и последовательности букв

Как в 19ой понять, что первый этап пройден? Должна получиться какая-то фраза? Если должны получиться числа, то как можно понять, что они правильные?
получится место. Нет, не числа должны получиться. Но этот в Минске, так можно понять, что он правильный.

мафия причастна к 19 задаче или просто тихий?
вероятно, ни первое, ни второе. Для определения места там числа и последовательности букв.

А можете как-то направить? А то вообще непонятно, как подходить к 19-ой задаче(ещё в первом этапе). Что делать с этими буквами и цифрами)
число связано с тем, как написано слово. на левой аналогичная связь

Получив просто тонну различной информации, стало понятно, что есть некая функция, которая принимает в себя строку и число и как-то переставляет в ней буквы. Реализовываем различные сдвиги, вводим слово openre и выводим каждую итерацию в консоль, смотрим примерно на 20 позицию, потому что без понятия что там по +-1. При определённом алгоритме встречаем opener на 21 позиции, а это 20 если с нуля.


Меняем входное значение на то, что находится на другой стороне монеты u9pgezed6. Повторяем тоже самое, но уже знаем про +1 и смотрим на 2010 итерацию, вместо 2009 приходим к u9edez6gp (файл с сгенерированными строками).

Из подсказок знаем, что конец первого этапа место. Ищем способы задать точное место строкой, натыкаемся на Plus коды Google, но формат не тот. Ищем альтернативные варианты и находим GeoHash! Для эксперимента вбиваем на этом сайте город Минск и сравниваем две строки. Похожи! Вводим нашу полученную строку с монет:


Место выглядит абы-где, как будто не туда, куда надо, указано, но я был там летом (проходил тестирование) и знаю, что там есть офис Itransition. Это точно то, что нам надо! По приходу на место бросается эта красота:


Первым делом я гуглю картинку, выхожу на ask девушки, потом на её instagram, интересуюсь в директе, откуда у неё эта фотография, как она с ней связана и прочее (объяснив ситуацию с конкурсом, конечно же). Оказывается, что девушка просто неподалеку отдыхала в каком-то заведении, а на улице была эта стена, которую она сфотографировала и опубликовала.

Присмотревшись к стене, находим ссылки на авторов ими оказались две девушки. Одна ссылка на Instagram профиль там, как раз, процесс создания этого шедевра. Вторая ссылка пользователь Telegram. Перейдя по второй, похвалив за проделанную работу (правда ведь красиво), спрашиваю: Связано ли это с конкурсом как-то?, на что получаю положительный ответ: Да ребята мы рисовали по строгому задания там нужно найти закономерность в этих чудовищных больше ничего сказать не могу. Нас не трогать.

Продолжаем залипать на стену, рассматривать монстров. Думаю, что-то в сторону конечностей. Не помню, кто именно, но точно не я, замечает, что это матрица 8x8, где каждый элемент монстр. Теперь и скобки [] в условии задачи выглядят для нас не как целая часть числа, а как обозначение матрицы.

Возвращаемся к переводу орёл и решка на английский язык (к этому подстегнула музыкальная подсказка с песней Лепса Уходи по-английски), закидываю идею посчитать heads и tails каждого монстра в отдельных матрицах. Долго сопротивляемся, но решаем попробовать. Сопротивляемся по той причине, что чёрт ногу сломит тут понять что хвост, а что голова и сколько их. Матрицы перемножаем:


Замечаем подозрительное количество четвёрок (да и в знаменателе она же). Игорь заменяет все ненулевые элементы на 4, так как могли ошибиться при подсчёте и получает следующую картину:


Игорь ничего не разглядел на этой матрице и начал циклически сдвигать вправо авось, что проявится. Отчаявшись, скинул в чатик:



Заключение


Всего было полсотни задач и рассказывать красочно о каждой, в рамках одной статьи, просто нецелесообразно. Мы отобрали те, где есть, что показать и рассказать. К сожалению, сюда не вошли алгоритмические задачи, коих было достаточное количество.

Чего мы только не вытворяли, чтобы достигнуть решения. Писали код на двух языках в одном файле, который будет без проблем выполняться в разных компиляторах. Коллизии MD5 хэш трёх разных файлов с кодом, игрались с RFC 2898 + AES, изучили флаги стран по цветам, выучили Ruby, пописали на asme, подеобфусцировали кучу раз код и многое-многое другое

Это был незабываемый месяц! Рекомендуем принять участие в следующем году! А вот и обещанная задача про Python (без решения):
Написать скрипт на языке Python 3, который: состоит не более чем из 4000 латинских букв и круглых или угловых скобок; при запуске печатает на консоль переданные в скрипт аргументы в обратном порядке (каждый на отдельной строке).

Дополню, что пробелы использовать запрещено. Исключительно то, что написано в условии. Жду вас в комментариях!

Спасибо, что дочитали аж до сюда! Всем МурмурХеша.
Подробнее..

L-системы и что они себе позволяют

30.01.2021 16:19:23 | Автор: admin

Давайте начнём с азов, если брать определение из всем известной и всеми любимой Википедии, то L-система (или же система Линденмайера) это параллельная система переписывания и вид формальной грамматики.

Если говорить простым языком, то L-система состоит из алфавита символов, которые могут быть использованы для создания строк, набора порождающих правил, которые задают правила подстановки вместо каждого символа, начальной строки ( аксиомы ), с которой начинается построение, и механизм перевода образованной строки в геометрические структуры. Самым простым примером L-системы может служить задача построения дерева.

Вводные данные:

Строка (далее Аксиома): A B

Переменные (которые мы можем задействовать в построении дерева): A B C

Правило (правило по которому каждая переменная на последующие строке меняется):

  • A - > AB

  • B - > AC

  • C - > A

Получаются такие преобразования:

Поколение

Состояние

1

A B

2

AB AC

3

AB AC AB A

4

AB AC AB A AB AC AB

5

AB AC AB A AB AC AB AB AC AB A AB AC

6

и так далее

Основным направлением, в котором применяются L-системы, это моделирование процессов роста как живых организмов, так и неживых объектов (кристаллов, раковин моллюсков или пчелиных сот).

Пример:

Для моделирования подобных процессов, мы с вами будем использовать такой язык программирования как Python, в нём есть встроенная библиотека turtle.

Итак, приступим:

  1. Здесь мы импортируем библиотеку Turtle в наш проект:

    import turtle

  2. Далее мы подключаем все необходимые конфигурации для нашей черепашки:

    turtle.hideturtle()

    turtle.tracer(1)

    turtle.penup()

    turtle.setposition(-300,340)

    turtle.pendown()

    turtle.pensize(1)

  3. Далее мы задаём значение непосредственно самой аксиомы и сопутствующих параметров, необходимых для задания последовательности:

    axiom = "F+F+F+F"

    tempAx = ""

    itr = 3

    (itr- значения итераций цикла, оно нам понадобится в следующем шаге при написании нашей программы)

  4. В данном цикле, где как раз нам и понадобится переменная itr-, мы занимаемся обработкой и "выращиванием" непосредственно генома нашего фрактала/растения:

    for k in range(itr):

    for ch in axiom:

    if ch == "+":

    tempAx = tempAx + "+"

    elif ch == "-":

    tempAx = tempAx + "-"

    elif ch == "F": #F

    tempAx = tempAx + "F+F-f-F+F"

    else:

    tempAx = tempAx + "f"

    axiom = tempAx

    tempAx = " "

    print(axiom)

    Если мы с вами пробежимся по циклу, то сразу же в первом условии мы увидим фильтр на символ "+":

    if ch == "+":

    tempAx = tempAx + "+"

    Здесь мы ищем в аксиоме (изначальной строке) знак + и при его появлении мы добавляем символ + в последующую строчку. Так же происходит и с символом - и f, мы просто добавляем в последующую строчку символы - и f соответственно. Но при появлении в нашей аксиоме символа F, мы поступим немного иначе и добавим в последующую строчку уже последовательность символов F + F f F + F, для увеличения длины каждой последующей строки. Данное действие в принципе не принципиально, но для быстроты генерации генома, я решил поступить именно так. В конце мы обязательно приравниваем аксиому к нашему геному и обнуляем его:

    axiom = tempAx

    tempAx = " "

    Результат (значение аксиомы):

  5. Ну что, вроде по генерации генома всё понятно, давайте уже приступим непосредственно к визуализации. Для этого нам понадобиться простенький цикл, который будет переводить встречающиеся в геноме символы в движения черепашки:

    for ch in axiom:

    if ch == "+":

    turtle.right(45)

    turtle.forward(10)

    turtle.right(45)

    elif ch == "-":

    turtle.left(45)

    turtle.forward(10)

    turtle.left(45)

    else:

    turtle.forward(20)

    Сразу можно заметить, что по аналогии с предыдущим пунктом, мы детектируем символы "+", "-", "F" и "f". Только теперь в момент, когда мы встречаем символ "+":

    if ch == "+":

    turtle.right(45)

    turtle.forward(10)

    turtle.right(45)

    Мы поворачиваем сначала на право, на 45 градусов, потом проезжаем расстояние, равное 10, и потом мы снова поворачиваем на право, на 45 градусов. Когда же мы встречаем символ "-":

    elif ch == "-":

    turtle.left(45)

    turtle.forward(10)

    turtle.left(45)

    Мы делаем все те же самые действия, что и при символе "+", только на этот раз поворачиваем уже не вправо, а уже влево. Но если же мы встретим символы "F" или "f", то мы просто буем проезжать вперёд на 20 пикселей:

    else:

    turtle.forward(20)

    В итоге мы получаем вот такой фрактал-снежинку:

  6. Если же мы захотим раскрасить наш фрактал-снежинку, то нам понадобиться перед циклом из предыдущего пункта добавить строчки:

    turtle.fillcolor("#99BBFF")

    turtle.begin_fill()

    Где #99BBFF - это кодировка цвета (RGB: 153, 187, 255), а begin_fill() это начало заполнения цветом. И в конце, уже после цикла, добавить строчки:

    turtle.end_fill()

    turtle.update()

    turtle.done()

    А end_fill() означает конец заполнения. Далее мы обновляем и выключаем нашу "черепашку". И на выходе мы получаем вот такой фрактал-снежинку:

Вы так же можете посмотреть, "потыкать" код, изменяя параметры и данные в нём.

В конце, хочу также добавить, что мне очень понравилось работать и писать по данной тематике, возможно, в будущем, я напишу ещё ряд статей по теме "L-системы", но а пока, хочу представить вам результаты моего тыканья творчества:

Подробнее..

Популярные задачи для собеседований бэкенд-разработчиков на Go и их решения

01.02.2021 20:15:32 | Автор: admin

Я живу в Ташкенте, и когда учился в университете начал учить Python, чтобы писать ботов. Боты это узбекский хлеб, у нас на них построено вообще все. Например, никто не делает приложения для заказа еды, все только в мессенджерах.

Я учил язык по статьям из интернета просто брал каркас и дальше дописывал, смотрел, где что падает, постоянно решал задачи на leetcode. Писал я тогда ужасно, но что было, то было. Мне нравилось, но чем больше я углублялся, тем сильнее раздражали скорость выполнения, ограничения параллелизма и динамическая типизация.

Тогда я решил попробовать Go.


Go простой, классный и востребованный

Меня привлекла их идея легковесной конкурентности и понравилось то, что не нужно разбираться в зоопарке асинхронности, который был в питоне. Сначала я писал на Go что-то для себя, смотрел как себя ведет язык. Потом на работе мы решили попробовать один несложный проект. Получили хорошие результаты и по скорости разработки, и по скорости выполнения.

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

Как говорил Роб Пайк: Простота это сложно. Философия, все дела. Кто-то ругает голанг за излишнюю простоту, а мне она нравится.

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

Один раз я полуслучайно угодил на синьорское собеседование. Это было самое душное из всех интервью, что я видел. Было ощущение, что интервьюера заставили прийти и слушать меня. Он сразу начал с технических вопросов, и я понял, что он просто задает вопросы из статьи с хабра причем идет по ним подряд, как будто за 15 минут до встречи погуглил Вопросы для собеседования бэкенд-разработчика.

Эйчары написали мне через месяц и сказали, что уже готовят оффер. Потом написали еще через час и сказали, что, к сожалению, иностранцев они уже не берут.

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

Я считаю, что самые адекватные способы понять, хорош ли разраб давать ему задачи и разбирать код. На работе, которую я в итоге получил, было именно так. Здесь я собрал несколько самых популярных задач, которые часто попадаются на собесах и написал, как бы я стал их решать.


Популярные задачи на собеседованиях

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

Стандартная задача с leetcode и ее довольно часто спрашивают на собеседованиях в качестве простой задачи для разогрева.

Можно решить сортировкой, за более долгое время, но без выделения дополнительной памяти. А можно выделить дополнительную память и решить за линейное время.

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

Решение

https://play.golang.org/p/1WQWZdsevf7

Написать генератор случайных чисел

В принципе, легкая задача, на базовые знания по асинхронному взаимодействию в Go. Для решения я бы использовал небуфферезированный канал. Будем асинхронно писать туда случайные числа и закроем его, когда закончим писать.

Плюс ее можно использовать в немного измененном виде в задаче на слияние N каналов.

Решение

https://play.golang.org/p/T0McDy7TfTG

Слить N каналов в один

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

Мы хотим, чтобы результат работы функции выглядел примерно так:

for num := range joinChannels(a, b, c) {

fmt.Println(num)

}

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

Создаем канал, куда будем сливать все данные. Он будет небуферезированный, потому что мы не знаем, сколько данных придет из каналов.

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

Решение

https://play.golang.org/p/31sWw60MkFM

Сделать конвейер чисел

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

Довольно частая задача, более подробно можно почитать тут https://blog.golang.org/pipelines.

Решается довольно прямолинейно запускаем две горутины. В одной пишем в первый канал. Во второй читаем из первого канала и пишем во второй. Главное не забыть закрыть каналы, чтобы ничего нигде не заблокировалось.

Решение

https://play.golang.org/p/BmVfWzGszEU

Написать WorkerPool с заданной функцией

Довольно распространенная задача, плюс подобные задачи встречаются на практике.

Нам нужно разбить процессы на несколько горутин при этом не создавать новую горутину каждый раз, а просто переиспользовать уже имеющиеся. Для этого создадим канал с джобами и результирующий канал. Для каждого воркера создадим горутину, который будет ждать новую джобу, применять к ней заданную функцию и пулять ответ в результирующий канал.

Решение

https://play.golang.org/p/9aQi63fiL41

Сделать кастомную waitGroup на семафоре

Семафор можно легко получить из канала. Чтоб не аллоцировать лишние данные, будем складывать туда пустые структуры.

В нашем случае мы хотим сделать семафор, который будет ждать выполнения пяти горутин. Для этого просто добавим вместо обычного канала буфферизированный. И внутри каждой горутины положим в него значение. А в конце будем дожидаться, что все ок мы вычитаем все значения из канала.

Решение

https://play.golang.org/p/w-QokHyWcW5

В общем, если понравились задачи и показались полезными заходите в канал Rebrain там часто выкладывают бесплатные вебинары и практикумы по Go. Потом можно обсуждать кто, что и как делает в сообществе.


Мысли о будущем Go

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

Никто не ругает топор, за то что он такой топорный, да и вообще он не бензопила.

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

Но сейчас на Go все чаще пишут гигантские системы. Наделали фреймворков (само по себе понятие фреймворк противоречит идее Go), разработали инструменты, чтобы затащить его на фронтенды, адаптировать к разработке огромных приложений, стали делать на нем все, что не приколочено. Начали требовать серьезного развития языка в сторону усложнения чтобы было как в Java и C#. Чтобы у нас, значит, тоже получалось пилить грандиозные монолитные бекенды, обмазывать всё тоннами декораторов, писать универсальный, сверхпереиспользуемый код и все такое.

Посмотрите на С++. Чтобы угодить потребностям всех разработчиков на плюсах, язык набили фичами настолько, что всерьез вот сесть и выучить С++ невозможно. А уж выбрать его в качестве инструмента для разработки, когда есть альтернативы абсолютно исключено.

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

Автор статьи @alisher_m, участник сообщества Rebrain. Подписывайтесь, если хотите тоже поделиться опытом и поспрашивать советов. Там регулярно разбираем все эти темы и многие другие, которые пригодятся и на собеседовании, и в работе

Подробнее..

SQL для аналитики рейтинг прикладных задач с решениями

11.02.2021 12:14:32 | Автор: admin

Привет, Хабр! У кого из вас black belt на sql-ex.ru, признавайтесь? На заре своей карьеры я немало времени провел на этом сайте, практикуясь и оттачивая навыки. Должен отметить, что это было увлекательное и вознаграждающее путешествие. Пришло время воздать должное.

В этой публикации я собрал топ прикладных задач и мои подходы к их решению в терминах SQL. Каждая задача снабжена кусочком данных и кодом, с которым можно интерактивно поиграться на SQL Fiddle.

SQL is intergalactic data speak. SQL - это межгалактический язык данных

- Michael Stonebraker

Моя цель - показать походы и самые распространенные проблемы на понятных и доступных примерах. Конечно, СУБД, на которой решается задача имеет значение. Поддержка функций и синтаксиса варьируется. В SQL Fiddle я задействовал PostgreSQL, Oracle, SQL Server. Для решения серьезных аналитических задач сегодня я чаще всего использую специальные СУБД, такие как Redshift, Vertica, BigQuery, Clickhouse, Snowflake.

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

Конкатенация значений из нескольких строк в одну через разделитель

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

Формулировка задачи: Для каждого лида вывести список тегов, разделенных запятой в одном столбце

SQL Fiddle (PostgreSQL 9.6): http://sqlfiddle.com/#!17/f3ace/2/0

Входные данные:
Пример решения:
select lead_id ,string_agg(tag, ', ') as tagsfrom leadsgroup by lead_id;
Результат:

Аналитические функции при сохранении всех строк выборки

Речь пойдет о так называемых analytic functions, которые оперируют над партициями данных (окна, windows), возвращая результат для каждой строки. В отличие от aggregate functions, схлопывающих строки, оконные функции оставляют все строки выборки.

Окно определяется спецификацией (выражение OVER) и основывается на трех основных концепциях:

  • Разбиение строк на группы (выражение PARTITION BY)

  • Порядок сортировки строк в каждой группе (выражение ORDER BY)

  • Рамки, которые определяют ограничения по количеству строк относительно каждой строки (выражение ROWS)

Таких функций существует немало, от аналитических: всем известные SUM, AVG, COUNT, менее известные LAG, LEAD, CUMEDIST, и до ранжирующих: RANK, ROWNUMBER, NTILE. Я же приведу несколько простых примеров часто встречающихся запросов:

  • Ко всем транзакциям пользователя вывести дату первой покупки

  • К каждой транзакции добавить дату предыдущей транзакции пользователя

  • Показать сумму покупок пользователя нарастающим итогом

  • Присвоить всем транзакциям пользователя / продавца / отделения порядковый номер

SQL Fiddle: http://sqlfiddle.com/#!17/ee00f/13

Входные данные:
Пример решения:
select  salesid ,dateid ,sellerid ,buyerid ,qty ,first_value(dateid) over (partition by buyerid order by dateid) as first_purchase_dt ,lag(dateid) over (partition by buyerid order by dateid) as previous_purchase_dt ,sum(qty) over (partition by buyerid order by dateid rows between unbounded preceding and current row) as moving_qty ,row_number() over (partition by buyerid order by dateid) as order_numberfrom winsales;
Результат:

Работа с NULL и применение логики ветвления IF-THEN-ELSE в SQL

Про COALESCE / NVL знают все, и нет смысла останавливаться на них подробно. Зато с NVL2 и NULLIF знакомы уже не так много людей.

NULLIF сравнивает два значения и возвращает NULL, если аргументы равны. По сути эта функция - обратна к NVL / COALESCE. Формулировка задачи:

  • Как обработать ошибку деления на 0 (divide by zero error)

  • Как выводить NULL вместо пустых строк ()

SQL Fiddle (PostgreSQL 9.6): http://sqlfiddle.com/#!17/bf56e/2

Входные данные:
Пример решения:
select lead_id ,nullif(tag, '') as tagfrom leads;
Результат:

NVL2 в свою очередь вернет одно из значений, в зависимости от того, является ли входной аргумент NULL или NOT NULL. Например, если в таблице транзакций есть ссылка на invoiceid, значит транзакция в сегменте B2B, и ее следует пометить соответствующим образом.

SQL Fiddle (Oracle 11g R2): http://sqlfiddle.com/#!4/4cac9/11

Входные данные:
Пример решения:
select "transaction_id" ,"ts" ,"invoice_id" ,nvl2("invoice_id", 1, 0) as "is_b2b"from transactions;
Результат:

Но больше всего мне нравится функция DECODE. Она в буквальном смысле позволяет расшифровать значения согласно заданной вами логике:

DECODE ( expression, search, result [, search, result ] [ ,default ] ).

Формулировка задачи: Присвоить численному коду (или, например, битовой маске) текстовые наименования.

SQL Fiddle (Oracle 11g R2): http://sqlfiddle.com/#!4/60341/1

Входные данные:
Пример решения:
select "transaction_id" ,decode("status", 0, 'charge', 1, 'authorize', 2, 'settle', 'void') as "status"from transactions;
Результат:

Опережая вопрос, конечно, эту же логику можно выразить через всем известное выражение CASE. Задача показать что-то интересное, и чем меньше кода - тем красивее, на мой взгляд.

Дедупликация данных

Это классика. Задачу часто спрашивают на собеседованиях в формулировке как удалить дубли / копии строк, и решить ее можно несколькими способами. Я привык мыслить в терминах историзации данных в Хранилище, и удаление мне ни к чему, поэтому для решения задачи я воспользуюсь ранжирующей функцией ROWNUMBER().

Формулировка задачи: Выбрать самую актуальную запись с учетом статуса (успешная / отмененная транзакция) и временнОй метки

SQL Fiddle (Oracle 11g R2): http://sqlfiddle.com/#!4/ad305/1

Входные данные:
Пример решения:
with decoded as (   select   "transaction_id"   ,"is_successful"   ,"ts"   ,decode("is_successful", 'true', 0, 'false', 1, 2) as "order_is_successful"   from transactions),ordered as (   select   "transaction_id"   ,"is_successful"   ,"ts"   ,row_number() over(partition by "transaction_id" order by "order_is_successful" asc, "ts" desc) as rn   from decoded)select "transaction_id" ,"is_successful" ,"ts"from orderedwhere rn = 1;
Результат:

Некоторые СУБД, например, Teradata позволяют сделать запрос короче при помощи выражения QUALIFY:

select *from students_db.exam_resultsqualify row_number() over (partition by subject order by marks desc) = 1;

Анализ временных рядов

Просто не могу обойти это стороной. ВременнАя шкала - это, безусловно, одно из наиболее часто используемых измерений. Отчетность зачастую строится вокруг измерения метрик и их динамики относительно периодов: неделя, месяц, время суток и т.д.

Замечательно, если ваша BI система умеет работать с различными абсолютными и относительными фреймами, и наружу выставляет красивый визуальный интерфейс. Еще лучше, если в ваш инструментарий аналитика входит пара наиболее используемых функций:

  • Получение текущей даты (+ время) - CURRENTDATE, CURRENTTIMESTAMP

  • Разница между событием и текущим временем - DATEDIFF

  • Подсчет времени истечения срока действия события - DATEADD

  • Дата начала недели, в которой произошло событие - DATETRUNC

  • Конвертация Unix Timestamp (epoch) в человекочитаемый формат

SQL Fiddle (MS SQL Server 2017): http://sqlfiddle.com/#!18/618cf/6

Входные данные:
Пример решения:
select ts ,_metadata_ts_epoch ,convert(date, getdate()) as current_dt ,current_timestamp as current_ts ,datediff(minute, ts, getdate()) as minutes_since_ts ,dateadd(hour, 36, ts) as ts_expiration_ts  ,dateadd(week, datediff(week, 0, ts), 0) as ts_week ,dateadd(S, (_metadata_ts_epoch / 1000), '1970-01-01') as _metadata_tsfrom transactions;
Результат:

Анализ истории со Slowly Changing Dimensions (SCD)

В основе Хранилища Данных лежит принцип историзации. Иначе говоря - это возможность получить состояние той или иной сущности на определенный момент времени, а также проследить цепочку событий и изменений атрибутов и показателей. Существует несколько способов организации хранения истории. Один из наиболее популярных подходов - запись новой строки на любое изменение атрибутного состава, с указанием даты начала и окончания действия каждой строки.Есть несколько задач, с которыми вы с большой долей вероятности можете встретиться.

Формулировка задачи: Какой статус был у клиентов на 3-й день месяца?

SQL Fiddle (PostgreSQL 9.6): http://sqlfiddle.com/#!17/743e9/6

Входные данные:
Пример решения:
select  client_id  ,statusfrom clientswhere '2021-02-03' >= valid_from and '2021-02-03' < coalesce(valid_to, '2100-01-01');
Результат:

Формулировка задачи: Как в течение недели росло количество активных клиентов?

SQL Fiddle (PostgreSQL 9.6): http://sqlfiddle.com/#!17/743e9/11

Пример решения:
select   c.dt  ,h.status  ,count(distinct h.client_id)from calendar c  left join clients h      on c.dt >= valid_from and c.dt < coalesce(valid_to, '2100-01-01')::datewhere trueand c.dt between '2021-02-01' and '2021-02-07'and h.status in ('active')group by   c.dt  ,h.statusorder by 1, 3 desc;
Результат:

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

Использование выражения CASE в агрегирующих функциях

Агрегирующие функции могут принимать в качестве аргумента результат оценки выражения CASE. Таким образом можно к агрегируемым строкам применить псевдофильтр. Это напоминает мне использование формулы СУММЕСЛИ из старого доброго Excel, только для реляционных баз данных. Смотрите сами:

  • Подсчитать все лиды и выручку

  • Подсчитать количество лидов со статусом success

  • Подсчитать выручку лидов с тегом python

SQL Fiddle (MS SQL Server 2017): http://sqlfiddle.com/#!18/dc01d5/4

Входные данные:
Пример решения:
select dt ,count(1) as leads_total ,sum(case status when 'success' then 1 else 0 end) as leads_success ,sum(case when tags like '%python%' then 1 else 0 end) as leads_python ,sum(amount) as amount_total ,sum(case status when 'success' then amount else 0 end) as amount_successfrom leadsgroup by dtorder by dt;
Результат:

Парсинг колонки с разделением на отдельные атрибуты

Чаще всего так поступают в условиях внешних ограничений, когда иного выхода нет. Например, при ограниченном наборе полей в CRM системе. Или при передаче нескольких UTM-меток в одной строковой переменной. Еще так могут делать люди, которые не слышали про нормализацию данных.

Формулировка задачи: Выделить закодированные в названии кампании атрибуты в отдельные колонки: сеть, регион, категория, температура, бренд.

SQL Fiddle (PostgreSQL 9.6): http://sqlfiddle.com/#!17/205e7b/6

Входные данные:
Пример решения:
select campaign ,split_part(campaign, '-', 1) as network ,split_part(campaign, '-', 2) as region ,split_part(campaign, '-', 3) as category  ,nullif(split_part(campaign, '-', 4), 'None') as temperature  ,split_part(campaign, '-', 5) as brand from campagins;
Результат:

Чуть более сложная ситуация с парсингом UTM-меток, а именно UTMContent, которая по сути является контейнером для произвольного набора атрибутов, разделенных любым символом. Поэтому стоит быть последовательным и аккуратным при формировании таких меток, хотя зачастую инженер вынужден работать с тем, что есть.

Формулировка задачи: Разбить строку UTMContent на отдельные атрибуты cid, gid, aid, kwd с соблюдением соответствия ключ-значение. Каждое значение предваряется наименованием ключа, все значения разделены вертикальной строкой (|).

SQL Fiddle (PostgreSQL 9.6): http://sqlfiddle.com/#!17/4f65e/4

Входные данные:
Пример решения:
select substring("UTMContent" from '%cid_#"%#"_gid%' FOR '#' ) AS cid ,substring("UTMContent" from '%gid_#"%#"_aid%' FOR '#' ) AS gid ,substring("UTMContent" from '%aid_#"%#"_dvc%' FOR '#' ) AS aid ,substring("UTMContent" from '%kwd_#"%#"_pos%' FOR '#' ) AS kwdfrom utm;
Результат:

FULL JOIN для соединений без потери строк

Уверен, что все знают про FULL JOIN, но кто хоть иногда использует этот тип соединения? Это незаменимый подход в ситуациях, когда я хочу сохранить все исходные строки с каждой стороны джоина. Иначе говоря, недопустимо терять факты трат денежных средств, даже если для них не нашлось соответствующих лидов в таблицах CRM.

А теперь представьте ситуацию, когда таблиц больше двух. Это может быть веб-аналитика, выгрузки из рекламных кабинетов, CRM. В этом случае я дополнительно формирую мета-колонки isrowmatched (нашлось ли совпадение - да / нет) и roworigin (источник данных для конкретной строки).

Формулировка задачи: Подготовить витрину-трекер для сквозной аналитики лидов из CRM и трат из Рекламных Кабинетов (Яндекс.Директ, Google Adwords, Facebook).

SQL Fiddle (PostgreSQL 9.6): http://sqlfiddle.com/#!17/227eaf/1

Входные данные:
Пример решения:
select coalesce(c.hash_key, l.hash_key) as hash_key ,coalesce(c.dt, l.dt) as dt ,coalesce(c.campaign_id, l.campaign_id) as campaign_id -- costs ,coalesce(c.platform, null) as platform ,coalesce(c.clicks, 0) as clicks ,coalesce(c.costs, 0) as costs -- leads ,coalesce(l.leads, 0) as leads ,coalesce(l.amount, 0) as amount -- meta ,case     when c.dt is not null then c.platform     when l.dt is not null then 'crm'   end as meta_row_origin ,case     when c.hash_key = l.hash_key then 1     else 0   end as meta_is_row_matchfrom costs as c   full join leads as l on l.hash_key = c.hash_key;
Результат:

Пример упрощен и умозрителен. Однако этой задаче я посвятил одну из своих предыдущих публикаций: Сквозная Аналитика на Azure SQL + dbt + Github Actions + Metabase и недавнее выступление на вебинаре: Путь Инженера Аналитики: Решение для Маркетинга. Тема заслуживает отдельного внимания.

Разбиение пользовательских событий на сессии

Сессионизация - весьма интересная и сложная задача, сочетающая в себе сразу комплекс инженерных и аналитических решений. С ростом популярности и востребованности всевозможных трекеров, таких как Google Analytics, Snowplow, Amplutide кратно возрастает спрос на решение подобного рода задач.

Для чего это можно использовать? Прежде всего, для того, чтобы перейти от анализа хитов (кликов) к полноценному анализу пользовательского взаимодействия и поведения. Во-вторых, улучшение UX и качества сервисов, проведение A/B тестирования. Наконец, поиск паттернов, определенных сегментов пользователей, в том числе fraud monitoring (защита от мошенничества и ботов).

Чуть подробнее про дефиницию сессии от Google Analytics: How a web session is defined in Universal Analytics. Резюмируя, сессия - это набор пользовательских действий в рамках заданного промежутка времени. Сессия завершается при следующих событиях:

  • 30 минут бездействия

  • Начало новых суток

  • Смена источника трафика (возврат на сайт по клику на новый рекламный баннер)

Базовая задача сессионизации сводится к следующему: превратить последовательность кликов из лога веб-сервера в набор сессий.

SQL Fiddle (PostgreSQL 9.6): http://sqlfiddle.com/#!17/17271/3

Попробуем декомпозировать и решить задачу по частям:

  • Шаг 1. Для каждого пользователя берем идентификатор просмотра, время просмотра, источник трафика (хеш-сумма). Хеш-сумма берется от текстовой конкатенации атрибутов источника трафика: utm_source + utm_medium + utm_campaign. При этом обрабатываются null-значения в любом из столбцов (заменяются на литерал 'null'). По хеш-сумме легко проверить смену источника трафика.

Шаг 1
 select   user_id   ,hit_id   ,ts   ,md5(concat(coalesce(utm_source, 'null'), coalesce(utm_medium, 'null'), coalesce(utm_campaign, 'null'))) as utm_hash from hits_raw
  • Шаг 2. Для каждого хита выводим предыдущий хит и соответствующее ему время. Окно - по пользователю, сортировка по времени хита:

Шаг 2
select   user_id   ,hit_id   ,ts   ,lag(ts, 1) over (partition by user_id order by ts) as lag_ts   ,utm_hash   ,lag(utm_hash, 1) over (partition by user_id order by ts) as lag_utm_hash from hits
  • Шаг 3. Рассчитываем, является ли каждый хит началом новой сессии. Это проверка на выполнение любого из трех указанных выше условий окончания сессии:

Шаг 3
select   user_id   ,hit_id   ,ts   ,lag_ts   ,case     when utm_hash <> lag_utm_hash then 1     when date_part('day', ts - lag_ts) <> 0 then 1     when date_part('hour', ts - lag_ts) * 60 +             date_part('minute', ts - lag_ts) > 30 then 1     else 0    end as is_new_session --    ,date_part('day', ts - lag_ts) as days_diff--    ,date_part('hour', ts - lag_ts) * 60 +--              date_part('minute', ts - lag_ts) as minutes_diff   ,utm_hash   ,lag_utm_hash from lags
  • Шаг 4. Присваиваем каждой сессии уникальный идентификатор. Для этого сначала необходимо пронумеровать сессии одного пользователя монотонно возрастающими числами. Затем построить уникальный суррогатный ключ сессии: к номеру сессии добавить идентификатор пользователя, взять хеш-сумму:

Шаг 4
select   user_id   ,hit_id   ,ts   ,is_new_session   ,sum(is_new_session) over (partition by user_id order by ts rows between unbounded preceding and current row) as session_index   ,md5(concat(user_id, sum(is_new_session) over (partition by user_id order by ts rows between unbounded preceding and current row))) as session_id from new_sessions
Результат:

В реальном мире всё сложнее

Помимо логики, выраженной в SQL, не меньшее значение имеет ряд других факторов:

  • СУБД, с которой вы работаете: то, какие функции и возможности она поддерживает, формат хранения данных: в виде колонок или строк

  • Фактически используемый план выполнения запроса: алгоритмы соединения таблиц, локальность операций, наличие статистических данных у оптимизатора

  • Используемые физические и логические модели данных: индексы, материализованные представления, кеш, предварительно отсортированные данные


На занятиях курса Data Engineer я и мои коллеги готовим объемлющий и интересный контент, затрагивающий множество тем, связанных с архитектурой аналитических приложений, внутренним устройством систем обработки больших данных и развертыванием ML.

Советую посетить ближайшие открытые вебинары:

Оставляйте ваши комментарии и вопросы, предлагайте собственные примеры задач и подходы к решению.

Следить за моими публикациями в авторском канале: https://t.me/enthusiastech

Благодарю за внимание.

Подробнее..

Разбор секции DESIGN на DUMP куда расти и развиваться?

12.04.2021 20:16:10 | Автор: admin

Дизайн - одна из самых заметных и посещаемых секций на конференции DUMP. Здесь стоит вспомнить доклад Алексея Кулакова про обратную связь. На прошлой конференции он затронул очень важные и близкие каждому дизайнеру вопросы:

В этом году нам с вами тоже есть, что обсудить. Поговорим и зоне развития дизайнера.

В качестве слушателей в секцию дизайна придут специалисты разного профиля и опыта. И задача спикеров - показать и рассказать то, что позволит по окончанию сессии докладов сказать: "Это интересно, я хочу попробовать так же". Или: "Я хочу это скорректировать (что нормально) и попробовать реализовать в своем рабочем процессе".

Антон Русецкий, директор мультимедиа программ JetStyle как представитель программного комитета рассказал, что данный поток не будет каким-то набором универсальных ответов на вопросы, он больше про истории и ситуации. Про поиск решения текущих задач. Для этого мы стараемся с нашими спикерами обсуждать доклады с точки зрения баланса между их кейсами или методологией о которых они рассказывают, полученном опыте и примерами реализации. Думаю, это позволит зацепиться за интересные аспекты и менеджерам, и арт-директорам, и дизайнерам.

Если пробежаться по докладам, то Александр Обанин расскажет, как можно в своем рабочем процессе применять генеративный дизайн и покажет, как с его помощью можно решать утилитарные задачи, а также делать различную цифровую красоту. Интересная тема для тех, кто хочет автоматизировать рутинные дизайн-процессы, и для тех, кому хочется попробовать создать что-то необычное, интерактивное и разнообразное.

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

Павел Колодяжный выступит в роли приглашенной звезды. От него мы узнаем о том, как переключиться в состояние фокусировки и концентрации. Ждем простой и понятный алгоритм действий.

Мы постараемся интересно рассказать про тот прекрасный и разнообразный мир проблем и решений, в котором живут дизайнеры. Главное, чего хотелось бы добиться - дать слушателям идеи для позитивных изменений внутри своих рабочих групп и процессов.

Присоединяйся к DUMP-2021!Билеты на офлайн и онлайн уже на сайте

Подробнее..

Перевод Принятие решений на основе математики задача о проблеме секретаря

09.10.2020 16:18:18 | Автор: admin

Настало время занимательных задач. Представьте, что вы снимаете квартиру в огромном городе. Как свести к минимуму риски при столь значимом выборе, когда вы ничего не знаете о вариантах заранее? На этот вопрос отвечает теория вероятности и задача о проблеме секретаря. Графики, рассуждения, немного кода на Julia все подробности под катом.



Как теория вероятностей отвечает на вопрос согласиться или отказать?


Проблема секретаря или задача о разборчивой невесте в русскоязычной литературе это известная загадка на тему принятия решений. Речь идет о том, чтобы найти наилучшую стратегию выбора из последовательности, когда вы не знаете, какой вариант лучше. Формулировка задачи звучит так:

Вы менеджер по персоналу и должны нанять лучшего секретаря из $N$ кандидатов. Вы можете собеседовать их одного за другим в случайном порядке. Однако решение о назначении или отказе в назначении на должность должно приниматься сразу после собеседования. Если никто не был принят, выбирается последний кандидат. Какую стратегию вы выберете, чтобы максимально увеличить шансы нанять лучшего кандидата?

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

  • Решение снять квартиру в переполненном городе.
  • Быстрый поиск старшей карты при перетасовывании колоды.
  • Поиск магазина с невысокими ценами без проходов туда и обратно.
  • Обязательства перед долгосрочным партнером.

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

Прежде чем приступать к делу, нужно принять важное решение. Решите для себя, хотите ли вы снова прочитать загадку и подумать о решении самостоятельно. Я настоятельно рекомендую это сделать, потому что это упражнение для ума. Независимо от того, осознаете вы лучшую стратегию или нет. Если вы нетерпеливы, просто прочитайте вывод.

Случайность? Спасибо, не надо


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

Перед лицом этой полной неопределенности заманчиво довериться удаче. Можно принять произвольное решение: как бы то ни было, я выбираю первый вариант. Неудивительно, что эта случайная стратегия работает плохо. У вас есть только вероятность $P=1/N$, что первый кандидат будет лучшим. То же самое верно и при выборе всегда последнего претендента или всегда кандидата $n$ ваши шансы всегда $1/N$ для любого заранее подготовленного варианта.

Случайная стратегия становится все менее пригодной по мере увеличения числа претендентов. Если бы у вас было всего $N=3$ кандидатов, случайный выбор работал бы только в 33% случаев. При $N=10$ претендентов шансы случайно выбрать лучшего кандидата составляют жалких 10%. С $N=100$ это всего 1%. Эти цифры неприемлемы для уважающего себя менеджера по персоналу. Существует ли жизнеспособная стратегия лучше случайного выбора?

Подождать. Подобрать критерии. Опять подождать


В этот момент вы, возможно, поняли, что единственная контролируемая вами переменная это число людей, которым вы отказали.

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

  1. Собеседуем R людей и отказываемся нанимать их. Запоминаем лучшего кандидата. Назовем его $Xref$.
  2. Продолжаем опрашивать следующих кандидатов, пока не найдется первый с оценкой выше $Xref$. То есть, $X>Xref$. Выбираем этого кандидата.

Эта стратегия звучит многообещающе, но нужно уточнить деталь: установить, какому количеству людей вы должны отказать.

Когда число $R$ слишком велико, вы можете заложить высокие критерии отбора. Но вы рискуете также сказать нет лучшему кандидату. Когда число $R$ слишком мало, у вас будет скучная точка отсчета. Вы, вероятно, выберете неоптимального кандидата. Что нам нужно сделать, так это найти оптимальное значение $R*$ количества отказов, учитывая $N$ кандидатов в общей сложности. Чтобы понять это, нам понадобится немного математики.

Однако прежде чем заняться математикой, всегда разумно перепроверить, имеет ли смысл общая идея. Рассмотренную стратегию удобно тестировать в случае $N=3$ претендентов. Здесь единственная значимое количество людей, которому следует отказать, это $R=1$. В противном случае вы всегда выберете последнего кандидата, если $R=2$, или первого, если $R=0$, и оба случая будут просто случайной стратегией.

На приведенном ниже рисунке показаны все 6 возможных комбинаций прибытия трех кандидатов вместе с соответствующими результатами стратегии вызвать первого кандидата, а затем выбрать следующего лучшего (в противном случае последнего).


Тестирование оптимальной стратегии остановки с тремя кандидатами.

Стратегия способна выявить лучшего в трех сценариях из шести. То есть мы имеем вероятность успеха $Р=1/2$. Это больше, чем $P=1/3$ случайной стратегии. Теперь, когда наш метод, кажется, работает, стоит сделать некоторые математические расчеты.

Оптимизация стратегии


Во-первых, нам нужно вычислить вероятность успеха $P(R)$ при выборе лучшего кандидата для некоторого значения $R$ из кандидатов, которым отказали. Вероятность успеха можно рассматривать как сумму вероятностей нахождения наилучшего кандидата в позиции $n$, где $n$ может состоять из $R+1$ и общего числа $N$ (т.е. оставшихся кандидатов):


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

Напомним, что принятый кандидат это первый кандидат, набравший наибольшее количество баллов из $R$ отклоненных кандидатов. Однако это не гарантирует, что он также будет лучшим кандидатом в целом. Итак, как рассчитать вероятность того, что выбранный претендент $n$ будет одновременно лучшим? Есть два возможных пути.

Первый способ: рассуждение о втором лучшем кандидате


Выбранный кандидат $n$, несомненно, также лучший, когда второму лучшему было отказано в самом начале. Это означает, что требования были высокими настолько, чтобы продолжать отвергать кого-либо еще, кроме лучшего кандидата.


Визуализация рассуждений о позиции второго по значимости кандидата.

На язык математики это переводится так:


Рассуждение 2(а): вычисляем вероятность успеха, установив, что второй лучший кандидат был отброшен среди первых $R$.

Последнее рассуждение просто выводит из суммы независимые от $n$ факторы. Вот и все. У нас есть формула. Давайте теперь рассмотрим другой способ достижения такого же результата.

Второй способ: рассуждение о количестве зарегистрированных записей


Альтернативный способ потребовать, чтобы был выбран кандидат $n$ и при этом лучший кандидат это представить себе, что нужно последовательно пройти через всех оставшихся кандидатов от $R+1$ до $N$ и бросить специальную монету на каждом.

Монета решит, будет ли этот кандидат регистрировать запись о новом рекордном балле. Из-за случайного упорядочения запись происходит с вероятностью $1/m$, где $m$-позиция текущего кандидата. Нам нужен только один максимальный результат для монеты кандидата $n$, тогда как все остальные монеты должны провалить новый рекорд с вероятностью $1-1/m$.


Визуализация рассуждений о наивысших баллах. Математический эквивалент этой идеи:


Рассуждение 2(b): вычисляем вероятность успеха, установив, что новый высший балл будет иметь место только один раз до последнего кандидата.

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

Оптимальное количество отказов


Теперь, когда у нас есть пуленепробиваемая формула для $P(R)$, можно легко вычислить значения для заданного числа кандидатов и посмотреть, какое оптимальное число отказов $R$ максимизирует вероятность успеха $P(R)$. Это легко реализуется, например, на языке Julia:

Ns = collect(1:50)                       # number of candidatesP(R,N) = R/N*sum([1/(n-1) for n=R+1:N])  # define function P(R)Ropt = zeros(Int64,length(Ns))           # define vector for R*Popt = zeros(length(Ns))                 # define vector for P(R*)for N in Ns                              # optimization loop    Popt[N], Ropt[N] = findmax([P(R,N) for R=1:N])end

Ниже вы можете увидеть график оптимального $R*$ по мере увеличения $N$ и соответствующей вероятности успеха $P(R*)$.



Вверху оптимальное значение отказов, как функция от общего числа кандидатов. Зеленым обозначена вероятность успеха выбора лучшего кандидата, следуя оптимальной стратегии отказов. Красным цветом обозначена низкая вероятность успеха при принятии решения с помощью случайности.

Можно отметить две интересные тенденции. Во-первых, вероятность успеха при оптимальной стратегии не стремится к нулю при больших $n$, как при случайном выборе. Это поразительно. При оптимальной стратегии вероятность выбора именно лучшего кандидата не уменьшается, когда существует произвольно много кандидатов. Просто подумайте об этом: более вероятно выбрать лучшего кандидата из 100 с оптимальной стратегией, чем преуспеть, выбирая наугад между 3 кандидатами.

Во-вторых, оптимальное значение $R*$ следует простой линейной зависимости с $N$. Можем ли мы извлечь из этого практическое правило?

Да, это закон $1/e$.


Закон $1/e$ получил свое название от асимптотического поведения вероятности успеха: отношение $1/e$ точно соответствует значению, при котором вероятность успеха $P(R*)$ сходится для больших $N$. Здесь буква $e$ обозначает число Эйлера, 1/$e$ составляет около 1/2.720.37, как видно из графика.

Точно так же мы наблюдаем, что оптимальное число отказов $R*$ растет с $N$ сродни лестнице, совершая прыжок каждые 3 или иногда 2 единицы. Знаете что? Точный наклон снова равен $1/e$ это означает, что оптимальный $R$ может быть эффективно приближен вычислением $N/e$.

Кажущееся магическим значение $1/e$ может быть явно получено путем приближения второй последней строки на рисунке Рассуждение 2(b) для больших $R$ и $N$, но я опущу это вычисление здесь. Важно отметить, что закон $1/e$ справедлив и для более общих случаев проблемы секретаря. Например, когда также известно общее число заявителей, но нам дан крайний срок, к которому кандидаты могут подать заявку. Для получения более подробной информации о последнем сценарии вы можете обратиться к этой статье.

Заключение


Итак, вы хотите выбрать лучший из нескольких вариантов по принципу бери или уходи, но ничего не знаете о вариантах? Тогда:

  1. Отклоните первые приблизительно $N/2.7$ вариантов.
  2. Выберите вариант лучше тех, что вы увидели.

image

Получить востребованную профессию с нуля или Level Up по навыкам и зарплате, можно пройдя онлайн-курсы SkillFactory:



Подробнее..

Перевод Заключённый использовал одиночную камеру для изучения математики. Сегодня он решает самые трудные уравнения в мире

11.03.2021 20:12:02 | Автор: admin

В 2010 году, некий Кристофер Хейвенс (Christopher Havens) был приговорен к 25 годам тюремного заключения за убийство. В 2020 году его работа по теории чисел была опубликована в научном журнале. Все стены камеры, в которой Кристофер Хейвенс отбывал 25-летний срок за убийство, испещрены бумажными листками с формулами.

Бумажные листы, исписанные числами и греческими символами, уже не помещаются на небольшом столике и теперь, как пёстрые обои, развешаны по всем стенам камеры размером 2.4x3.7 метров. В процессе поиска решений он мог записывать на стенах уравнения непрерывных дробей длиной до 4.5 метров.


Заметки на некоторых листках могли показаться полным бредом, попыткой проникновения в неизвестные глубины математики одному ему известными способами. Заметки на других листах были более осмысленны. Они свидетельствуют о том, что он самостоятельно освоил теорию чисел. Но сам Хейвенс об этом не знал. Он также не знал, что у задачи, которую он пытался решить, решения не было. Охранники и другие заключённые, когда проходили мимо его камеры, с интересом заглядывали внутрь. Для всех он казался чокнутым, но для него это уже не имело никакого значения. Ведь он был на пути к решению. Он был намерен идти до конца. В тюрьму он попал по той причине, что хотел быть как все, не отличаться от других.


Это случилось в ноябре 2012 года уже не в первый раз Кристофер Хейвенс почувствовал, что достиг дна. Это было время, когда он скрывался от закона, и когда семья считала его мёртвым. Были ночи, когда он дрожал от холода на улицах Сан-Франциско. Его лишили опеки над детьми, и он потерял с ними связь. Как и большинство наркоманов, Хейвенс не раз давал клятвенные заверения, что прекратит принимать наркотики и что это было в последний раз.

Но, естественно, всё повторялось снова и снова.

Хейвенс был брошен в одиночную камеру тюрьмы штата Вашингтон в городе Уолла-Уолла. Попав в тюрьму строгого режима после осуждения на 25 лет за убийство, он понял, что именно здесь он сможет прожить достойную жизнь. "Я как-то позвонил из тюрьмы отцу, и он спросил меня, кем я собираюсь стать в тюрьме рыбой-клоуном или акулой", рассказывает он. Хейвенс решил стать акулой. Он попытался примкнуть к тюремным авторитетам и вступить в их братство. Одним из его проверочных заданий было избить другого заключённого. Но вот прошло два месяца после того, как он вошёл в тюремные двери, и он оказался в крошечной неотапливаемой камере, в которой круглосуточно горел свет, и соседи-заключённые выражали свой гнев и разочарование, крича, стуча по стенам, а иногда размазывая фекалии по вентиляционным отверстиям кондиционера. Ему не удавалось заснуть, поэтому он сидел, разгадывал судоку и думал о тех годах, которые ему предстояло здесь прожить.

Хэйвенс мог обвинить отца в том, что тот вынудил его примкнуть к тюремным авторитетам, но он этого не сделал. Он честно признался себе в том, что во всём, что с ним произошло, виноват он сам. Ещё с детских лет ему хотелось всем нравиться. Но желание нравиться сыграло с ним злую шутку он пристрастился к наркотикам, и это в конечном счёте привело его к тюрьме. Желание нравиться бросило его в камеру, где он несколько месяцев пребывал в совершенном одиночестве.

Каждый полдень хотя при включённом свете определить время суток было сложно он слышал, как тюремщик что-то передаёт другим заключённым. "Он что-то передавал в окошко камеры и просто уходил", рассказывает Хейвенс. Так прошло несколько дней, но Хейвенс не стал интересоваться у "мистера Г.", как его называли заключённые, что именно тот передавал в камеры заключённым. Ему хватало своего судоку. Но дни тянулись и тянулись, и он стал понимать, что так больше продолжаться не может ему нужно заняться чем-нибудь, что поможет скоротать время. Он встал у двери и спросил у мистера Г., когда тот проходил мимо его камеры, что именно он передаёт другим заключённым. Мистер Г. не ответил, но на следующий день окошко двери камеры Хейвенса открылось, и кто-то просунул в него листки с какими-то математическими задачками.

И Хейвенс решил посвятить свои 25 лет заключения обучению математике, лелея себя надеждой, что, возможно, когда-нибудь он сможет возвратить свой долг обществу как математик.

Хейвенс бросил обучение на втором курсе института. Учился он неважно, пропускал много занятий и говорит, что почти не помнит, как учился, так как все его мысли в то время занимали наркотики. Но случилось интересное: он стал размышлять над листками мистера Г., и ему всегда удавалось находить решения. "Дошло до того, что я стал заниматься только этим и ничем другим, говорит он. Я мог размышлять над математическими задачами всю ночь напролёт.

Каждый день мистер Г. приносил ему новые и новые задачки. Это были элементарные, легко решаемые задачки. В основном алгебраические, говорит Хейвенс и добавляет, что вскоре он стал просить мистера Г., чтобы тот приносил ему задачи из других областей математики, а также поинтересовался, есть ли у него более сложные задачи. Мистер Г. сказал, что нет. Через несколько месяцев мистер Г. вместо обычного набора задач передал ему "маляву", то есть записку. В записке говорилось: "Мистер Хейвенс, у меня для Вас больше ничего нет. Желаю успеха".

Впервые за долгое время, возможно, с самого детского возраста Хейвенс понял, что он обладатель редкого таланта. Он был обычным мелким воришкой, к тому же наркозависимым, и в те годы, когда хорошо у него получались только плохие дела, он опустился на самое дно. Но теперь каждое решённое уравнение что-то меняло в нём. Он почувствовал мир в душе. Он понял, в каком направлении ему нужно двигаться. Он, по его словам, влюбился в математику. Хейвенс решил посвятить свои 25 лет заключения обучению математике, лелея себя надеждой, что, возможно, когда-нибудь он сможет возвратить свой долг обществу как математик. Однако в своих прогнозах, как скоро наступит его математическое будущее, он ошибся.


Хейвенс отдаёт себе ясный отчет, какие ужасные вещи он творил в прошлом, даже если помнит не всё. В 2010 году, когда он жил в городе Олимпии, штат Вашингтон, где пристрастился к наркотикам метамфетаминам и из-за этого потерял работу в ночную смену в кафе "У Денни", он занялся продажей наркотиков. И однажды убил человека, с которым они вместе торговали наркотиками. Хейвенс объясняет, что опасался того человека и, чтобы не быть убитым, решил убить его первым, и в этом ему помог другой его приятель. Теперь, вспоминая прошлое, Хейвенс говорит, что не уверен, убивал ли он на самом деле или нет, так как в то время его разум был затуманен наркотиками, и любые параноидальные мысли могли представляться ему реальностью. Он хочет вновь оказаться рядом с детьми (их у него пятеро) и с мамой. И ещё хочет найти способ как-то оправдаться перед ними за все свои прегрешения. Если раньше он делал всё, чтобы его родная страна Америка стала более опасной, то теперь, возможно, он мог бы использовать свой талант к математике, чтобы повернуть вспять колесо судьбы.

Хейвенс бросил школу в подростковом возрасте и, естественно, забыл, что операции с числами всегда давались ему очень легко. Когда Хейвенс учился в начальной школе, его мама Терри Форте была поражена тем, как быстро он всё схватывает, особенно что касается математики. Она была медсестрой, отлично справлялась со своей работой, но в математике разбиралась очень слабо. К четвёртому классу успехи сына стали настолько впечатляющими, что учителя стали просить его подтянуть по математике других учеников. Форте говорит, что его сыну нравилось помогать другим детям. Форте была армейской медсестрой, поэтому они часто переезжали с места на место. Хейвенс вспоминает, что "он никогда не пользовался популярностью среди людей и всегда был немного неловким", но после каждого переезда всегда старался побыстрее влиться в новую среду и завести новые знакомства. И вот, умный и добрый ребёнок начал меняться в худшую сторону. В подростковом возрасте, пытаясь не отставать от сверстников, он начал курить траву и употреблять алкоголь, затем последовали грибы, затем ЛСД, затем болеутоляющие таблетки и метамфетамины ведь это употребляли другие подростки. Но он не был плохим ребёнком. Он был просто ребёнком, которому очень хотелось понравиться, говорит Форте. "Он бы отдал последнее, чтобы кому-нибудь угодить, и это одна из причин, по которой мне было так трудно поверить в то, что случилось."

Хейвенс говорит, что благодарен семье за поддержку, особенно матери, которая присылала ему учебники и бумагу. Мать Хейвенса говорит, что её сын с раннего возраста проявлял уникальные математические способности и учителя часто просили его подтянуть по математике других учеников.Хейвенс говорит, что благодарен семье за поддержку, особенно матери, которая присылала ему учебники и бумагу. Мать Хейвенса говорит, что её сын с раннего возраста проявлял уникальные математические способности и учителя часто просили его подтянуть по математике других учеников.

В 2010 году Форте заметила, что её сын, которому сейчас немного за 30, который то "завязывал", то опять принимался за старое, то опять "завязывал", снова сорвался. Она очень хорошо чувствовала, в каком состоянии находится Хейвенс, по тому, как он заботился о своей дочери, которую он взял к себе после того, как её мать передала опеку над ней штату Калифорния. Хейвенс стал отцом-одиночкой, но он занимался чем угодно, только не воспитанием ребёнка. Форте была этим очень обеспокоена.

Внезапный звонок из полиции не стал большим сюрпризом, так как такие звонки раздавались в доме часто, но то, что она услышала в этот раз, стало для нее шоком. Когда из полиции позвонили в первый раз и сообщили, что его посадили в тюрьму за убийство, я им ответила: нет, этого не может быть, и повесила трубку", рассказывает Форте. Но спустя какое-то время она перезвонила в полицию сама. Убийство? Но этого же просто не может быть. Ведь её сын такой добрый ребенок.


Свой первый день в тюрьме штата Вашингтон Кристофер Хейвенс начал с изучения тюремной терминологии слов вроде "очко" и поиска новых друзей. Он мог вновь повторить те же самые ошибки, из-за которых у него было столько неприятностей.

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

После того как Хейвенс закончил решать математические задачки мистера Г., он приступил к изучению тригонометрии, численных методов, а затем полез в такие математические дебри, как гипергеометрическое суммирование. Когда он позвонил матери и попросил, чтобы та передала ему учебник по тригонометрии, она была несколько удивлена. Удивилась она не тому, что он, бросивший школу, стал интересоваться наукой (ведь она знала, что он умный), но тому, что в кои-то веки у него появилось желание сделать что-то не руками, а головой. Через несколько недель, когда он попросил книгу по математике, она уже не удивилась. "Я помню, во времена, когда он был моложе, если он решил что-то сделать, он всегда это делал", говорит Форте. Всё, за что он брался, он доводил до конца, чего бы это ему ни стоило. В детстве, когда он увлекался видеоиграми, он не мог успокоиться до тех пор, пока не пройдёт все уровни, а с футбольных игр возвращался весь измотанный и в синяках.

Он приступил к изучению тригонометрии, численных методов, а затем полез в такие математические дебри, как гипергеометрическое суммирование.

Через несколько месяцев Хейвенс стал просить приносить ему учебники, названия которых были настолько непонятными (например, Вырожденные гипергеометрические функции), что Форте часто его переспрашивала: "Можешь произнести это по буквам? Я вообще не представляю, о чём ты говоришь.

Когда Хейвенса перевели из одиночной камеры в общую, сокамерники заметили изменения в его поведении. "В то время я больше заботился о своем образовании, чем об освоении тюремной культуры". В конце концов один из парней сказал: "Тебе не место среди нас". И, знаете, что я ему ответил? Да, ты прав, вспоминает Хейвенс.


Отрывок статьи Хейвенса, опубликованной в журнале Исследования в области теории чисел.Отрывок статьи Хейвенса, опубликованной в журнале Исследования в области теории чисел.

У Хейвенса нет доступа к компьютеру, поэтому почти все свои работы он пишет от руки. Доказательства теорем часто растягиваются на несколько страниц, так как он анализирует множество вариантов, которые могут привести к решению. Эти страницы (как и многие другие) он отправил в Туринский университет в Италии как подтверждение того, что ему удалось решить ранее никем не решённую математическую проблему. В январе 2020 года его лучшая работа по данной проблеме была опубликована в журнале Исследования в области теории чисел.

Если бы не тюремный срок, возможно, он смог бы примкнуть к команде профессиональных математиков. В январе 2013 года Хейвенс написал письмо в издательство "Математические науки" организацию, занимающуюся изданием ряда престижных математических журналов. В письме он рассказал, что отбывает тюремный срок и пытается изучать высшую математику. "Я попросил их выслать мне несколько журналов, а также спросил, с кем я могу переписываться. Через несколько недель он получил вежливый ответ, смысл которого сводился к тому, что он в этих журналах ничего не поймёт и высылать ему такие журналы они не станут. В этот момент Хейвенс снова почувствовал, что остался совершенно один.

Как выздоравливающий наркоман Хейвенс хорошо знал, во что может вылиться это чувство, и как никогда осознавал собственную уязвимость. "Если вы находитесь на переходном этапе и пытаетесь забыть всё, что было в прошлом, но не чувствуете от людей никакой поддержки, очень вероятно, что вы опять скатитесь в пропасть", говорит он. Но Хейвенс сказал себе, что отступать не собирается. Не в этот раз.


Тюремная жизнь это сплошной хаос. Конечно, в тюрьме действуют свои правила, но такие правила очень часто бывают произвольными и непредсказуемыми. Тюремные сотрудники могут в любой момент изменить обычный режим на режим изоляции. И почти полное отсутствие контроля. Когда ты принимаешь душ, ешь, работаешь и спишь, все это происходит по чьей-то чужой воле. Но, какой бы хаотической ни была жизнь в тюрьме, иногда она бывает крайне монотонной. Хейвенс более или менее представлял, как пройдут следующие два с половиной десятилетия его жизни.

И именно математика помогла Хейвенсу осознать, что у него всё находится под контролем. Существуют правила, и такие правила логичны и последовательны в разных областях. Даже когда Хейвенс понимает основные пути решения проблемы, конечный результат часто оказывается неожиданным. Математика во многих смыслах является идеальным противоядием от тюремного заключения, и математикой в тюрьме занимаются гораздо больше людей, чем можно подумать, говорит Гэри Гордон, доктор философии, профессор математики в колледже Лафайетт в городе Истоне, штат Пенсильвания. Он любил придумывать задачи для раздела "Задачи студенческого журнала для любителей математики Математические горизонты. Для каждого выпуска он придумывал хитрую, но вполне поддающуюся решению задачу, и читатели присылали ему свои решения. Нередко бывали случаи, когда решения его задач ему присылали такие же, как и он, заключённые. "Такие ответы всегда были написаны от руки, поэтому, когда они приходили по почте, я всегда знал, от кого они", говорит он.

В 2015 году Хейвенс послал своё решение Гордону. Тот был впечатлён изобретательностью Хейвенса, его поразил способ, который Хейвенс применил для получения правильного ответа. Было ясно, что у Хейвенса не было даже начального математического образования, так как он не использовал математический аппарат, который, как предполагал Гордон, необходимо было использовать для решения. Но решение, тем не менее, было получено. (Прокрутите вниз, чтобы узнать, какую задачу предлагал решить Гордон в журнале "Математические горизонты". Щёлкните здесь, чтобы ознакомиться с недавно опубликованными Хейвенсом задачами.)

Однако Хейвенсу быстро надоело решать задачи, которые фактически представляли собой числовые загадки. Он хотел стать настоящим математиком, который смог бы двигать вперёд всю математическую науку. В своём письме в издательство "Математические науки" Хейвенс рассказал, что увлекается теорией чисел, то есть хочет изучать целые числа. Теория чисел включает в себя такие разделы, как модульная арифметика, в которой повторяющиеся числовые закономерности помогают понять, как работают обыденные вещи, например, как узнать время в 24-часовом формате, если имеются только часы с 12-часовым циферблатом. Методы модульной арифметики могут оказаться очень полезными в реальной жизни например, при генерации штрих-кодов и шифровании данных. Редакторы издательства "Математические науки" не смогли в должной мере оценить способности Хейвенса, но кто-то передал его просьбу о друге по переписке. И вот однажды он получил письмо из города Турина, Италия.


Модульная арифметика базовое представлениеМодульная арифметика базовое представление

Вы наверняка уже знакомы с модульной математикой, так как совершенно точно представляете, каким образом читаются показания часов. Модульная арифметика получила своё название от латинского слова, означающего "мера" (measure), и определяет методы осуществления подсчётов через последовательность чисел. Модуль, или, для краткости, мод часов, равен 12. Мы считаем до 12, а затем начинаем счёт сначала. Поэтому можно говорить 3 часа дня, но нельзя говорить 15 часов вечера, но при этом число 3 конгруэнтно (то есть равняется) 15 (по модулю 12). Модульная операция это действие взятия остатка при делении числа на модуль. Таким образом, 3 и 15 являются одним и тем же числом по модулю 12, так как оба они дают остаток 3 при делении на 12. Модулем может быть любое положительное число. Например, числа 3 и 5 являются одними и теми же числами по модулю 2, так как как они дают остаток 1 при делении на 2. В отличие от чисел на циферблате часов в модульной арифметике счёт обычно начинается с 0. Поэтому числами, используемыми для арифметического модуля 12, обычно являются числа от 0 до 11. В арифметическом модуле 2 обычно используются только две цифры: 0 и 1. Все чётные числа эквивалентны нулю по модулю 2, а все нечётные числа эквивалентны единице.


Письмо было составлено группой исследователей, изучающих теорию чисел, в частности непрерывные дроби (см. ниже Непрерывные дроби базовое представление). Эти исследователи отказались давать нам интервью, однако дочь одного из них Марта Серрути, доктор философии, профессор Университета Макгилла в городе Монреале написала нам о связи с The Conversation, журналом, в котором публикуются (в основном) научные теоретические работы. Серрути рассказала, что именно она попросила своего отца Умберто Серрути, доктора философии, профессора Туринского университета попросить Хейвенса решить проблему. В ответ Хейвенс прислал длинную, сложную и написанную от руки формулу. "Отец ввёл формулу в компьютер и, к его удивлению, результаты оказались верными!" написала она. Затем Умберто Серрути попросил Хейвенса заняться ещё одной проблемой на этот раз не имевшей решения.

То, что проблема не имела решения, Хейвенс просто не знал. Большинство людей, получивших вторую задачу от Серрути, сразу сдались, когда узнали, что решения у такой задачи до сих пор нет. Но у Хейвенса не было доступа к Google, и он добросовестно приступил к решению задачи. Он сел за работу.

Чтобы понять теорию чисел и, в частности, непрерывные дроби, необходимо окунуться в бесконечность, говорит Хейвенс. Возьмём, к примеру, число пи, это иррациональное число. Последовательность его знаков после десятичной точки продолжается до бесконечности. На первый взгляд, они расположены в совершенно хаотичном порядке. Но на самом деле это не так. Иррациональное число можно записать другим способом в виде непрерывной дроби. Если записать число Pi таким способом, мешанина его десятичных знаков после запятой превращается в ряд упорядоченных и вложенных друг в друга уровней дробей внутри дробей, которые предопределяют все десятичные знаки числа Pi вплоть до бесконечности. В иррациональном числе таких вложенных уровней бесконечное число. В рациональном числе, то есть в числе, имеющем конец, уровни дробей рано или поздно заканчиваются, другими словами, их число конечно.

С 2016 года Хейвенс проводит мероприятия "День пи" в исправительном учреждении города Монро. За эти годы мероприятие посетили группы математиков, в том числе его наставники из Италии. В 2014 году Хейвенса перевели в тюрьму обычного режима в городе Монро.С 2016 года Хейвенс проводит мероприятия "День пи" в исправительном учреждении города Монро. За эти годы мероприятие посетили группы математиков, в том числе его наставники из Италии. В 2014 году Хейвенса перевели в тюрьму обычного режима в городе Монро.

"Для меня непрерывные дроби это святая святых иррациональных чисел", говорит Хейвенс. "Они красивы и чисты, и у них даже есть пульс в том смысле, что их наборы подходящих дробей "пульсируют" в такт колеблющейся арифметической последовательности".

Подходящие дроби представляют собой рациональные числа, которые можно использовать в качестве аппроксимаций при записи непрерывных дробей для иррациональных чисел. Их красота отчасти объясняется в том, что они обеспечивают наилучшее приближение иррационального числа, запись которого в формате десятичной дроби длилась бы бесконечно. При работе с непрерывными дробями, чем больше вычисляется уровней, тем ближе подходящие дроби приближаются к точному значению иррационального числа, но добраться до истинного конечного числа за конечное время никогда не получится. По словам Хейвенса, решение непрерывной дроби означает нахождение всех подходящих дробей для такой непрерывной дроби.


Непрерывные дроби базовое представлениеНепрерывные дроби базовое представление

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

Самый простой способ перейти к непрерывной дроби начать с "простой и конечной" непрерывной дроби, где не будет ничего, кроме единиц в числителях непрерывных дробей, и эта дробь разрешится всего за несколько шагов. Запись непрерывных дробей для иррациональных чисел, таких как Pi, продолжается до бесконечности. Возьмём дробь 37/13. Это одна из "неудобных" неправильных дробей. Дробь 37/13 можно записать как 2 плюс 11/13. Это первый шаг в преобразовании обычной дроби в непрерывную.

Чтобы перейти на следующий вложенный уровень, для деления снова потребуется неправильная дробь. Заменим выражение 2 плюс 11/13 на 2 плюс 1, поделённая на 13/11. Теперь разделим 13 на 11, что, естественно, даст результат 1 плюс 2/11. Это будет наш следующий уровень. Будем продолжать процесс до тех пор, пока число, на которое вы будете делить, не станет равным 1. Мы достигли конца конечной, рациональной непрерывной дроби, так как любое число, поделённое на 1, равняется самому себе.

Для меня непрерывные дроби это святая святых иррациональных чисел. Они красивы и чисты, и у них даже есть пульс в том смысле, что их наборы подходящих дробей "пульсируют" в такт колеблющейся арифметической последовательности.

Задача, которую Хейвенс получил из города Турина, заключалась в изучении того, что происходит с особым типом непрерывной дроби после того, как к ней будет применена особая функция, называемая дробно-линейным преобразованием. Такое преобразование описывается четырьмя числами (a,b,c,d), и оно отображает дробь f на дробь (af + b)/(cf + d). Хейвенс и его коллеги обнаружили, что при применении преобразования к непрерывной дроби возникают новые семейства непрерывных дробей. Ещё одним удивительным открытием было то, что колеблющиеся последовательности в подходящих дробях не всегда линейны. "Этот результат может открыть новые области исследований в теории чисел", написал Серрути в своей работе о Хейвенсе.

У Хейвенса была цель опубликоваться в научном журнале, но то, что произошло дальше, его целью не было. Когда стало известно, что заключённый решил "ранее неразрешимую" проблему, средства массовой информации буквально сошли с ума. В начале августа, когда мне позвонил Хейвенс, он поставил одно условие: чтобы я не сравнивал его с Эвклидом, греческим математиком и отцом теории чисел. В другой статье такое сравнение присутствовало, и Хейвенс испытывал от такого сравнения чувство глубокой неловкости. Те же самые чувства испытывали члены команды в Италии. (Хейвенс попросил меня не обращаться с просьбой дать интервью к Умберто Серрути и не удивился, когда другие члены туринской команды не ответили на мои просьбы об интервью.) Время учёных-одиночек прошло, сегодня учёные работают в составе команд и опираются на результаты множества прошлых работ своих коллег. Хейвенс не выполнял свою работу в одиночку и уж точно не создавал совершенно новую ветвь математики.


Хейвенсу осталось сидеть 14 лет (или 12, если его выпустят досрочно за хорошее поведение). Это ещё более десяти лет, и он уже не сможет наблюдать, как взрослеют его дети. Когда он вернётся в общество, его дети вполне могут сами стать родителями. Однако Хейвенс рассматривает свой приговор не как наказание, а как возможность самостоятельно получить образование и начать здесь новую жизнь. (Он также подчёркивает, что теперь он лучший отец, чем был раньше.) Поскольку Хейвенс самоучка, в его математических знаниях имеются огромные пробелы. Как правило, студенты проходят обучение практически, то есть изучение ими каждого нового предмета базируется на знаниях, полученных при изучении предыдущего предмета. Хейвенсу же приходилось всё время строить догадки с чего начинать, как продолжать? Он пытается заполнить образовательные пробелы и поэтому до сих пор переписывается с членами итальянской команды, а также с профессором математики из Гарварда. После освобождения он планирует получить систематическое образование. Хейвенс прекрасно понимает, что после отбытия срока многим бывшим преступникам удаётся получать только самую низкопробную работу, но он не хочет для себя такого будущего. "Большинство заключённых ждут освобождения и только потом начинают строить карьерные планы", говорит он. Но только не я. В тюрьме я собираюсь доказать, что и здесь можно заниматься делом и расти над собой".

Так, в 2016 году Хейвенс запустил проект "Тюремная математика", получивший признание на национальном уровне. "Моя цель изменить жизнь через ликвидацию рецидивной преступности с помощью математики", говорит он.

Идея проекта была позаимствована у того самого небезызвестного мистера Г., то есть просить заключённых решать математические задачки. Затем заключённые объединяются в пары с научными руководителями, которые будут помогать им в обучении

Большинство заключённых ждут освобождения и только потом начинают строить карьерные планы. Но только не я. В тюрьме я собираюсь доказать, что и здесь можно заниматься делом и расти над собой.

В перерывах между заполнением пробелов в образовании и созданием программ обучения для других заключённых любителей математики Хейвенс посвящает остальную часть своего срока изучению криптографии гораздо более сложной математической науки. Криптография это сохранение информации с помощью математических методов и чисел, а также расширение теории чисел. Фактически именно криптография стала причиной того, что Хейвенс впервые заинтересовался теорией чисел. Он понимал, что для того, чтобы получить хоть малый шанс понять основы криптографии, ему нужно сначала разобраться в теории чисел. Марта Серрути в своей статье упомянула, что Хейвенс искал наставника, и на этот призыв откликнулся доктор философии Амита Сахаи, криптограф из Калифорнийского университета Лос-Анджелеса. Теперь Хейвенс и Сахаи регулярно переписываются. Сахаи говорит, что относит Хейвенса "к числу самых усердных студентов, с которыми я когда-либо имел удовольствие работать на протяжении всей своей научной карьеры".

Он не только усердный, но и невероятно умный и решительный человек. "За последние несколько недель он решил несколько сложных задач, которые в состоянии решить лишь немногие из моих выпускников, закончивших Калифорнийский университет. И это при том, что Кристофер работает один, и уже не говоря о том, что он работает, мягко выражаясь, в неблагоприятном окружении", говорит Сахаи.

Хейвенс может проводить целые дни, работая над проблемами, которые присылает ему Сахаи. Частично его новая одержимость объясняется тем, криптография как наука очень близка к логике и математике. Но есть и другая причина. Он до сих пор чувствует, что наука криптографии это воплощение всего того, что есть в нём самом.

Что нравится в криптографии Сахаи: "В криптографии мы пытаемся достичь невозможных целей. Бывают многие увлекательные случаи, когда какая-либо цель может интуитивно казаться недостижимой, но в конце концов оказывается достижимой". Сахаи точно так же мог бы охарактеризовать Хейвенса.


Сможете ли вы решить задачку из журнала Математические горизонты?

Циферблат (как на рисунке 1) может указывать на любое целое число от 1 до n, если вращать его против часовой стрелки. Отсчёт начинается с 1, затем стрелка поворачивается последовательно (всегда против часовой стрелки) на одну позицию, затем на две, затем на три и так далее, до последнего поворота на n-1 позицию. Например, первыми пятью позициями при n=12 будут 1, 2, 4, 7, 11 и 4. Для каких значений n стрелка циферблата будет указывать на другую позицию на каждом этапе такого процесса?

Представлено Гари Гордоном и Денизом Озбаем, ноябрьский выпуск журнала "Математические горизонты", 2020 год.

Циферблат имеет 12 позиций.Циферблат имеет 12 позиций.

Лучший способ решить эту задачу начать с малого. Циферблат с одной позицией не годится, но мы могли бы попробовать циферблат с двумя позициями. В этом случае начинаем с позиции 1, делаем поворот на одно деление, получаем 2, поэтому последовательность цифр, на которые будет указывать стрелка, такая: 1-2. Это соответствует условиям задачи: на каждом шаге стрелка должна указывать на другую позицию, однако это не тот ответ, который просят представить Гордон и Озбай. Вернее будет сформулировать так: n это тип числа с бесконечными целыми числами, соответствующими требованиям задачи.

Чтобы не рисовать циферблат для каждого значения n, можно переформулировать задачу в терминах модульной арифметики. Для любого n последовательность позиций стрелки циферблата будет такой же, что и последовательность, при которой мы начинаем с 1 и добавляем сначала 1, затем 2, затем 3, и так весь путь до n-1, всё по модулю n. Поэкспериментируйте сами с такой последовательностью, чтобы понять мою идею. Если Вы это сделаете, то для n=3 у Вас получится последовательность 1-2-1; для n=4 у Вас получится последовательность 1-2-4-3 (ещё одна, соответствующая критерию); а для n=5 у Вас получится последовательность 1-2-4-2-1.

Случай, когда n=6, особенно показателен. Начнём с номера 1, затем добавляем 1, чтобы получить 2. К нему добавляем 2, чтобы получить 4, затем добавляем 3, чтобы получить 7 (то есть 1 по модулю 6), 4, чтобы получить 5, и 5, чтобы получить 10 (то есть 4 по модулю 6).

Таким образом, искомой последовательностью является 1-2-4-1-5-4, и мы повторили не одно, а два числа. Между первым и вторым номером 1 мы добавили 1+2+3, или 6, что соответствует n. Между первым и вторым номером 4 в нашей последовательности мы добавили 3+4+5, или 12. В обоих случаях мы получили последовательность последовательных чисел, которая в сумме даёт число, кратное 6.

Попробуйте сами и подумайте, сможете ли Вы угадать, какие числа подходят или не подходят под критерии повторяемости Вашей последовательности. Если такая догадка у Вас появится, можно попробовать вежливые числа и попытаться понять, имеют ли они отношение к данному вопросу.

Пример Кристофера доказывает, что человек может научиться чему захочет, даже находясь в самых неблагоприятных для этого условиях. Но путь самостоятельного обучения может быть (не всегда!) подобен блужданию слепого в темной комнате, так что без опытных менторов и поддержки, которые за руку проведут по всему пути не обойтись. Если вам нужно подтянуть математику, то у нас на курсе математика для Data Scienceи его расширенной версииматематика и Machine Learning для Data Science у вас будут и опытные менторы и внимательная поддержка.

Узнайте, как прокачаться в других специальностях или освоить их с нуля:

Другие профессии и курсы
Подробнее..

Из песочницы Как приоритизировать фичи в продукте

04.11.2020 14:09:33 | Автор: admin

Приоритизация секретный ингредиент?


Согласно определению из Википедии: Приоритизация понятие, показывающее важность, первенство. Например, приоритет действий определяет порядок их выполнения во времени
Из определения становится понятно, что основная цель приоритизации понять, что важнее чего.

Казалось бы, что сложного? Выбрал те задачи для реализации, что повысят метрики компании, а остальные убрал поглубже в бэклог до лучших времен. Звучит действительно просто, когда у тебя немного задач.

Но что делать когда задач больше?

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

Петр выходит из переговорки держа под мышкой свой ноутбук. Облегченный выдох, настроение приподнятое. Только что у Петра закончилось многочасовое совещание с командой по генерации идей и задач на следующий квартал. По началу конечно шло тухло, но вскоре у команды случилось прозрение и идеи полились рекой. Мы обречены на успех подумал Петр, придя на свое место. Теперь осталось только выбрать с чего же начать победоносное шествие. И тут уже энтузиазм заметно падает перед списком:

1) A/B тест лендинга 1 и лендинга 2

2) Дизайн дашборда

3) Интеграция CRM для отдела продаж

4) Добавить базу знаний для пользователей


27) Welcome бонус при регистрации пользователя

Что же первое взять в работу? А второе? Ну дальше? Почему не наоборот?

image

Разумеется, реализовать их все вряд ли получится. Все упирается либо во время, либо в деньги. Но как правильно оценивать и отсеивать фичи?

Существует различные подходы к оценки той или иной задачи. Ниже разберем основные из них.

Быстрая приоритизация. А не фигню ли я делаю?


Данный метод представляет собой народное мнение команды. Во многих случаях это особенно полезно, когда фичи затрагивают несколько категорий. Одна фича для отдела саппорта, другая для отдела продаж, третья для маркетинга и т.д

В этом подходе мы используем метод Poker Planning:

image

Сам процесс по шагам выглядит так:

  1. Продакт- менеджер с командой обсуждают пользу каждой фичи и ставят свою оценку от 1 до 3. Где 3 супер полезно, а 1 минимально. Записывается среднее значение в таблицу.
  2. Тоже самое повторяем с оценкой затрат. Важно: затраты нужно обсуждать не с коллегой на кухне, а непосредственно с теми кто выполняет задачу.
  3. Получаем соотношение польза/затраты и видим, что 1 и 3 задача лидируют- значит, их можно взять в ближайший спринт.

Быстрая приоритизация. А не фигню ли я делаю?


Данный метод представляет собой народное мнение команды. Во многих случаях это особенно полезно, когда фичи затрагивают несколько категорий. Одна фича для отдела саппорта, другая для отдела продаж, третья для маркетинга и т.д

В этом подходе мы используем метод Poker Planning

image

Сам процесс по шагам выглядит так:

  1. Продакт- менеджер с командой обсуждают пользу каждой фичи и ставят свою оценку от 1 до 3. Где 3 супер полезно, а 1 минимально. Записывается среднее значение в таблицу.
  2. Тоже самое повторяем с оценкой затрат. Важно: затраты нужно обсуждать не с коллегой на кухне, а непосредственно с теми кто выполняет задачу.
  3. Получаем соотношение польза/затраты и видим, что 1 и 3 задача лидируют- значит, их можно взять в ближайший спринт.

RICE


image

Данный подход был разработан в компании Intercom. После тестов ребята остановили на 4 важных факторах:

  • Reach (охват) скольким пользователям мы улучшим жизнь?

Охват измеряется количеством людей / событий за период времени.

  • Impact (эффект) насколько мы улучшим жизнь нашим пользователям

Воздействие трудно измерить довольно точно. Поэтому для удобства можно сделать следующие варианты: 3 для сильного воздействия, 2 для высокого, 1 для среднего, 0,5 для низкого и 0,25 для минимального.

  • Confidence (уверенность) насколько мы уверены, что вообще можем что-то улучшить?

Здесь есть 3 градации уверенности:

100% высокая
80% средняя
50% низкая

  • Effort (усилия) сколько времени нам понадобится, чтобы реализовать задуманное?

В основном измеряется в человеко-месяцах. То есть объем работы, которую человек может выполнить за 1 месяц. Используем по возможности целые числа. Если 1 месяц, то значение 1,0. Если занимает меньше месяца, то значение 0,5.

image

Далее после того как умножим первые 3 параметра друг на друга и поделим на усилия, мы получаем итоговый счет. Чем выше счет тем важнее реализация той или иной задачи.

MoSCoW


Метод MoSCoW позволяет разделить все активности, хотелки и вновь прилетающие задачи на 4 категории, что намного эффективнее.

  • Must то, что необходимо сделать в любом случае. Без выполнения этих задач продукт не будет работать в принципе.
  • Should не самые важные требования, но они тоже должны быть выполнены. Естественно, после реализации must.
  • Could желательные требования, которые можно сделать, если останется время и будут ресурсы.
  • Would требования, которые хотелось бы сделать, но их можно проигнорировать или перенести на следующие релизы без вреда для продукта.

Отсюда как раз идет аббревиатура MoSCoW. Разберем данный подход на примере ремонта новой квартиры в новостройке:

  1. M делаем электричество, трубопровод, клеим обои, кладем плитку или паркет. Устанавливаем туалет, ванну, делаем кухню и базово в спальню хотя бы просто кровать.
  2. S покупаем мебель, шкафы, холодильник, микроволновку, стол, стулья, стиральную машину.
  3. C установка посудомойки, дополнительные шкафы, кран с вытягивающимся шлангом, подсветка по периметру шкафов или на потолке.
  4. W сервоприводы для ящиков, подсветка внутри шкафов, крутящаяся полка для углового шкафа, акустическая система, сетка на окнах от комаров, теплый пол, видеодомофон.

Плюсы: просто, быстро, понятно заказчику (если это не технический специалист)
Минусы: не сильно объективно, не учитывается техническая сложность и риски

ICE Scoring: Как это работает?


Рассчитайте оценку для каждой фичи или идеи, согласно формуле:

image

  • Влияние показывает, насколько ваша идея положительно повлияет на ключевой показатель, который вы пытаетесь улучшить.
  • Легкость реализации это о простоте реализации. Это оценка того, сколько усилий и ресурсов требуется для реализации этой идеи.
  • Уверенность показывает, насколько вы уверены в оценках влияния и легкости реализации.

image

В ICE используется шкала от 1 до 10 чтобы все факторы сбалансированно влияли на итоговый бал. Вы можете подразумевать под 110 то что вам нужно, лишь бы значения были согласованы между собой.

В качестве примера, применим это к фиче Виджеты для Dashboard:

  • Влияние: насколько это будет эффективно? Что это даст нашим пользователям и их целям и задачам?
  • Легкость реализации: насколько легко будет разрабатывать, тестировать и запускать эту фичу?
  • Уверенность: как я могу быть уверен, что эта фича приведет к такому улучшению, которое я описал в Impact и займет столько-то времени?

Недостатки ICE


ICE Scoring иногда подвергается критике за его субъективность:

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

Резюме


Описанные в статье подходы к приоритизации не единственные, но почти все они базируются на одних и тех же принципах.

В заключении приведу краткий алгоритм приоритизации:

  1. Найдите ТОП-3 ключевые метрики для конкретного сервиса.
  2. Соберите гипотезы для прокачки этих метрик: из бэклога или вне его.
  3. Если рынок новый используйте качественные методы: спрашивайте у потенциальных юзеров, чем они сейчас пользуются.
  4. Проведите быструю оценку и отбросьте слабые фичи.
  5. Проведите детальную оценку оставшихся фичей.
Подробнее..

Странные решения задач. Занудство или нестандартный подход

05.11.2020 14:15:50 | Автор: admin
Добрый день. У старшего сына наступил такой возраст (5 класс) что он участвует в куче олимпиад по математике, программированию и английскому. Часто задачи ставят в тупик и меня.
кадр из х/ф Феномен
Но вот недавно сын подошел после олимпиады по Финансовой грамотности на ресурсе ЯКласс, где после окончания выложили результаты и решения, с вопросом почему его решение неправильное. Рассмотрев решение от авторов и решение сына, погрузился в решения и уточнения, получив неоднозначные результаты. Эта ситуация напомнила мне мою молодость и не согласие со многими классическими задачами и их решениями. Далее под катом эта и другие задачи, в которых включается режим зануды.

Вот текст задачи
За какое время окупятся куры? (задача из Арифметики Леонтия Магницкого)
Один человек купил трёх кур и заплатил за них 45 копеек. Первая курица несла по 2 яйца за 4 дня, вторая по 2 яйца за 3 дня, а третья по 1 яйцу за 2 дня. Продавал он яйца по 5 штук за полкопейки. За какое время окупятся куры? Запиши ответ числом без точки.
Сама задача с ЯКЛАСС с решением автора

Даже если вы ещё не посмотрели решение, думаю для вас очевидна логика решения данной задачи с точки зрения математики, большинство из вас решат её даже в голове. Но олимпиада проводиться по Финансовой грамотности, и прочитав условия внимательно ещё раз начинают закрадываться смутные сомнения.
И действительно, вот купили мы три курицы каждая несется раз в сколько то дней, но в каком состоянии она сейчас, например первая, самая так сказать сложная в прогнозе. Может сегодня два яйца снесёт, может завтра, может вообще через три дня.
Вывод номер 1: С учётом условий задачи, каждая из трех куриц может находится на момент в произвольном состоянии (1-я в одном из 4-х, 2-я в одном из 3-х, третья в одном из 2-х).
Вывод номер 2: Состояние куриц друг относительно друга тоже может быть разным. Соответственно всего три курицы могут быть в одном из 24-х сочетаний состояний.
Но и это ещё не всё находясь в различных состояниях друг относительно друга, они несутся с разной периодичностью, следовательно в каждом сочетании есть цикличность, и этот цикл 12 дней. Курицы могут быть куплены нами в любой из дней 12-ти дневного цикла.
Итог у нас может быть 288 различных сочетаний, несомненно многие из них повторяются, это теоретический предел.
Имея все эти данные, достаточно просто составить таблицы того как несутся куры во всех вариантах, в результате чего мы узнаем что на самом деле срок окупаемости варьируется от 269 дней до 272 дней. Проанализировав все варианты получаем следующую гистограмму распределения по дням окупаемости:

В итоге верный ответ на данную задачу по финансовой грамотности (с моей точки зрения) должен звучать так:
В 17,3 % случаев срок окупаемости будет 269 дней;
В 35,4 % случаев срок окупаемости будет 270 дней;
В 39,8 % случаев срок окупаемости будет 271 день;
В 7,5 % случаев срок окупаемости будет 272 дня.
На картинке в начале запечатлен кадр из фильма Феномен (1996 Phenomenon), и этот эпизод как раз про похожую ситуацию, когда вроде бы оригинальные вопросы, на определенном уровне восприятия показывают ограниченность их предыдущего рассмотрения.
Посмотрите пять минут беседы главного героя с исследователем

Никакого ответа от службы поддержки ЯКласс, получено не было, хотя ситуацию описал подробно с приложением расчётов в excel, что конечно огорчило формализмом в таком важном деле как развитие детей.
Такая задача не исключение, мне в школе всегда не нравилась другая задача: Имеется три слова: Кошка, Солнце, Близко. Какое слово лишнее?. После прохождения тестирования, узнал, что лишнее слово Близко, потому что прилагательное. Я же руководствовался логикой количества букв и лишним посчитал слово КОШКА. Если посидеть и подумать можно придумать ещё несколько логических исключений любого слова в представленном примере (мы с сыном придумали пять вариантов). И вот у ребенка возникает вопрос, чем мои логические измышления хуже чем у автора теста.
Очень много дискуссий вызывает задача: На стене висят часы, у которых минутная и часовая стрелка совпадают каждые 65 минут, в точности. Они спешат, отстают или идут правильно?

Должны ли мы приводить мышление детей к общим стандартам, чтобы он вписался в социум, или надо поддерживать креативность и широту мысли. Как всегда истина где-то по середине, но думаю без нестандартной логики, что то выдающееся в этом мире не сделать.
Подробнее..

Как я начал с бумаги и перешел в цифру, оставив только творческие процессы

19.10.2020 12:14:37 | Автор: admin

Всем привет,в этой статьея рассказывал о том, как купил себе физический таймер, потому что хотел аналоговый и физичный прибор для визуализации времени. Я говорил о том, что напишу отдельный материал о цифровых и аналоговых процессах:

Многое со мной и так происходит в диджитале, и я стал делегировать некоторые процессы в офлайн. Я строю майндмэпы на бумаге, изначально строю карты бизнес-процессов в блокноте, иногда пишу вводные тасклисты в блокноте, а потом переношу их в Todoist. Митинги я тоже стараюсь проводить на бумаге: учусь визуализировать идеи, потому что писать в стену глупо, а запоминать проще образами. Короче, я напишу об этом отдельную статью.

Эту статью вы и читаете.

История упорядочивания процессов

Всё началось несколько лет назад, когда меня посетила навязчивая идея создать жесткую структуру всего: одежды, файлов, счетов за квартиру и кабелей рабочего стола.

Сам процесс не был упорядочен я понемногу фиксил отдельные баги и вел бэклог в заметках.

В определенный момент я понял, что мне нужно структурировать и сам процесс, в первую очередь я хотел организовать рабочую часть своей жизни:

  1. организация файловой системы;

  2. организация рабочего процесса: постановка задач, календарь, заметки;

  3. Обработка входящей информации и сегментация;

  4. Бэклог и рефлексия.

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

Если интересны частные детали системы, как выстроены приложения и процессы, напишите в комментарии, я подготовлю отдельный материал.

После успехов интеграции этих решений я перешел и к остальным сферам своей жизни: ввел аналогичные решения в писательство, подкаст и домашние дела.

Аналоговый старт

В студенчестве я носил с собой маленький блокнотMoleskineи ручку: это был мой список задач и блокнот для заметок. Мне нравилась эта система, тогда у меня уже был Evernote и Google Календарь, но я был фанатом BlackBerry OS, которая уже не очень дружила с новыми продуктами, в отличие от iPhone и Android. Так я перешел к первой структуре планирования дел задачи на неделю.

Система очень простая, но достаточно эффективная: дни недели расположена в ряд, вертикально идут планируемые дела. Существует 4 знака дела: запланировано (точка), выполнено (галочка), отменено (крестик), перенесено (стрелка). Благодаря этой структуре работает такой подход:

  1. в начале недели я выписывал все дела в столбик, как в обычном тасклисте;

  2. затем проставлял точки: что и когда нужно было сделать;

  3. потом приступал к работе: сделал галочка, перенес из-за другого приоритета стрелочка и так далее;

  4. в конце дня результативность можно посмотреть по вертикальной оси;

  5. В конце недели можно посмотреть все дела и перенести невыполненные на следующий лист.

Так это превращается в блокнот на 52 разворота, потому что соседнюю страничку я оставлял для заметок. С этой системой я провел год. Позже она переросла в Bullet Journal.

Мое мнение о Bullet Journal

Для тех, кто не знает,Bullet Journal метод ведения заметок и дел, позволяющий сократить время и объем контента в блокноте. Мне очень нравилась эта идея на старте, и я много из нее подчеркнул для будущих систем. Оригинальный Bullet Journal заполняется так:

Есть метки для типа записи: событие, заметка, задача. Есть короткое описание.Что мне нравилось:

  • быстрый ввод информации: мой день заполнялся буквально за считанные минуты;

  • быстрая обработка: сразу проставляете метки задач и событий;

  • свобода бумаги: мне нравится работать на бумаге и концентрироваться на плане.

На этом, пожалуй, плюсы для меня закончились.

Какие минусы:

  • постоянно носить с собой книжку;

  • постоянно переносить и переписывать изменения;

  • заполнение Future Log и Month Log превращается в дизайн;

  • загрязнение и испорченный визуал, когда делается в спешке.

Иногда Bullet Journal буквально становится чем-то культовым и превращается в такое:

Мне, конечно, такое не подходит, потому что заполнение и создание структуры занимает больше времени, чем само ведение. В первую очередь для меня это был инструмент, несмотря на моё дизайнерское прошлое и факт того, что я невероятный визуал. НаPinterestесть целый тег для людей, которые придумываю всё новые и новые системы для своих Bullet Journal, и это просто безумие.

Я ушел с Bullet Journal и понял, что базовый фрейм работы у меня должен быть цифровой: я не забываю телефон дома, все оформительство на себя забирают приложения, а нужную информацию можно искать, фильтровать, структурировать.

Почему цифра

Я забывал бумажные блокноты, не заносил в них дела, но самое важное: перелистывание для поиска. То, что в цифровых записях я способен найти за секунды, на бумаге я судорожно искал минутами.

Я каждый раз чувствовал себя идиотом, когда искал нужную строчку в бумажных записях.

Я писал о софте, которым пользуюсь без описания собственной структурыздесь, в этой статье я не хотел бы отвлекаться на это. Одно было ясно: мне нужно уйти на цифру. Конечно, сегодня большое множество предложений: поиск и привыкание заняли у меня не один месяц, а структуру системы я постоянно дорабатываю. Сейчас мы внедряем подобие спринтов дома, когда пробуем что-то новое, формируем контент-план для подкаста и статей в Notion (жду комментариев про продуктовые подходы).

Цифровые продукты имеют следующие преимущества:

  • Быстрота ввода: телефон всегда в кармане, по всей системе у меня есть так называемый Inbox, куда можно кинуть всё что угодно в два тапа, а потом распределить в нужное место на компьютере.

  • Уведомления: то, что не даст ни один аналоговый продукт. Так я не забываю про дела и рефлексию. Я уже писал статью про настройки своего телефона, её можно почитатьтут.

  • Тегирование: ультимативное решение для структуры верхнего уровня. На бумаге такое можно исполнять цветом.

  • Поиск: здесь без комментариев, это стало основным триггером к цифровизации.

В определенный момент у меня в цифре было все и это перебор в другую сторону. Мне казалось, что цифра снижала мою креативность, потому что я пользовался шаблонами и ограничен функционалом приложения. Тогда я понял, что мне нужен баланс.

То, что поддаётся четкому фрейму уже существующей системы должно быть в цифре, размышления же я веду на бумаге.

Баланс и что осталось на бумаге

Сейчас я стараюсь балансировать между двумя методами: на бумаге я делаю всё то, у чего нет фреймворка. Вот несколько примеров:

  • Визуализация. Мне нравится идея простого скетчинга, поэтому я зарисовываю работу: так создаются обложки для моих статей, так я придумываю структуры для инфографики, иногда формирую советы для UI.

  • Описание процессов. Я консультирую проекты и мне часто нужно формировать структуры процессов это я начинаю делать на бумаге и потом переношу в цифру. Бумага позволяет ошибаться, мусорить и пачкать, оставляя след хода мысли.

  • Заметки переговоров. Когда у меня встречи в офлайне, я не записываю на них вообще это формат живой беседы и мне кажется странным конспектирование слов клиента. Но как только я остаюсь один в дело идет ручка. Я зарисовываю структуру задач, записываю тезисы и заношу сроки: короче говоря, конспектирую. Если мы говорим по телефону: всё это я делаю в режиме live.

Для этого у меня есть блокнот: я пользуюсь мягкимLeuchtturm. А ещё ручкаFischer Space Pen: она действительно безотказно пишет и не занимает места.

Всё бумажное я стараюсь оцифровывать: документы, договоры, справки, выписки, счета и прочее. Так мне проще искать нужную бумажку и ничего не терять. Разумеется, у меня есть резервное хранилище с оригиналами этих бумаг дома. Все заметки по работе с клиентами я переношу в проект, внутри которого задачи, а схемы строю в нужном софте.

Итоги

Мне не нравилось, что всё время я проводил за компьютером, поэтому часть процессов я вернул на бумагу. Думаю, это вовсе не обязательно, но благодаря этому я подхожу к бумаге, как к другой задаче: мне нравится сесть за чистый лист и почиркать по нему ручкой. Мне нравится скетчить идеи и зачёркивать ошибки, потому что они остаются видимыми, в отличии от backspace. Может, в этом есть что-то архаичное и даже вычурное, но я чувствую бльшую вовлеченность в процесс. Есть ли что-то в вашей работе, что вы оставили вне клавиатуры?

Подробнее..

Трекинг ног и пет-паспорта no-code решение для банка задач

15.04.2021 10:21:55 | Автор: admin

Весной 2021 проходит шестой запуск проектно-образовательного интенсива От идеи к прототипу Университета 20.35. В нём студенты придумывают идеи для будущих технологических проектов самостоятельно, либо получают их от инновационных бизнес-компаний. С 2020 года в интенсивах существует Банк задач чуть больше чем за год в проект привлечено 30+ компаний, в 25% случаев заказчики предлагали студентам стажировку или работу по итогам интенсива, не менее половины команд решили задачи и показали прототипы на финале проектного трека.

Новый запуск принёс и новую форму самого банка no-code решение публичной витрины для прозрачного и доступного бронирования задач. Нажав на карточку, пользователь может прочесть краткое описание, а также увидеть тематические теги и название вузов, взявших задачу для своих студентов. Рассказываем, как это было.

Наташ, мы всё уронили

В прошлых волнах интенсивов отраслевые партнёры уже не раз предлагали студентам проектные задачи. При этом формат, в котором вузы получали эти кейсы, оставлял желать лучшего: масштабная сводная таблица с перечнем компаний, краткими описаниями задач, колонкой для бронирования и ссылками на внешние pdf-файлы с подробными расшифровками.

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

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

Как мы пришли к Airtable

В предыдущем запуске отраслевые партнёры предложили 13 задач, весной 2021 их стало уже вдвое больше вопрос, где разместить эти 28 кейсов, чтобы всё не превратилось в хаос. С помощью Airtable удалось разработать удобное и опрятное решение для всех пользователей: организаторов интенсивов, проектных наставников и координаторов в вузах, компаний.

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

На витрине расположены карточки со всеми задачами для студентов весеннего запуска интенсивов, каждый пользователь видит:

  • краткое описание того, что предстоит сделать,

  • тематику задачи (например, агротех, дизайн, VR или чат-боты),

  • требования к команде (если компания оставила пожелания),

  • подробную расшифровку в pdf-файле

  • бронирования от вузов кто уже взял эту задачу

При том, что задач стало больше, благодаря системе тегов можно легко ориентироваться и сортировать подходящие для вуза кейсы. Расшифровки в pdf открываются на той же странице, а значит никто не потеряется по пути обратно к карточке. Новый подход показал: больше не нужно проводить подробные вебинары с инструктажем как пользоваться таблицей. Хотя руководители проектной деятельности и получили объяснение, как работает витрина, многие наставники разобрались с ней самостоятельно. И больше никаких проблем из-за прав доступа или возможной порчи документа. Посмотрев задачи, представитель вуза переходит на страницу бронирования: в заявке можно сразу указать все кейсы, которые хочется взять для студентов и не заполнять форму по несколько раз.

С появлением такого no-code решения организаторы интенсивов получили возможность модерировать заявки на бронирование задач, один кейс могли взять себе три вуза. Если желающих было больше, их можно отсечь по времени заполнения формы на бронирование кто не успел, тот опоздал. К тому же в следующий раз не понадобится создавать новый документ или страницу: существующая витрина обновится с появлением свежих задач. Иными словами, файл для внутреннего пользования превратился в наглядный пример как для университетов что их студенты могут получить в качестве бизнес-кейса для проекта в интенсиве, так и для компаний что и в каком формате они могут предложить в качестве задачи.

А что сейчас?

В марте 2021 года координаторы 29 вузов выбрали 27 задач из 28 предложенных, самыми популярными по количеству запросов оказались задачи edtech, медицинско-ветеринарного профиля и агротех. Традиционно высокий спрос на решения data science и веб-разработку.

Уфимский ГАТУ вдохновился примером Банка и воспользовался готовым шаблоном на Airtable от разработчиков Университета 20.35. Так студенты этого вуза смогли асинхронно выбрать предложенные задачи с помощью витрины и наглядно записаться в интересующие их проекты.

Что даёт участие в Банке задач стартапам и компаниям:

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

решить не самую приоритетною задачу за счёт внешнего ресурса без лишних затрат;

предложить себя в качестве работодателя в обход конкуренции с большими и популярными корпорациями, чтобы студенты познакомились со спецификой бизнеса и корпоративной культурой стартапов;

прокачать навык менторства и получить новые идеи для решений других задач от студентов

К слову, если вы тоже хотите, чтобы студенты интенсива потрудились над задачей вашей компании, оставьте заявку: http://business.2035.university.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru