Собеседование в Яндекс v.2023г

Привет! Особенно @kesn сейчас расскажу почему!

Ко мне в телеграмм постучалась очень приветливая и милая девушка HR из Яндекса, с предложением о работе. Я очень обрадовалась, особенно потому, что рынок IT в 2023 очень нестандартный :-)

Созвонились на 15 минут, мне рассказали об этапах — три алгоритмических интервью, по две задачи в течение часа, третье — с независимым экспертом Яндекса и на целых 1,5 часа. Скинули ссылки на leetcode, CodeRun, пара видео с разбором задачек на доске с фломастером и статья Яндекса о том, как они нанимают бэкэнд разработчиков.

Я просмотрела эти материалы и достаточно быстро нашла статью. Хм, интересно! Изначально у меня не было высоких ожиданий относительно интервью, у меня двухлетний опыт Java разработки, и нет идей как алгоритмический live-coding в три этапа поможет вычленить нужного проекту кандидата. И да, я не готовилась.

Интервью 1. Очень приятный молодой человек, прекрасно вел интервью и поддерживал, так как видел мое волнение. 

Задача 1

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

Input: s = "eceba", k = 2

Output: 3

Решение:

public class Main {

    public static void main(String[] args) {

        String s = "eceba";

        int k = 2;

        System.out.println(lengthOfLongestSubstringKDistinct(s, k));

    }

    public static int lengthOfLongestSubstringKDistinct(String s, int k) {

        if (k == 0 || s == null || s.length() == 0) {

            return 0;

        }

        if (s.length() < k) {

            return s.length();

        }

        Map map = new HashMap<>();

        int left = 0;

        int max = 1;

        for (int right = 0; right < s.length(); right++) {

            char c = s.charAt(right);

            map.put(c, map.getOrDefault(c, 0) + 1);

            while (map.size() > k) {

                char leftChar = s.charAt(left);

                if (map.containsKey(leftChar)) {

                    map.put(leftChar, map.get(leftChar) - 1);

                    if (map.get(leftChar) == 0) {

                        map.remove(leftChar);

                    }

                }

                left++;

            }

            max = Math.max(max, right - left + 1);

        }

        return max;

    }

}

Окей!

Ожидаю вторую, я осведомлена о потоке задач, который должен на меня свалиться. Но вау! Второй задачи на первом интервью нет! Как воодушевляет! Вместо этого интервьюер задавал вопросы про работу HashMap, TreeMap, его вращение, потокобезопасность, ну круто!

Интервью 2. Еще более молодой и такой же приятный человек начинает интервью. 

Задача 1

Перенести нули в конец массива, сохранив порядок остальных элементов

[1,0,8,9] → [1,8,9,0]

Решение:

public class Main {

    public static void main(String[] args) {

        int[] nums = {1, 0, 8, 9};

        moveZeroes(nums);

        for (int i : nums) {

            System.out.print(i + " ");

        }

    }

    public static void moveZeroes(int[] nums) {

        if (nums == null || nums.length == 0) return;

        int insertPos = 0;

        for (int num: nums) {

            if (num != 0) {

                nums[insertPos++] = num;

            }

        }        

        while (insertPos < nums.length) {

            nums[insertPos++] = 0;

        }

    }

}

Задача 2

Дан массив из нулей и единиц. Нужно определить, какой максимальный по длине подинтервал единиц можно получить, удалив ровно один элемент массива.

[1, 1, 0]

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

Решение:

class Main {

    public static void main(String[] args) {

        int[] arr = {1, 1, 0};

        System.out.println(maxOnesAfterRemoveItem(arr));

    }

    static int maxOnesAfterRemoveItem(int[] arr) {

        List ones = new ArrayList<>();  

        List zeros = new ArrayList<>(); 

        int n = arr.length;

        int l = 0;

        for (int r = 0; r < n; r++) {

            if (arr[r] == 0) {

                ones.add(new int[]{l, r});

                zeros.add(r);

                l = r + 1;

            }

        }

        ones.add(new int[]{l, n});

        int maxOnes = 0;

        for (int i = 0; i < zeros.size(); i++) {

            int onesBefore = ones.get(i)[1] - ones.get(i)[0];

            int onesAfter = ones.get(i + 1)[1] - ones.get(i + 1)[0];

            maxOnes = Math.max(maxOnes, onesBefore + onesAfter);

        }

        return maxOnes;

    }

}

После этого интервью я решила посмотреть откуда генерируют задачки и была невероятно удивлена, что они уже встречались пару лет назад. Как-то странно, это же первая ссылка по запросу «Собеседование Яндекс». Окей, думаю случайность, продолжу не готовится!  

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

Интервью 3. Независимый эксперт очень суров и непреклонен, никакой вежливости, только хард скиллы!

Задача 1

Дан отсортированный массив чисел а, индекс элемента index и целое число k. Необходимо вернуть в любом порядке k чисел из массива, которые являются ближайшими по значению к элементу а[index].

find_k_closest (a={2,3,5,7,11}, index=3, k=2) → {5,7}

find_k_closest (a={4,12,15,15,24}, index=1, k=3) → {12,15,15}

find_k_closest (a={2,3,5,7,11}, index=2, k=2) → {5,7} или {3,5}

Решение:

 public static List findKClosest(int[] a, int index, int k) {

        int left = index - 1; 

        int right = index + 1; 

        List result = new ArrayList<>();

        result.add(a[index]); 

        if (k == 0) {

            return result; 

        }

        result.add(a[index]);

        k--;

        while(k-- > 1) {

            if(left < 0) { 

                result.add(a[right++]);

            } else if(right >= a.length) { 

                result.add(a[left--]);

            } else if(Math.abs(a[left] - a[index]) <= Math.abs(a[right] - a[index])) { 

                result.add(a[left--]);

            } else { 

                result.add(a[right++]);

            }

        }

        return result;

    }

}

Задача 2

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

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

Решение:

class Point {

    int x;

    int y;

    Point(int x, int y) {

        this.x = x;

        this.y = y;

    }

    @Override

    public boolean equals(Object o) {

        if (this == o) return true;

        if (o == null || getClass() != o.getClass()) return false;

        Point point = (Point) o;

        return x == point.x && y == point.y;

    }

    @Override

    public int hashCode() {

        return Objects.hash(x, y);

    }

}

public class Main {

    public static void main(String[] args) {

        Point[] points = {new Point(1, 1), new Point(2, 2), new Point(-1, 1), new Point(-2, 2)};

        System.out.println(hasSymmetry(points)); // true

    }

    public static boolean hasSymmetry(Point[] points) {

        int sumX = 0;

        Set pointSet = new HashSet<>();

        for (Point point : points) {

            sumX += point.x;

            pointSet.add(point);

        }

        double avgX = 1.0 * sumX / points.length;

        for (Point point : points) {

            int symX = (int) (2 * avgX - point.x);

            if (!pointSet.contains(new Point(symX, point.y))) {

                return false;

            }

        }

        return true;

    }

}

После последнего интервью я снова проверила откуда задачи. Вау, это не случайность.

Мои наблюдения вдобавок к тем выводам, что сделал @kesn

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

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

  3. Яндекс повторяется в задачах, даже если они разобраны на Хабре. С чем это может быть связано и как аффектится на найм — оставлю эти и другие вопросы на рефлексию каждому!

© Habrahabr.ru