Algorithms Flashcards

1
Q

Two Sum
# arrays # dicts
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

A

def twoSum(nums: List[int], target: int) -> List[int]:
nums_dict = {}
# создаем словарь значение:индекс
for i in range(len(nums)):
if nums[i] not in nums_dict:
nums_dict[nums[i]] = i
else:
if nums[i] * 2 == target:
return [nums_dict.get(nums[i]),i]

        # проход по индексам списка
        for i in range(len(nums)): 
            x = nums[i]
            y = target - x
            if x!=y and y in nums_dict:
                return [i,nums_dict[y]]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q
Add Two Numbers
# linked lists
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807.

A
# Definition for singly-linked list.
# class ListNode:
#     def \_\_init\_\_(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        carry = 0 # остаток от суммы (если > 10)
        res = None
        r = None
        while l1 or l2 or carry:
            d1 = l1.val if l1 else 0
            d2 = l2.val if l2 else 0
            sum = d1 + d2 + carry
            carry = sum // 10;
            resNode = ListNode(sum % 10)
            if res:
                res.next = resNode
            else: 
                r = resNode
            res = resNode
        l1 = l1.next if l1 else None
        l2 = l2.next if l2 else None
    return r
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q
Longest Substring Without Repeating Characters
# strings
Given a string, find the length of the longest substring without repeating characters.

Input: “abcabcbb”
Output: 3
Explanation: The answer is “abc”, with the length of 3.

A

def lengthOfLongestSubstring(self, s: str) -> int:
start = 0
sub_max = 0
# проходим по срезу строки, сдвигая границы: если символ имеет индекс -1 в текущей подстроке, длина текущей подстроки больше sub_max, увеличиваем sub_max. Иначе сдвигаем первую границу подстроки
for end in range(len(s)):
c = s[end]
c_index = s.find(c, start, end)
if c_index != -1:
start = c_index + 1
else:
if (end-start) + 1 > sub_max:
sub_max += 1
return sub_max

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

ZigZag Conversion
# strings
The string “PAYPALISHIRING” is written in a zigzag pattern on a given number of rows like this:

P A H N
A P L S I I G
Y I R
And then read line by line: “PAHNAPLSIIGYIR”

Write the code that will take a string and make this conversion given a number of rows:

Input: s = “PAYPALISHIRING”, numRows = 3
Output: “PAHNAPLSIIGYIR”

A

def convert(s: str, numRows: int) -> str:
if numRows == 1:
return s
res = “”
d = 0
k = 0
# пока результирующая строка не сравняется с исходной: прибавляем к ней по символу из двух индексов, прибавляем символ по третьему индексу, если второй не нулевой и меньше числа рядов на 1 и третий индекс меньше длины строки. Первый индекс увеличиваем на двойное число рядов минус 2.
while len(res) != len(s):
res += s[d + k]
if k != 0 and k != numRows - 1:
ind = d + 2 * numRows - 2 - k
if ind < len(s):
res += s[ind]
d += 2 * numRows - 2
# если сумма индексов больше длины строки, обнуляем первый индекс и увеличиваем второй
if d + k >= len(s):
d = 0
k += 1
return res

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q
Reverse Integer
# numbers # arithmetic
Given a 32-bit signed integer, reverse digits of an integer.

Input: 123
Output: 321

A
def reverse(self, x: int) -> int:
        r = 0
        p = 1
// если число отрицательное, берем его модуль и умножаем на -1
        if x < 0:
            x = abs(x)
            p = -1
// циклом делим число на 10, получаем последнюю цифру и прибавляем ее к результату, умноженному на 10
        while x != 0:
            t = x % 10
            x = x // 10
            r = r * 10 + t
        r = r * p
        #if r > 2**31 or r <= -2**31:
        #    return 0
        return r
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q
Palindrome Number
# numbers # arithmetic
Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.
A
def isPalindrome(self, x: int) -> bool:
        if(x < 0 or (x % 10 == 0 and x != 0)):
            return False
// сохраняем исходное число в отдельной переменной        
        r = 0
        k = x
// циклом делим число на 10, пока перевертыш меньше. Прибавляем последнюю цифру числа к перевертышу, умноженному на 10. В конце проверяем равенство чисел или первой цифры перевертыша
        while r < k:
            r = r * 10 + k % 10
            k = k // 10
        return r == k or k == r // 10
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q
Integer to Roman
# numbers # strings # dicts
Convert integers to Roman numbers
3 -> III
9 -> IX
A

def intToRoman(self, num: int) -> str:
// заводим словарь соответствий арабских цифр римским
d = {
1000: ‘M’, 900: ‘CM’, 500: ‘D’, 400: ‘CD’, 100: ‘C’,
90: ‘XC’, 50: ‘L’, 40: ‘XL’, 10: ‘X’, 9: ‘IX’, 5: ‘V’, 4: ‘IV’,
1: ‘I’
}
res = ‘’
// проходимся циклом по словарю: к выходной строке прибавляем значение, умноженное на результат целого деления числа на ключ, берем остаток от деления числа на ключ
for i in d:
res += (num//i) * d[i]
num %= i
return res

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q
Roman to Integer
# numbers # strings # dicts
Convert a Roman number into integer
III -> 3
LVIII -> 58
A
def romanToInt(s: str) -> int:
        res = 0
// заводим словарь соответствий римских цифр арабским
        roman = {
            'I': 1,
            'V': 5,
            'X': 10,
            'L': 50,
            'C': 100,
            'D': 500,
            'M': 1000
        }
        prev = 0 // переменная для сохранения предыдущего значения
// проходимся циклом по перевернутой строке: если пред. значение больше текущего, вычитаем текущее из результата, иначе прибавляем его
        for i in s[::-1]:
            current = roman[i]
            if prev > current:
                res -= current
            else:
                res += current
            prev = current
        return res
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q
Longest Common Prefix
# strings
Write a function to find the longest common prefix string amongst an array of strings. If there is no common prefix, return an empty string "".
Input: ["flower","flow","flight"]
Output: "fl"
A
def longestCommonPrefix(self, strs: List[str]) -> str:
        if not len(strs) or not len(strs[0]):
            return ""
// цикл по индексам первого слова массива
        for i in range(len(strs[0])):
// цикл по словам массива после первого: если индекс больше длины текущего слова или буква с текущим индексом не соответствует букве первого слова с тем же индексом, вернуть срез первого слова до этого индекса
            for s in strs[1::]:
                if len(s) <= i or s[i] != strs[0][i]:
                    return strs[0][:i]
        return strs[0]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Letter Combinations of a Phone Number
# strings # dicts
Given a string containing digits from 2-9 inclusive, return all possible letter combinations that the number could represent.
Input: “23”
Output: [“ad”, “ae”, “af”, “bd”, “be”, “bf”, “cd”, “ce”, “cf”].

A
def letterCombinations(self, digits: str) -> List[str]:
// составляем словарь соответствий цифр буквам
        phone = {
            '2': 'abc',
            '3': 'def',
            '4': 'ghi',
            '5': 'jkl',
            '6': 'mno',
            '7': 'pqrs',
            '8': 'tuv',
            '9': 'wxyz'
        }
        if digits:
// составляем список с буквами по первой цифре номера
            res = list(phone[digits[0]])
// цикл по цифрам номера после первой: копируем содержимое результирующего массива в другой массив, результирующий обнуляем
            for d in digits[1:]:
                temp = res
                res = []
// цикл по буквам отдельных цифр
                for letter in phone[d]:
// цикл по сочетаниям рабочего массива: прибавляем текущую букву к сочетанию, сохраняем в результирующий массив
                    for chars in temp:
                        chars+=letter
                        res.append(chars)
            return res
        else:
            return []
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q
Merge Two Sorted Lists
# linked lists
Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4
A
# Definition for singly-linked list.
# class ListNode:
#     def \_\_init\_\_(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
            res = None
// сначала определяем корневую ноду итогового списка: сравниваем значения и переставляем указатель на следующую ноду
            if not l1 and not l2:
                return None
            if l1 and (not l2 or l1.val < l2.val):
                res = l1
                l1 = l1.next
            else:
                res = l2
                l2 = l2.next
            head = res
// цикл по оставшимся нодам: сравниваем значения и переставляем указатели
            while True:
                if not l1:
                    res.next = l2
                    break
                if not l2:
                    res.next = l1
                    break
                if l1.val < l2.val:
                    res.next = l1
                    l1 = l1.next
                else:
                    res.next = l2
                    l2 = l2.next
                res = res.next
            return head
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Search in Rotated Sorted Array
# arrays # search
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.
(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).
You are given a target value to search. If found in the array return its index, otherwise return -1.
Input: nums = [4,5,6,7,0,1,2], target = 0
Output: 4

A

def search(self, nums: List[int], target: int) -> int:
def binarySearch(arr, x, left_bound, right_bound):
if right_bound == left_bound - 1:
return -1
// определяем серединный индекс
mid = (left_bound + right_bound+1) // 2
if arr[mid] == x:
return mid
// если значение левой границы меньше серединного значения, проверяем, входит ли искомое значение в этот промежуток, если да, то выполняем поиск в левой части от середины, иначе поиск в правой части
if arr[left_bound] < arr[mid]:
if arr[left_bound] <= x <= arr[mid]:
return binarySearch(arr, x, left_bound, mid - 1)
else:
return binarySearch(arr, x, mid + 1, right_bound)
// если искомое значение больше середины и меньше правой границы, выполняем поиск в правой части, если нет, то в левой части
else:
if arr[right_bound] >= x > arr[mid]:
return binarySearch(arr, x, mid + 1, right_bound)
else:
return binarySearch(arr, x, left_bound, mid - 1)
return binarySearch(nums,target,0,len(nums)-1)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q
Group Anagrams
# strings # anagrams # dicts
Given an array of strings, group anagrams together.
Input: ["eat", "tea", "tan", "ate", "nat", "bat"],
Output:
[
  ["ate","eat","tea"],
  ["nat","tan"],
  ["bat"]
]
A
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
        d = {}
// составляем словарь, в котором ключи - кортеж букв, а значения - составленные из них слова, имеющиеся в массиве. Проходимся циклом по словам массива. Делаем ключ из кортежа букв слова, значением делаем массив с этим словом (проверяя, есть ли уже значение ключа. В конце возвращаем список значений словаря
        for w in strs:
            key = tuple(sorted(w))
            d[key] = d.get(key, []) + [w]
        return list(d.values())
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Maximum Subarray
# arrays
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

A
def maxSubArray(self, nums: List[int]) -> int:
// делаем массив из 0 длиной исходного массива, первые элементы одинаковы
            dp = [0]*len(nums)
            dp[0] = nums[0]
// проходимся по индексам первого массива: записываем во второй массив либо число из первого массива с этим индексом, либо сумму числа из первого массива с текущим индексом и числа из второго массива с предыдущим индексом (что больше). В конце возвращаем максимум второго массива
            for i in range(1, len(nums)):
                dp[i] = max(nums[i], dp[i-1]+nums[i])
            return max(dp)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q
Minimum Path Sum
# arrays # graphs # matrices
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path. You can only move either down or right at any point in time.
Input:
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
Output: 7
Explanation: Because the path 1→3→1→1→1 minimizes the sum.
A
def minPathSum(self, grid: List[List[int]]) -> int:
// создаем нулевую матрицу той же размерности
            m = len(grid)
            n = len(grid[0])
            matrix = [[0 for i in range(n)] for i in range(m)]
// заполняем первый столбец и первый ряд матрицы кумулятивными суммами из 1го столбца и 1го ряда исходного массива     
            sums = 0
            for i in range(n):
                sums += grid[0][i]
                matrix[0][i] = sums
            sums = 0
            for j in range(m):
                sums += grid[j][0]
                matrix[j][0] = sums
 // проходимся по матрице (индексы), заполняем элементы: минимальное значение из соседних элементов сверху и слева плюс значение из исходной матрицы на этом же месте. В конце возвращаем самый правый нижний элемент              
            for i in range(1,m):
                for j in range(1,n):
                    matrix[i][j] = min(matrix[i-1][j], matrix[i][j-1]) + grid[i][j]
            return matrix[m-1][n-1]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Best Time to Buy and Sell Stock II
# arrays
Say you have an array prices for which the ith element is the price of a given stock on day i. Design an algorithm to find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times). You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).

Input: [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.

A

def maxProfit(self, prices: List[int]) -> int:
profit = 0
// проходимся циклом по индексам массива: если следующий элемент больше предыдущего, прибавляем их разность к профиту
for i in range(len(prices)-1):
if prices[i+1] - prices[i] > 0:
profit += (prices[i+1] - prices[i])
return profit

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q
Single Number
# arrays
Given a non-empty array of integers, every element appears twice except for one. Find that single one.
Input: [2,2,1]
Output: 1
A

def singleNumber(self, nums: List[int]) -> int:
i = 0
// проходимся циклом по массиву: если количество вхождений числа равно 1, возвращаем это число, иначе сдвигаем индекс
while nums:
if nums.count(nums[i]) == 1:
return nums[i]
else:
i += 1

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q
Min Stack
# stack
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.

push(x) – Push element x onto stack.
pop() – Removes the element on top of the stack.
top() – Get the top element.
getMin() – Retrieve the minimum element in the stack.

E.g.
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); // return -3
minStack.pop();
minStack.top();    // return 0
minStack.getMin(); // return -2
A
class MinStack:
// конструктор с массивом значений
    def \_\_init\_\_(self):
        self.stack = []
// при добавлении нового элемента в стек сравниваем его с текущим минимумом, потом добавляем в массив кортеж (значение, текущий минимум)       
    def push(self, x: int) -> None:
        curMin = self.getMin()
        if curMin is None or x < curMin:
            curMin = x
        self.stack.append((x, curMin))
    def pop(self) -> None:
        self.stack.pop()
// возвращаем нулевой элемент последнего кортежа
    def top(self) -> int:
        if len(self.stack) == 0:
            return None
        else:
            return self.stack[-1][0]
// возвращаем первый элемент последнего кортежа
    def getMin(self) -> int:
        if len(self.stack) == 0:
            return None
        else:
            return self.stack[-1][1]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
19
Q
Number of Islands
# arrays # graphs
Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.
Input:
11110
11010
11000
00000

Output: 1

A

def numIslands(self, grid: List[List[str]]) -> int:
islands = 0
// проходимся циклом по матрице: если элемент равен 1, увеличиваем счетчик островов и выполняем поиск в глубину соседних элементов, чтобы объединить их всех как один остров
for i in range(len(grid)):
for j in range(len(grid[i])):
if grid[i][j] == ‘1’:
islands += 1
self.dfs(grid, i, j)
return islands

// функция для поиска в глубину
def dfs(self, grid, r, c):
grid[r][c] = ‘0’ // отмечаем посещенный элемент 0
// проходимся циклом по соседям данного элемента: если индексы не выходят на пределы матрицы и элемент равен 1, выполняем поиск с него
for dr, dc in [(-1,0),(1,0),(0,-1),(0,1)]:
nr = dr + r
nc = dc + c
if 0 <= nr < len(grid) and 0 <= nc < len(grid[0]) and grid[nr][nc] == ‘1’:
self.dfs(grid, nr, nc)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
20
Q

LRU Cache
# linked lists # dicts
Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: get and put.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item. The cache is initialized with a positive capacity.

LRUCache cache = new LRUCache(2);

cache. put(1, 1);
cache. put(2, 2);
cache. get(1); // returns 1
cache. put(3, 3); // evicts key 2
cache. get(2); // returns -1 (not found)
cache. put(4, 4); // evicts key 1
cache. get(1); // returns -1 (not found)
cache. get(3); // returns 3
cache. get(4); // returns 4

A
// используется класс ноды со своими ключом, значением, и указателями на след. и пред. ноды
class ListNode(object):
def \_\_init\_\_(self, key: int, val: int):

    self. key = key
    self. val = val
    self. prev = None
    self. next = None
class LRUCache:
// в конструкторе заводятся головная нода, хвост, словарь с ключами и значениями нод, максимальный объем и текущий размер (0)
    def \_\_init\_\_(self, capacity: int):
        self.head = ListNode(-1, -1)
        self.tail = self.head
        self.key2node = {}
        self.capacity = capacity
        self.length = 0
// если ключа нет в словаре кеша, возвращаем -1
    def get(self, key: int) -> int:
        if key not in self.key2node:
            return -1
        node = self.key2node[key]
        val = node.val
// если у найденной ноды есть след.указатель, то перемещаем след.указатель предыдущей ноды на следующую ноду, пред.указатель следующей ноды на предыдущую ноду, след.указатель хвоста на ноду, пред.указатель ноды на хвост, обнуляем след.указатель ноды, делаем ноду хвостом
        if node.next:
            node.prev.next = node.next
            node.next.prev = node.prev
            self.tail.next = node
            node.prev = self.tail
            node.next = None
            self.tail = node
        return val
    def put(self, key: int, value: int) -> None:
// если ключ уже есть в словаре кеша, то заменяем его значение
        if key in self.key2node:
            node = self.key2node[key]
            node.val = value
// если у ноды есть указатель на след. ноду, то перемещаем след.указатель предыдущей ноды на следующую, пред.указатель следующей ноды на предыдущую, след.указатель хвоста на ноду, пред.указатель ноды на хвост, обнуляем след.указатель ноды, и делаем ноду хвостом
            if node.next:
                node.prev.next = node.next
                node.next.prev = node.prev
                self.tail.next = node
                node.prev = self.tail
                node.next = None
                self.tail = node   
        else:
// иначе заводим новую ноду с ключом и значением, пару ключ-значение добавляем в словарь кеша, ставим след. указатель от хвоста к ноде, пред.указатель от ноды к хвосту, делаем ноду хвостом, увеличиваем размер кеша
            node = ListNode(key, value)
            self.key2node[key] = node
            self.tail.next = node
            node.prev = self.tail
            self.tail = node
            self.length += 1
// если размер кеша превышает допустимый объем, то следующую ноду после головы отмечаем на удаление, перемещаем след. указатель от головы на ноду после удаляемой, перемещаем пред.указатель ноды после головы на голову, удаляем из словаря кеша ключ удаляемой ноды, уменьшаем размер кеша
            if self.length > self.capacity:
                remove = self.head.next
                self.head.next = self.head.next.next
                self.head.next.prev = self.head
                del self.key2node[remove.key]
                self.length -= 1
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
21
Q
Bitwise AND of Numbers Range
# bitwise
Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers in this range, inclusive.
Input: [5,7]
Output: 4
A
def rangeBitwiseAnd(self, m: int, n: int) -> int:
            i = 0
// пока границы диапазона не стали равны друг другу, выполняем побитовый сдвиг вправо (делим на 2^1) и увеличиваем счетчик. В конце выполняем побитовый сдвиг влево правой границы (умножаем на 2^i)
            while m != n:
                m >>= 1
                n >>= 1
                i += 1
            return n << i
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
22
Q
Happy Number
# numbers # arithmetic
Write an algorithm to determine if a number n is "happy". A happy number is a number defined by the following process: Starting with any positive integer, replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1. Those numbers for which this process ends in 1 are happy numbers.
Return True if n is a happy number, and False if not.
Input: 19
Output: true
Explanation: 
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
A
def isHappy(self, n: int) -> bool:
// функция для вычисления суммы цифр
        def getSum(n:int) -> int:
            sums = 0
            while n:
                sums += (n%10) ** 2
                n //= 10
            return sums
// заводим множество для хранения уже встречавшихся значений
        seen = set()
// циклом вычисляем сумму цифр, если результат вычисления уже есть во множестве встречавшихся, выходим из цикла и возвращаем ложь, иначе добавляем во множество
        while n != 1:
            n = getSum(n)
            if n in seen:
                return False
            else:
                seen.add(n)
        else:
            return True
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
23
Q
Product of Array Except Self
# arrays # arithmetic
Given an array nums of n integers where n > 1,  return an array output such that output[i] is equal to the product of all the elements of nums except nums[i].
Input:  [1,2,3,4]
Output: [24,12,8,6]
A
def productExceptSelf(self, nums: List[int]) -> List[int]:
// заводим второй массив из единиц
        arr = [1] * len(nums)
        pi = pj = 1
// проходимся циклом по индексам массива, заводим второй индекс, идущий с конца. Элементы с этими индексами умножаем на указатели pi, pj, после указатели умножаем на числа тех же индексов из первого массива
        for i in range(len(nums)):
            j = -1-i
            arr[i]*=pi
            arr[j]*=pj
            pi *= nums[i]
            pj *= nums[j]
    return arr
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
24
Q
Move Zeroes
# arrays
Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements.
Input: [0,1,0,3,12]
Output: [1,3,12,0,0]
A

def moveZeroes(self, nums: List[int]) -> None:
// подсчитываем количество нулей в массиве
zeroes = nums.count(0)
// циклом удаляем нули из массива
while 0 in nums:
nums.remove(0)
// прибавляем к массиву новый массив из нулей
nums.extend([0]*zeroes)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
25
Q

Contiguous Array
# arrays
Given a binary array, find the maximum length of a contiguous subarray with equal number of 0 and 1.

Input: [0,1]
Output: 2
Explanation: [0, 1] is the longest contiguous subarray with equal number of 0 and 1.

A

def findMaxLength(self, nums: List[int]) -> int:
// заводим переменную-счетчик, словарь для индексов и счетчика, максимальную длину подмассива
c,d,m = 0,{0:0},0
// проходимся циклом по списку кортежей (индекс, значение): прибавляем к счетчику 0 или 1 в зависимости от значения. Если значение счетчика уже есть в словаре, проверяем, что больше: максимальная длина или подстрока индекс+1 - значение из словаря по счетчику? Если нет в словаре, добавляем запись счетчик : индекс + 1
for i,v in enumerate(nums):
c += 2*v -1
if c in d:
m = max(m,i+1-d[c])
else:
d[c] = i+1
return m

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
26
Q
Jump Game
# arrays
Given an array of non-negative integers, you are initially positioned at the first index of the array. Each element in the array represents your maximum jump length at that position. Determine if you are able to reach the last index.

Input: [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.

Input: [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible to reach the last index.

A
def canJump(self, nums: List[int]) -> bool:
// переменная для самого дальнего индекса
        j = 0
// для каждого индекса, длина прыжка которого равна значению, определяем максимальную длину прыжка (если индекс+значение больше текущего максимума, переопределяем максимум). Если максимум меньше текущего индекса, то него никак нельзя прыгнуть, поэтому сразу возвращаем false
        for ind, val in enumerate(nums):
            if j < ind:
                return False
            j = max(j, ind+val)
        return True
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
27
Q
Diameter of Binary Tree
# trees # graphs
Given a binary tree, you need to compute the length of the diameter of the tree. The diameter of a binary tree is the length of the longest path between any two nodes in a tree. This path may or may not pass through the root.
A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def diameterOfBinaryTree(self, root: TreeNode) -> int:
        self.res = 0
// функция для поиска в глубину
        def dfs(node):
            if node == None:
                return 0
// выполняем поиск в глубину левого узла и правого узла, определяем максимум текущий результат vs левый узел + правый узел, возвращаем максимум из левого и правого узла + 1
            l = dfs(node.left)
            r = dfs(node.right)
            self.res = max(self.res,l+r)
            self.res = max(self.res,max(l,r))
            return max(l,r) +1
    dfs(root)
    return self.res
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
28
Q
Subarray Sum Equals K
# arrays # dicts
Given an array of integers and an integer k, you need to find the total number of continuous subarrays whose sum equals to k.

Input:nums = [1,1,1], k = 2
Output: 2

A
// если кумулятивная сумма элементов массива увеличилась на k, значит, это нужная подпоследовательность
def subarraySum(self, nums: List[int], k: int) -> int:
            count = 0
            sums = 0
            d = {0:1}
// проходимся по индексам массива: прибавляем к сумме значение по индексу, к счетчику значение из словаря по ключу (сумма - к), или 0, если такого нет, в словарь добавляем новую запись сумма-ключ: значение по ключу сумма (либо 0) + 1
            for i in range(len(nums)):
                sums += nums[i]
                count += d.get(sums-k, 0)
                d[sums] = d.get(sums, 0) + 1
            return count
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
29
Q
Valid Parenthesis String
# strings
Given a string containing only three types of characters: '(', ')' and '*', write a function to check whether this string is valid. We define the validity of a string by these rules:

Any left parenthesis ‘(‘ must have a corresponding right parenthesis ‘)’.
Any right parenthesis ‘)’ must have a corresponding left parenthesis ‘(‘.
Left parenthesis ‘(‘ must go before the corresponding right parenthesis ‘)’.
‘*’ could be treated as a single right parenthesis ‘)’ or a single left parenthesis ‘(‘ or an empty string.
An empty string is also valid.

”()” - True
“()” -True
“(
))” - True
“)(“ - False

A
def checkValidString(self, s: str) -> bool:
\\ cmin - это минимальное количество открытых скобок (должно быть 0 в конце), cmax - это максимальное количество открытых скобок (не должно быть меньше 0)
        cmin = cmax = 0
// цикл по строке: если скобка ), увеличиваем оба счетчика, если ( - уменьшаем максимум, меняем минимум либо на минимум-1, либо 0 (что больше). Если *, увеличиваем максимум и меняем минимум
        for i in s:
            if i == '(':
                cmax += 1
                cmin += 1
            if i == ')':
                cmax -= 1
                cmin = max(cmin - 1, 0)
            if i == '*':
                cmax += 1
                cmin = max(cmin - 1, 0)
            if cmax < 0:
                return False
        return cmin == 0
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
30
Q
Backspace String Compare
# strings
Given two strings S and T, return if they are equal when both are typed into empty text editors. # means a backspace character. Note that after backspacing an empty text, the text will continue empty.

Input: S = “ab#c”, T = “ad#c”
Output: true
Explanation: Both S and T become “ac”.

A

def backspaceCompare(self, S: str, T: str) -> bool:
// функция для очистки от решеток-“пробелов”: пока есть решетки в строке, заменяем срезы строк [индекс до решетки:индекс после решетки] на пустую строку, если решетка не в начале строки. Если она в начале, заменяем строку на срез с 1-го индекса
def cleanBackspaces(text: str):
if ‘#’ in text:
while ‘#’ in text:
if text.index(‘#’) != 0:
text = text.replace(text[(text.index(‘#’) - 1):text.index(‘#’) + 1], ‘’)
else:
text = text[1:]
return text
// выполняем очистку на обеих строках и сравниваем их
S = cleanBackspaces(S)
T = cleanBackspaces(T)
return S == T

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
31
Q
Middle of the Linked List
# linked lists
Given a non-empty, singly linked list with head node head, return a middle node of linked list. If there are two middle nodes, return the second middle node.

Input: [1,2,3,4,5]
Output: Node 3 from this list

Input: [1,2,3,4,5,6]
Output: Node 4 from this list.Since the list has two middle nodes with values 3 and 4, we return the second one.

A
# Definition for singly-linked list.
# class ListNode:
#     def \_\_init\_\_(self, x):
#         self.val = x
#         self.next = None
// используем 2 указателя, на след. ноду и через одну ноду. Сдвигаем их циклом, пока возможно
class Solution:
    def middleNode(self, head: ListNode) -> ListNode:
        tmp = head
        while tmp and tmp.next:
            head = head.next
            tmp = tmp.next.next
        return head
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
32
Q
Longest Common Subsequence
# strings
Given two strings text1 and text2, return the length of their longest common subsequence. A subsequence of a string is a new string generated from the original string with some characters(can be none) deleted without changing the relative order of the remaining characters. (eg, "ace" is a subsequence of "abcde" while "aec" is not). A common subsequence of two strings is a subsequence that is common to both strings. If there is no common subsequence, return 0.

Input: text1 = “abcde”, text2 = “ace”
Output: 3
Explanation: The longest common subsequence is “ace” and its length is 3.

Input: text1 = “abc”, text2 = “def”
Output: 0
Explanation: There is no such common subsequence, so the result is 0.

A

def longestCommonSubsequence(self, text1: str, text2: str) -> int:
m = len(text1)
n = len(text2)
// строим пустую матрицу размерности длина первой строки + 1 х длина второй строки + 1
matrix = [[None]*(n+1) for i in range(m+1)]
// проходимся по элементам матрицы: если один из индексов 0, записываем 0, если буквы строк по текущим индексам-1 совпадают, записываем значение соседа сверху слева + 1, иначе записываем бОльшее значение из соседей (слева или сверху). В конце возвращаем значение последнего элемента матрицы
for i in range(m+1):
for j in range(n+1):
if i == 0 or j == 0:
matrix[i][j] = 0
elif text1[i-1] == text2[j-1]:
matrix[i][j] = matrix[i-1][j-1] + 1
else:
matrix[i][j] = max(matrix[i-1][j],matrix[i][j-1])
return matrix[m][n]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
33
Q
Maximal Square
# arrays # matrices
Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area.
Example:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Output: 4
A
def maximalSquare(self, matrix: List[List[str]]) -> int:
        m = len(matrix)
        n = len(matrix[0]) if m else 0
        maxn = 0
// строим нулевую матрицу размерности m+1 x n+1
        f = [[0] * (n+1) for _ in range(m+1)]
// проходимся по элементам матрицы (начиная f[1][1]): если элемент из исходной матрицы с индексами -1 равен единице, то в матрицу записываем минимальное значение из соседей (сверху, слева, слева-сверху) + 1. В результат записываем бОльшее из значений: текущее или текущего элемента. Возвращаем квадрат результата 
        for i in range(1,m+1):
            for j in range(1,n+1):
                if matrix[i-1][j-1] == '1':
                    f[i][j] = 1 + min(f[i-1][j], f[i][j-1], f[i-1][j-1])
                    maxn = max(maxn, f[i][j])
        return maxn**2
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
34
Q
Binary Tree Maximum Path Sum
# trees # graphs
Given a non-empty binary tree, find the maximum path sum. For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path must contain at least one node and does not need to go through the root.

Input: [1,2,3]

   1
  / \
 2   3

Output: 6

A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def maxPathSum(self, root: TreeNode) -> int:
// исходное значение максимума ставим на -бесконечность
        self.max = float('-inf')
// вспомогательная функция для нахождения суммы узлов: рекурсивно вызываем функцию для левой и правой веток корня, сравниваем полученные значения с 0 и сохраняем бОльшее, в максимум записываем либо текущее, либо значение левой ноды + значение правой ноды + значение корня. Возвращаем максимум из левой ноды/правой ноды/ 0 + значение корневой ноды. В конце передаем в функцию корневую ноду и возвращаем итоговый максимум
        def get_sum(root):
            if root is None:
                return 0
            else:
                ls = max(get_sum(root.left), 0)
                rs = max(get_sum(root.right), 0)
                self.max = max(self.max, ls + rs + root.val)
                return max(ls, rs, 0) + root.val
    get_sum(root)
    return self.max
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
35
Q
Construct Binary Search Tree from Preorder Traversal
# trees # graphs # arrays
Return the root node of a binary search tree that matches the given preorder traversal. (Recall that a binary search tree is a binary tree where for every node, any descendant of node.left has a value < node.val, and any descendant of node.right has a value > node.val.  Also recall that a preorder traversal displays the value of the node first, then traverses node.left, then traverses node.right.) It's guaranteed that for the given test cases there is always possible to find a binary search tree with the given requirements.
A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
def bstFromPreorder(self, preorder: List[int]) -> TreeNode:
// делаем корневую ноду из нулевого элемента массива
root = TreeNode(preorder[0])
// в стек добавляем корневую ноду
stack = [root]
i = 1
// циклом проходимся по оставшимся элементам массива
while i < len(preorder):
temp = None
// извлекаем из стека последний элемент, пока значение из массива больше топа стека
while len(stack) > 0 and preorder[i] > stack[-1].val:
temp = stack.pop()
// делаем это значение правой нодой и добавляем в стек
if temp:
temp.right = TreeNode(preorder[i])
stack.append(temp.right)
// если значение меньше, делаем его левой нодой и добавляем в стек
else:
temp = stack[-1]
temp.left = TreeNode(preorder[i])
stack.append(temp.left)
i += 1

    return root
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
36
Q

First Bad Version
# arrays # recursion
You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.
Suppose you have n versions [1, 2, …, n] and you want to find out the first bad one, which causes all the following ones to be bad.
You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.

Example:

Given n = 5, and version = 4 is the first bad version.

call isBadVersion(3) -> false
call isBadVersion(5) -> true
call isBadVersion(4) -> true

Then 4 is the first bad version.

A
# The isBadVersion API is already defined for you.
# @param version, an integer
# @return a bool
# def isBadVersion(version):
class Solution:
    def firstBadVersion(self, n):
        """
        :type n: int
        :rtype: int
        """
// определяем нижнюю и верхнюю границу прохода
        lo = 1
        hi = n
// цикл, пока нижняя граница не больше верхней: определяем середину, если это значение подходит, сдвигаем верхнюю границу (середина -1), иначе сдвигаем нижнюю границу (середина + 1). В конце возвращаем значение нижней границы
        while lo <= hi:
            mid = (lo + hi) // 2
            if isBadVersion(mid):
                hi = mid - 1
            else:
                lo = mid + 1
        return lo
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
37
Q

Last Stone Weight
# arrays
We have a collection of stones, each stone has a positive integer weight. Each turn, we choose the two heaviest stones and smash them together. Suppose the stones have weights x and y with x <= y. The result of this smash is:
If x == y, both stones are totally destroyed;
If x != y, the stone of weight x is totally destroyed, and the stone of weight y has new weight y-x.
At the end, there is at most 1 stone left. Return the weight of this stone (or 0 if there are no stones left.)

Input: [2,7,4,1,8,1]
Output: 1
Explanation:
We combine 7 and 8 to get 1 so the array converts to [2,4,1,1,1] then,
we combine 2 and 4 to get 2 so the array converts to [2,1,1,1] then,
we combine 2 and 1 to get 1 so the array converts to [1,1,1] then,
we combine 1 and 1 to get 0 so the array converts to [1] then that’s the value of last stone.

A

class Solution:
def lastStoneWeight(self, stones: List[int]) -> int:
// цикл, пока камней в массиве больше 1: сортируем камни по весу, прибавляем разницу последних двух камней. В конце возвращаем первый камень
while len(stones) > 1:
stones.sort()
stones.append(stones.pop() - stones.pop())
return stones[0]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
38
Q

Counting Elements
# arrays
Given an integer array arr, count element x such that x + 1 is also in arr. If there’re duplicates in arr, count them seperately.
Input: arr = [1,2,3]
Output: 2
Explanation: 1 and 2 are counted cause 2 and 3 are in arr.

A
class Solution:
    def countElements(self, arr: List[int]) -> int:
            out = 0
// циклом проходимся по массиву и увеличиваем счетчик
            for i in arr:
                if i + 1 in arr:
                    out += 1
            return out

def countElements(self, arr: List[int]) -> int:
// делаем сет из массива, проходимся циклом по массиву и проверяем, есть ли бОльшее число в сете, и увеличиваем счетчик
numbers_present = set(arr)
count = 0
for num in arr:
if num+1 in numbers_present:
count += 1

    return count
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
39
Q

Perform String Shifts
# strings # arrays
You are given a string s containing lowercase English letters, and a matrix shift, where shift[i] = [direction, amount]:
direction can be 0 (for left shift) or 1 (for right shift).
amount is the amount by which string s is to be shifted.
A left shift by 1 means remove the first character of s and append it to the end.
Similarly, a right shift by 1 means remove the last character of s and add it to the beginning.
Return the final string after all operations.

Input: s = “abc”, shift = [[0,1],[1,2]]
Output: “cab”
Explanation:
[0,1] means shift to left by 1. “abc” -> “bca”
[1,2] means shift to right by 2. “bca” -> “cab”

A

def stringShift(self, s: str, shift: List[List[int]]) -> str:
// сначала определяем итоговый поворот строки: если направление равно 1, прибавляем к повороту количество символов, иначе отнимаем от него это количество
rotate = 0
for direction, n in shift:
if direction == 1:
rotate += n
else:
rotate -= n
// если модуль поворота больше самой строки, берем за поворот остаток от деления на длину строки
if abs(rotate) > len(s):
rotate %= len(s)
// если поворот больше 0, меняем местами части строки: в начало идет кусок с индекса (длина строки - поворот), затем оставшаяся часть
if rotate > 0:
return s[len(s)-rotate:] + s[:len(s)-rotate]
// если меньше 0, в начало идет кусок строки начиная с индекса -поворот, затем оставшаяся часть
else:
return s[-rotate:] + s[:-rotate]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
40
Q

Leftmost Column with at Least a One
# arrays # matrices
A binary matrix means that all elements are 0 or 1. For each individual row of the matrix, this row is sorted in non-decreasing order. Given a row-sorted binary matrix binaryMatrix, return leftmost column index(0-indexed) with at least a 1 in it. If such index doesn’t exist, return -1. You can’t access the Binary Matrix directly. You may only access the matrix using a BinaryMatrix interface: BinaryMatrix.get(row, col) returns the element of the matrix at index (row, col) (0-indexed).
BinaryMatrix.dimensions() returns a list of 2 elements [rows, cols], which means the matrix is rows * cols.
Submissions making more than 1000 calls to BinaryMatrix.get will be judged Wrong Answer. Also, any solutions that attempt to circumvent the judge will result in disqualification.
For custom testing purposes you’re given the binary matrix mat as input in the following four examples. You will not have access the binary matrix directly.

A
# """
# This is BinaryMatrix's API interface.
# You should not implement it, or speculate about its implementation
# """
#class BinaryMatrix(object):
#    def get(self, x: int, y: int) -> int:
#    def dimensions(self) -> list[]:

class Solution:
def leftMostColumnWithOne(self, binaryMatrix: ‘BinaryMatrix’) -> int:
// определяем количество строк и столбцов
rows, cols = binaryMatrix.dimensions()
// ставим указатель на -1
ptr = -1
i = 0
j = cols - 1
// проходимся циклом по матрице (пока i меньше строк, а j не меньше 0: если элемент матрицы на данных координатах равен 1, то приравниваем указатель индексу столбца (j), j сдвигаем на -1, иначе сдвигаем индекс строки на 1. В конце возвращаем указатель
while i < rows and j >= 0:
if binaryMatrix.get(i,j) == 1:
ptr = j
j -= 1
else:
i += 1
return ptr

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
41
Q
First Unique Number
# arrays
You have a queue of integers, you need to retrieve the first unique integer in the queue.
Implement the FirstUnique class:
FirstUnique(int[] nums) Initializes the object with the numbers in the queue.
int showFirstUnique() returns the value of the first unique integer of the queue, and returns -1 if there is no such integer.
void add(int value) insert value to the queue.

FirstUnique firstUnique = new FirstUnique([2,3,5]);
firstUnique.showFirstUnique(); // return 2
firstUnique.add(5); // the queue is now [2,3,5,5]
firstUnique.showFirstUnique(); // return 2
firstUnique.add(2); // the queue is now [2,3,5,5,2]
firstUnique.showFirstUnique(); // return 3
firstUnique.add(3); // the queue is now [2,3,5,5,2,3]
firstUnique.showFirstUnique(); // return -1

A
// класс для ноды списка
class DoublyLinkedListNode:
    def \_\_init\_\_(self, data):
        self.data = data
        self.prev = None
        self.next = None
// класс двусвязного списка: в конструкторе корневая нода с пустым значением
class DoublyLinkedList:
    def \_\_init\_\_(self):
        self.dummy_head = DoublyLinkedListNode(None)
        self.dummy_head.next = self.dummy_head
        self.dummy_head.prev = self.dummy_head
// метод для проверки, пустой ли список (если корневая нода указывает на саму себя)
    def is_empty(self):
        return self.dummy_head.next == self.dummy_head
// метод для первой ноды (возвращает следующую ноду после корневой)
    def first_node(self):
        return self.dummy_head.next
// метод для удаления ноды: меняем след.указатель предыдущей ноды на след.ноду, пред. указатель след.ноды на предыдущую ноду, обнуляем след. и пред. указатели данной ноды и возвращаем ее
    def pop(self, node):
        node.prev.next = node.next
        node.next.prev = node.prev
        node.next = None
        node.prev = None
        return node
// добавление ноды: пред. указатель ноды ставим на пред.указатель корня, след. указатель ставим на корень, след. указатель ноды перед корнем ставим на ноду, пред. указатель корня ставим на ноду
    def push_last(self, node):
        node.prev = self.dummy_head.prev
        node.next = self.dummy_head
        self.dummy_head.prev.next = node
        self.dummy_head.prev = node

class FirstUnique:
// в конструкторе заводим словарь, двусвязный список, добавляем с словарь значения из массива
def __init__(self, nums: List[int]):
self.num_to_node = dict()
self.unique_nodes = DoublyLinkedList()
for num in nums:
self.add(num)

// если список пустой, возвращаем -1, иначе значение первой ноды
    def showFirstUnique(self) -> int:
        if self.unique_nodes.is_empty():
            return -1
        return self.unique_nodes.first_node().data

// добавление в словарь: если значения нет в словаре, делаем ноду с этим значением, добавляем в словарь запись значение:нода, добавляем ноду в двусвязный список. Иначе сохраняем в переменную значение по ключу в словаре, если у ноды есть след.указатель, удаляем ее
def add(self, value: int) -> None:
if value not in self.num_to_node:
node = DoublyLinkedListNode(value)
self.num_to_node[value] = node
self.unique_nodes.push_last(node)
else:
node = self.num_to_node[value]
# if node is still in the list, pop the node
if node.next:
self.unique_nodes.pop(node)

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
42
Q

Check If a String Is a Valid Sequence from Root to Leaves Path in a Binary Tree
# trees # graphs # arrays
Given a binary tree where each path going from the root to any leaf form a valid sequence, check if a given string is a valid sequence in such binary tree. We get the given string from the concatenation of an array of integers arr and the concatenation of all values of the nodes along a path results in a sequence in the given binary tree.
Input: root = [0,1,0,0,1,0,null,null,1,0,0], arr = [0,1,0,1]
Output: true
Explanation:
The path 0 -> 1 -> 0 -> 1 is a valid sequence
Other valid sequences are:
0 -> 1 -> 1 -> 0
0 -> 0 -> 0

A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isValidSequence(self, root: TreeNode, arr: List[int]) -> bool:
// если дерево пустое, проверяем, пустой ли массив (если тоже пустой, то возвращаем истину)
        if not root:
            return len(arr) == 0
// вызываем вспомогательную функцию с аргументами корень дерева, массива, индекс 0
        return self.isValid(root, arr, 0)
// вспомогательная функция с использованием индекса массива
    def isValid(self, root: TreeNode, arr: List[int], index: int) -> bool:
// если значение корня не равно значению массива по данному индексу, возвращаем ложь
        if root.val != arr[index]:
            return False
// если индекс - последний в массиве, проверяем, нет ли у корня правой и левой ветвей
        if index == len(arr) - 1:
            return not root.left and not root.right
// выполняем проверку: есть ли левая ветвь и рекурсивно вызываем вспомогательную функцию на левой ветви (сдвигаем индекс на 1) или есть ли правая ветвь и рекурсивный вызов функции на правой ветви (сдвигаем индекс на 1)
        return (root.left and self.isValid(root.left, arr, index + 1)) or (root.right and self.isValid(root.right, arr, index + 1))
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
43
Q
Jewels and Stones
# strings # dicts
You're given strings J representing the types of stones that are jewels, and S representing the stones you have.  Each character in S is a type of stone you have.  You want to know how many of the stones you have are also jewels. The letters in J are guaranteed distinct, and all characters in J and S are letters. Letters are case sensitive, so "a" is considered a different type of stone from "A".

Input: J = “aA”, S = “aAAbbbb”
Output: 3

A

def numJewelsInStones(self, J: str, S: str) -> int:
stones_dict = {}
count = 0
// составляем словарь символ:количество в строке S
for s in S:
if s in stones_dict:
stones_dict[s] += 1
else:
stones_dict[s] = 1
// проходимся по строке J, если символ есть в словаре, добавляем по ключу его значение
for j in J:
if j in stones_dict:
count += stones_dict[j]

        return count
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
44
Q
Ransom Note
# strings
Given an arbitrary ransom note string and another string containing letters from all the magazines, write a function that will return true if the ransom note can be constructed from the magazines ; otherwise, it will return false. Each letter in the magazine string can only be used once in your ransom note.

canConstruct(“a”, “b”) -> false
canConstruct(“aa”, “ab”) -> false
canConstruct(“aa”, “aab”) -> true

A

def canConstruct(self, ransomNote: str, magazine: str) -> bool:
// проходимся по сету символов в записке: если частотность символа в записке больше, чем частотность символа в журнале, сразу возвращаем ложь
for i in set(ransomNote):
if ransomNote.count(i) > magazine.count(i):
return False
return True

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
45
Q
Number Complement
# numbers # bitwise
Given a positive integer, output its complement number. The complement strategy is to flip the bits of its binary representation.

Input: 5
Output: 2
Explanation: The binary representation of 5 is 101 (no leading zero bits), and its complement is 010. So you need to output 2.

Input: 1
Output: 0
Explanation: The binary representation of 1 is 1 (no leading zero bits), and its complement is 0. So you need to output 0.

A
def findComplement(self, num: int) -> int:
        i = 1
// циклом побитово сдвигаем счетчик i (умножаем на степень двойки)
        while i <= num:
            i = i << 1
// в конце вычитаем единицу (чтобы выровнять количество битов) и выполняем исключающее или с числом
        return (i - 1) ^ num
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
46
Q
First Unique Character in a String
# strings # dicts
Given a string, find the first non-repeating character in it and return it's index. If it doesn't exist, return -1.

Examples:
s = “leetcode”
return 0.

s = “loveleetcode”,
return 2.

A
def firstUniqChar(self, s: str) -> int:
// делаем словарь с частотностями букв
        freq = {}
        for letter in s:
            if letter not in freq:
                freq[letter] = 1
            else:
                freq[letter] += 1
// проходимся циклом по индексам строки
        for i in range(len(s)):
            if freq[s[i]] == 1:
                return i
        return -1
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
47
Q

Majority Element
# numbers
Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times. You may assume that the array is non-empty and the majority element always exist in the array.

Input: [3,2,3]
Output: 3

Input: [2,2,1,1,1,2,2]
Output: 2

A

// проходимся по сету чисел, сравниваем их частотность с major
def majorityElement(self, nums: List[int]) -> int:
major = len(nums) / 2
for n in set(nums):
if nums.count(n) > major:
return n

// проходимся циклом по массиву, манипулируем счетчиком: если он равен 0, текущее число - это кандидат, к счетчику прибавляем 1, если текущее число является кандидатом, если нет - отнимаем 1. В конце возвращаем число-кандидат
def majorityElement(self, nums):
        count = 0
        candidate = None
        for num in nums:
            if count == 0:
                candidate = num
            count += (1 if num == candidate else -1)
    return candidate
// делаем словарь частотности, определяем максимальное значение и возвращаем его ключ
def majorityElement(self, nums):
        num_dict = {}
        for n in nums:
            if n not in num_dict:
                num_dict[n] = 1
            else:
                num_dict[n] += 1
    major = max(num_dict.values())
    for k, v in num_dict.items():
        if v == major:
            return k
// сортируем массив и возвращаем элемент посередине
def majorityElement(self, nums):
        nums.sort()
        return nums[len(nums)//2]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
48
Q

Cousins in Binary Tree
# trees # graphs
In a binary tree, the root node is at depth 0, and children of each depth k node are at depth k+1.

Two nodes of a binary tree are cousins if they have the same depth, but have different parents.

We are given the root of a binary tree with unique values, and the values x and y of two different nodes in the tree.

Return true if and only if the nodes corresponding to the values x and y are cousins.

A

Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def isCousins(self, root: TreeNode, x: int, y: int) -> bool:
lookup = {}
// вспомогательная функция прохода по дереву: добавляем в словарь пары значение: (глубина, значение родителя), проходимся по левой и правой веткам дерева
def searchTree(root, depth=0, parentVal=None):
if root == None:
return
lookup[root.val] = (depth, parentVal)
searchTree(root.left, depth+1, root.val)
searchTree(root.right, depth+1, root.val)
searchTree(root)
// проверяем по словарю, что глубины нод совпадают, а значения родительских нод нет
return lookup[x][0] == lookup[y][0] and lookup[x][1] != lookup[y][1]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
49
Q
Check If It Is a Straight Line
# arrays # numbers
You are given an array coordinates, coordinates[i] = [x, y], where [x, y] represents the coordinate of a point. Check if these points make a straight line in the XY plane.

Input: coordinates = [[1,2],[2,3],[3,4],[4,5],[5,6],[6,7]]
Output: true

A
def checkStraightLine(self, coordinates: List[List[int]]) -> bool:
// сохраняем координаты первых двух точек в отдельных переменных
        (x0, y0), (x1, y1) = coordinates[: 2]
// проверяем, что отношение наклона у всех точек одинаковое
        return all((x1 - x0) * (y - y1) == (x - x1) * (y1 - y0) for x, y in coordinates)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
50
Q
Valid Perfect Square
# numbers
Given a positive integer num, write a function which returns True if num is a perfect square else False. Note: Do not use any built-in library function such as sqrt.

Input: 16
Output: true
Example 2:

Input: 14
Output: false

A
// метод Ньютона
def isPerfectSquare(self, num: int) -> bool:
        r = num
        while r*r > num:
            r = (r + num/r) // 2
        return r*r == num
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
51
Q

Find the Town Judge
# numbers # arrays
In a town, there are N people labelled from 1 to N. There is a rumor that one of these people is secretly the town judge.
If the town judge exists, then:
The town judge trusts nobody.
Everybody (except for the town judge) trusts the town judge.
There is exactly one person that satisfies properties 1 and 2.
You are given trust, an array of pairs trust[i] = [a, b] representing that the person labelled a trusts the person labelled b.
If the town judge exists and can be identified, return the label of the town judge. Otherwise, return -1.

Example 1:
Input: N = 2, trust = [[1,2]]
Output: 2

Example 2:
Input: N = 3, trust = [[1,3],[2,3]]
Output: 3

Example 3:
Input: N = 3, trust = [[1,3],[2,3],[3,1]]
Output: -1

Example 4:
Input: N = 3, trust = [[1,2],[2,3]]
Output: -1

Example 5:
Input: N = 4, trust = [[1,3],[1,4],[2,3],[2,4],[4,3]]
Output: 3

A
def findJudge(self, N: int, trust: List[List[int]]) -> int:
// составляем массив из нулей длиной N+1
        trusted = [0] * (N+1)
// заполняем массив: для элемента с индексом первого числа отнимаем единицу, для элемента с индексом второго числа прибавляем единицу
        for a, b in trust:
            trusted[a] -= 1
            trusted[b] += 1
// таким образом, у числа-"судьи" будет значение N-1: ищем это число циклом
        for i in range(1, N+1):
            if trusted[i] == N-1:
                return i
        return -1
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
52
Q

Flood Fill
# matrices # graphs # array
An image is represented by a 2-D array of integers, each integer representing the pixel value of the image (from 0 to 65535).
Given a coordinate (sr, sc) representing the starting pixel (row and column) of the flood fill, and a pixel value newColor, “flood fill” the image.
To perform a “flood fill”, consider the starting pixel, plus any pixels connected 4-directionally to the starting pixel of the same color as the starting pixel, plus any pixels connected 4-directionally to those pixels (also with the same color as the starting pixel), and so on. Replace the color of all of the aforementioned pixels with the newColor.
At the end, return the modified image.

Example 1:
Input:
image = [[1,1,1],[1,1,0],[1,0,1]]
sr = 1, sc = 1, newColor = 2
Output: [[2,2,2],[2,2,0],[2,0,1]]
Explanation:
From the center of the image (with position (sr, sc) = (1, 1)), all pixels connected
by a path of the same color as the starting pixel are colored with the new color.
Note the bottom corner is not colored 2, because it is not 4-directionally connected
to the starting pixel.

A

def floodFill(self, image: List[List[int]], sr: int, sc: int, newColor: int) -> List[List[int]]:
row= len(image)
col = len(image[0])
color = image[sr][sc]
if color == newColor: return image
// используем обход в глубину: если пиксель того же цвета, что стартовый пиксель, меняем цвет. Таким же образом проходимся по соседним пикселям (сверху, снизу, справа и слева)
def dfs(r, c):
if image[r][c] == color:
image[r][c] = newColor
if r >= 1: dfs(r-1, c)
if r+1 < row: dfs(r+1, c)
if c >= 1: dfs(r, c-1)
if c+1 < col: dfs(r, c+1)

    dfs(sr, sc)
    return image
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
53
Q
Single Element in a Sorted Array
# arrays
You are given a sorted array consisting of only integers where every element appears exactly twice, except for one element which appears exactly once. Find this single element that appears only once.

Input: [1,1,2,3,3,4,4,8,8]
Output: 2

A
def singleNonDuplicate(self, nums: List[int]) -> int:
// заводим переменные для левой и правой границ массива
        l, r = 0, len(nums)-1
// цикл пока левая граница меньше правой
        while l < r:
// находим индекс середины
            m = l + (r - l)//2
// если индекс четный
            if m % 2 == 0:
// если число справа от середины такое же, то сдвигаем левую границу (середина + 2), иначе сдвигаем правую границу на середину
                if nums[m] == nums[m+1]:
                    l = m + 2
                else:
                    r = m
// если число слева от середины такое же, то сдвигаем левую границу (середина + 1), иначе сдвигаем правую границу (середина - 1)
            else:
                if nums[m] == nums[m-1]:
                    l = m + 1
                else:
                    r = m - 1
// в конце возвращаем число с индексом левой границы
        return nums[l]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
54
Q
Remove K Digits
# strings
Given a non-negative integer num represented as a string, remove k digits from the number so that the new number is the smallest possible. The length of num is less than 10002 and will be ≥ k. The given num does not contain any leading zero.

Example 1:
Input: num = “1432219”, k = 3
Output: “1219”
Explanation: Remove the three digits 4, 3, and 2 to form the new number 1219 which is the smallest.

Example 2:
Input: num = “10200”, k = 1
Output: “200”
Explanation: Remove the leading 1 and the number is 200. Note that the output must not contain leading zeroes.

Example 3:
Input: num = “10”, k = 2
Output: “0”
Explanation: Remove all the digits from the number and it is left with nothing which is 0.

A
def removeKdigits(self, num: str, k: int) -> str:
        stack = []
// заполняем стек, проходимся циклом по цифрам
        for i in range(len(num)):
            while True:
// если к нулевое или стек пустой, выходим
                if  k == 0 or not stack:
                    break
// если последний элемент стека больше текущей цифры, убавляем к и выкидываем последний элемент стека, иначе просто выходим          
                if stack[-1] > num[i]:
                    k -= 1
                    stack.pop()
                else:
                    break
// добавляем в стек текущую цифру
            stack.append(num[i])
// проходимся циклом по стеку, убираем последние значения, убавляя к (если в пред.цикле к не убавилось)
        while k != 0:
            stack.pop()
            k -= 1
// проверка того, что в начале нет нулей, убираем нули в стеке
        for i in range(len(stack)):
            if stack[i] != "0":
                break
        stack = stack[i:]
// если стек пустой, возвращаем 0, иначе строку с цифрами
        if not stack:
            return "0"
        return "".join(stack)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
55
Q
Implement Trie (Prefix Tree)
# trees
Implement a trie with insert, search, and startsWith methods.
Example:
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple");   // returns true
trie.search("app");     // returns false
trie.startsWith("app"); // returns true
trie.insert("app");   
trie.search("app");     // returns true
A

class Trie:

// в конструкторе объявляем два сета для хранения слов и префиксов
    def \_\_init\_\_(self):
        self.words = set()
        self.prefixes = set()

// добавляем слово в сет слов, проходимся циклом по слову, добавляем сочетания в сет префиксов
def insert(self, word: str) -> None:
self.words.add(word)
for i in range(len(word)):
self.prefixes.add(word[:i+1])

// проверяем, есть ли слово в сете слов
    def search(self, word: str) -> bool:
        return word in self.words
// проверяем, есть ли префикс в сете префиксов
    def startsWith(self, prefix: str) -> bool:
        return prefix in self.prefixes
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
56
Q
Maximum Sum Circular Subarray
# arrays # subarrays
Given a circular array C of integers represented by A, find the maximum possible sum of a non-empty subarray of C.
Here, a circular array means the end of the array connects to the beginning of the array.  (Formally, C[i] = A[i] when 0 <= i < A.length, and C[i+A.length] = C[i] when i >= 0.)Also, a subarray may only include each element of the fixed buffer A at most once.  (Formally, for a subarray C[i], C[i+1], ..., C[j], there does not exist i <= k1, k2 <= j with k1 % A.length = k2 % A.length.)

Example 1:
Input: [1,-2,3,-2]
Output: 3
Explanation: Subarray [3] has maximum sum 3

Example 2:
Input: [5,-3,5]
Output: 10
Explanation: Subarray [5,5] has maximum sum 5 + 5 = 10

Example 3:
Input: [3,-1,2,-1]
Output: 4
Explanation: Subarray [2,-1,3] has maximum sum 2 + (-1) + 3 = 4

Example 4:
Input: [3,-2,2,-3]
Output: 3
Explanation: Subarray [3] and [3,-2,2] both have maximum sum 3

Example 5:
Input: [-2,-3,-1]
Output: -1
Explanation: Subarray [-1] has maximum sum -1

A
def maxSubarraySumCircular(self, A):
// заводим переменные для общего количества, максимальной-минимальной суммы, текущего максимума-минимума
        total, maxSum, curMax, minSum, curMin = 0, -float('inf'), 0, float('inf'), 0
// проходимся циклом по массиву: в текущий максимум записываем бОльшее из текущий максимум + число/число, в максимальную сумму бОльшее из макс.сумма/текущий максимум, в текущий минимум меньшее из текущий мин.+число/число, в мин.сумму меньшее из мин.сумма/текущий мин., в общее число прибавляем текущее число
        for a in A:
            curMax = max(curMax + a, a)
            maxSum = max(maxSum, curMax)
            curMin = min(curMin + a, a)
            minSum = min(minSum, curMin)
            total += a
// в конце возвращаем бОльшее из макс.сумма/общее число-мин.сумма (если макс.сумма больше 0), либо макс.сумму
        return max(maxSum, total - minSum) if maxSum > 0 else maxSum
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
57
Q
Odd Even Linked List
# linked list
Given a singly linked list, group all odd nodes together followed by the even nodes. Please note here we are talking about the node number and not the value in the nodes. You should try to do it in place. The program should run in O(1) space complexity and O(nodes) time complexity.

Example 1:
Input: 1->2->3->4->5->NULL
Output: 1->3->5->2->4->NULL

Example 2:
Input: 2->1->3->5->6->4->7->NULL
Output: 2->3->6->7->1->5->4->NULL

A
# Definition for singly-linked list.
# class ListNode:
#     def \_\_init\_\_(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def oddEvenList(self, head: ListNode) -> ListNode:
        if not head:
            return head
// используем нечетный указатель на голову и четный указатель на ноду после головы, заводим начало списка четных нод
        odd = head
        even = head.next
        eHead = even
// проходимся по списку, пока есть четная нода и след. после нее: меняем указатели четн. и нечет. нод на следующие, после этого меняем сами четные и нечетные ноды
        while even and even.next:
            odd.next = odd.next.next
            even.next = even.next.next
            odd = odd.next
            even = even.next
// в конце ставим указатель последней нечетной ноды на начало писка с четными нодами, возвращаем голову
        odd.next = eHead
        return head
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
58
Q

Find All Anagrams in a String
# strings # anagrams
Given a string s and a non-empty string p, find all the start indices of p’s anagrams in s.
Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.The order of output does not matter.

Example 1:
Input:
s: "cbaebabacd" p: "abc"
Output:
[0, 6]
Explanation:
The substring with start index = 0 is "cba", which is an anagram of "abc".
The substring with start index = 6 is "bac", which is an anagram of "abc".
A
// метод скользящего окна
def findAnagrams(self, s: str, p: str) -> List[int]:
// словарь для частотности букв в анаграмме
        chars = {}
    for i in p:
        if i in chars:
            chars[i] += 1
        else:
            chars[i] = 1 // переменные для левой и правой границы, список итоговых индексов, счетчик для оставшихся букв в анаграмме           
    start = 0
    end = 0
    ans = []
    counter = len(chars) // цикл, пока правый индекс меньше длины строки        
    while end < len(s): // если буква правого индекса есть в словаре, уменьшаем ее частотность, если частотность нулевая, уменьшаем счетчик
        if s[end] in chars:
            chars[s[end]] -= 1
            if chars[s[end]] == 0:
                counter -= 1 // сдвигаем правый индекс            
        end += 1  // пока счетчик равен нулю: если разность правого и левого индекса равна длине анаграммы, добавляем в ответ левый индекс           
        while counter == 0:
            if end - start == len(p):
                ans.append(start) // если буква левого индекса есть в словаре, увеличиваем ее частотность, если частотность больше 0, увеличиваем счетчик                    
            if s[start] in chars:
                chars[s[start]] += 1
                if chars[s[start]] > 0:
                    counter += 1 // сдвигаем левый индекс                        
            start += 1  // в конце возвращаем массив индексов               
    return ans
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
59
Q
Permutation in String
# strings # permutations
Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. In other words, one of the first string's permutations is the substring of the second string.

Input: s1 = “ab” s2 = “eidbaooo”
Output: True
Explanation: s2 contains one permutation of s1 (“ba”).

Input:s1= “ab” s2 = “eidboaoo”
Output: False

A

def checkInclusion(self, s1: str, s2: str) -> bool:
// заводим два массива для букв в строках (каждый индекс соответствует букве)
list1 = [0] * 26
list2 = [0] * 26
// заполняем первый массив для строки-анаграммы
for char in s1:
list1[ord(char)-ord(‘a’)] += 1
// проходимся по индексам второй строки: заполняем второй массив, если индекс больше длины анаграммы, то отнимаем единицу в букве по индексу (индекс - длина анаграммы)
for i in range(len(s2)):
list2[ord(s2[i]) - ord(‘a’)] += 1
if i >= len(s1):
list2[ord(s2[i-len(s1)]) - ord(‘a’)] -= 1
// в конце сравниваем два массива (если анаграмма есть в строке, то массивы одинаковые)
if list1 == list2:
return True
return False

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
60
Q

Online Stock Span
# stock # stack # oop
Write a class StockSpanner which collects daily price quotes for some stock, and returns the span of that stock’s price for the current day.
The span of the stock’s price today is defined as the maximum number of consecutive days (starting from today and going backwards) for which the price of the stock was less than or equal to today’s price.
For example, if the price of a stock over the next 7 days were [100, 80, 60, 70, 60, 75, 85], then the stock spans would be [1, 1, 1, 2, 1, 4, 6].

A
class StockSpanner:
// в конструкторе заводим стек
    def \_\_init\_\_(self):
        self.stack = []
def next(self, price):
    count = 1 // цикл по стеку, пока он непустой и цена больше последней в стеке: к счетчику прибавляем второе значение из последней пары стека, при этом ее удаляя
    while self.stack and price >= self.stack[-1][0]:
        count += self.stack.pop()[1] // в стек заводим пару значений: цена и текущее значение счетчика, в конце возвращаем счетчик                
    self.stack.append((price, count))
    return count
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
61
Q

Kth Smallest Element in a BST
# graphs # trees # bst
Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.
Note:
You may assume k is always valid, 1 ≤ k ≤ BST’s total elements.

Example 1:
Input: root = [3,1,4,null,2], k = 1
   3
  / \
 1   4
  \
   2
Output: 1
A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def kthSmallest(self, root: TreeNode, k: int) -> int:
// заводим стек
        stack = []
// цикл, пока дерево не пройдено или стек не пустой
        while root or stack:
// цикл, пока дерево не пройдено: добавляем в стек ноду, переходим на левую ветку
            while root:
                stack.append(root)
                root = root.left
// берем последнюю ноду из стека, уменьшаем k, если оно равно 0, возвращаем значение ноды
            root = stack.pop()
            k -= 1
            if k == 0:
                return root.val
// переходим на правую ветку
            root = root.right
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
62
Q
Count Square Submatrices with All Ones
# matrices # arrays # numbers
Given a m * n matrix of ones and zeros, return how many square submatrices have all ones.

Example 1:

Input: matrix =
[
  [0,1,1,1],
  [1,1,1,1],
  [0,1,1,1]
]
Output: 15
Explanation: 
There are 10 squares of side 1.
There are 4 squares of side 2.
There is  1 square of side 3.
Total number of squares = 10 + 4 + 1 = 15.
A
def countSquares(self, matrix: List[List[int]]) -> int:
// проходимся циклом по матрице, начиная с элемента (1,1): каждую ячейку умножаем на минимум из соседних значений (сверху, слева, наискосок слева) +1
        for i in range(1, len(matrix)):
            for j in range(1, len(matrix[0])):
                matrix[i][j] *= min(matrix[i - 1][j], matrix[i][j - 1], matrix[i - 1][j - 1]) + 1
// в конце возвращаем сумму всех элементов матрицы (функцией map считаем суммы строк, потом всю сумму)
        return sum(map(sum, matrix))
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
63
Q
Sort Characters By Frequency
# strings
Given a string, sort it in decreasing order based on the frequency of characters.
Example 1:
Input:
"tree"
Output:
"eert"
Explanation:
'e' appears twice while 'r' and 't' both appear once.
So 'e' must appear before both 'r' and 't'. Therefore "eetr" is also a valid answer.
A

def frequencySort(self, s: str) -> str:
// составляем массив из пар буква-частотность, сортируем по частотности по убыванию, формируем строку
freq = []
for letter in set(s):
freq.append((letter, s.count(letter)))
freq.sort(key=lambda i: i[1], reverse=True)
res = “”
for pair in freq:
res += pair[0] * pair[1]
return res

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
64
Q

Interval List Intersections
# arrays # numbers
Given two lists of closed intervals, each list of intervals is pairwise disjoint and in sorted order. Return the intersection of these two interval lists.
(Formally, a closed interval [a, b] (with a <= b) denotes the set of real numbers x with a <= x <= b. The intersection of two closed intervals is a set of real numbers that is either empty, or can be represented as a closed interval. For example, the intersection of [1, 3] and [2, 4] is [2, 3].)
Input: A = [[0,2],[5,10],[13,23],[24,25]], B = [[1,5],[8,12],[15,24],[25,26]]
Output: [[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]]

A

def intervalIntersection(self, A: List[List[int]], B: List[List[int]]) -> List[List[int]]:
ans = []
// заводим два указателя
i = j = 0
// циклом проходимся по массивам, пока указатели меньше длин массивов
while i < len(A) and j < len(B):
// определяем левую и правую границу пересечения: левая - максимум из первых координат, правая - минимум из вторых координат, если левая граница не больше правой, записываем координаты пересечения
lo = max(A[i][0], B[j][0])
hi = min(A[i][1], B[j][1])
if lo <= hi:
ans.append([lo, hi])
// если вторая координата в первом массиве меньше второй координаты во втором массиве, сдвигаем первый указатель, иначе второй
if A[i][1] < B[j][1]:
i += 1
else:
j += 1
// в конце возвращаем массив с пересечениями
return ans

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
65
Q

Uncrossed Lines
# arrays # numbers # dp
We write the integers of A and B (in the order they are given) on two separate horizontal lines.
Now, we may draw connecting lines: a straight line connecting two numbers A[i] and B[j] such that:
A[i] == B[j];
The line we draw does not intersect any other connecting (non-horizontal) line.
Note that a connecting lines cannot intersect even at the endpoints: each number can only belong to one connecting line.
Return the maximum number of connecting lines we can draw in this way.

Input: A = [1,4,2], B = [1,2,4]
Output: 2
Explanation: We can draw 2 uncrossed lines as in the diagram.
We cannot draw 3 uncrossed lines, because the line from A[1]=4 to B[2]=4 will intersect the line from A[2]=2 to B[1]=2.

A
def maxUncrossedLines(self, A: List[int], B: List[int]) -> int:
// строим матрицу размерности (длина А + 1) * (длина В + 1)
        dp = [[0] * (len(B) + 1) for _ in range(len(A) + 1)]
// циклом заполняем матрицу: для каждого элемента по диагонали снизу выбираем больший из соседей сверху и слева и по диагонали наверх с учетом равенства чисел из массивов по текущим индексам
        for i in range(len(A)):
            for j in range(len(B)):
                dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j], dp[i][j] + (A[i] == B[j]))
// в конце возвращаем самый последний элемент матрицы
        return dp[-1][-1]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
66
Q
Possible Bipartition
# arrays # graphs
Given a set of N people (numbered 1, 2, ..., N), we would like to split everyone into two groups of any size.
Each person may dislike some other people, and they should not go into the same group. 
Formally, if dislikes[i] = [a, b], it means it is not allowed to put the people numbered a and b into the same group.
Return true if and only if it is possible to split everyone into two groups in this way.

Example 1:
Input: N = 4, dislikes = [[1,2],[1,3],[2,4]]
Output: true
Explanation: group1 [1,4], group2 [2,3]

Example 2:
Input: N = 3, dislikes = [[1,2],[1,3],[2,3]]
Output: false

Example 3:
Input: N = 5, dislikes = [[1,2],[2,3],[3,4],[4,5],[1,5]]
Output: false

A

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

def possibleBipartition(self, N: int, dislikes: List[List[int]]) -> bool:
// делаем массив для пар отношений, массив с -1 для отметки посещенных вершин, переменную-счетчик
bag = [[] for i in range(N+1)]
visited = [-1] * (N+1)
count = 0
// заполняем bag: ставим второе число пары по индексу первого числа и наоборот
for dislike in dislikes:
bag[dislike[0]].append(dislike[1])
bag[dislike[1]].append(dislike[0])
// проходимся циклом от 1 до N+1: если элемент по текущему индексу в массиве посещенных вершин равен -1, а длина элемента по текущему индексу в массиве bag больше 0, и
for i in range(1, N+1):
if visited[i] == -1 and len(bag[i]) > 0:
if not self.visit(0, i, bag, visited):
return False

    return True

// вспомогательная функция для отметки посещенных вершин (принимает параметры текущего уровня глубины графа, текущего индекса, массивы bag и visited): если элемент по текущему индексу в массиве посещенных неотрицательный, проверяем, четная ли разность глубины графа и текущего посещенного элемента
def visit(self, curLevel, i, bag, visited):
if visited[i] >= 0:
return (curLevel - visited[i]) % 2 == 0
// в текущий посещенный элемент записываем значение текущую глубину графа
visited[i] = curLevel
// циклом проходимся по числам в bag по текущему индексу: если не посещено по функции с параметрами глубина+1, число из bag и массивы, возвращаем false
for des in bag[i]:
if not self.visit(curLevel + 1, des, bag, visited):
return False
return True

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
67
Q
Counting Bits
# numbers # arrays # bits
Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array.

Example 1:
Input: 2
Output: [0,1,1]

Example 2:
Input: 5
Output: [0,1,1,2,1,2]

A

def countBits(self, num: int) -> List[int]:
res = [0]
// заполняем результирующий массив циклом, пока длина массива не больше числа: к массиву прибавляем последовательность чисел на 1 больше из кусочка массива с начала до индекса (число + 1 - текущая длина массива)
while len(res) <= num:
res += [i + 1 for i in res[:num + 1 - len(res)]]
return res

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
68
Q

Course Schedule
# arrays # graphs
There are a total of numCourses courses you have to take, labeled from 0 to numCourses-1.
Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]
Given the total number of courses and a list of prerequisite pairs, is it possible for you to finish all courses?

Example 1:
Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.

Example 2:
Input: numCourses = 2, prerequisites = [[1,0],[0,1]]
Output: false
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0, and to take course 0 you should
also have finished course 1. So it is impossible.

A

// нужно проверить, является ли граф, построенный из пар курсов, цикличным

def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
// создаем массивы для графа и списка посещенных вершин
        graph = [[] for _ in range(numCourses)]
        visited = [0 for _ in range(numCourses)]
        # заполняем массив графа
        for pair in prerequisites:
            graph[pair[0]].append(pair[1])
        # посещаем каждую вершину: проходимся циклом по индексам до числа курсов: если вершина по текущему индексу не посещена, возвращаем ложь
        for i in range(numCourses):
            if not self.dfs(graph, visited, i):
                return False
        return True

// вспомогательная функция для обхода графа
def dfs(self, graph, visited, i):
# если i-я вершина отмечена как текущая в посещении, значит, граф цикличный, возвращаем ложь
if visited[i] == -1:
return False
# если вершина уже посещена, больше ее не отмечаем
if visited[i] == 1:
return True
# отмечаем вершину как текущую
visited[i] = -1
# посещаем рекурсивно все соседние вершины
for j in graph[i]:
if not self.dfs(graph, visited, j):
return False
# когда все соседи посещены, отмечаем вершину как посещенную, в конце возвращаем истину
visited[i] = 1
return True

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
69
Q
K Closest Points to Origin
# arrays # numbers # coordinates
We have a list of points on the plane.  Find the K closest points to the origin (0, 0).
(Here, the distance between two points on a plane is the Euclidean distance.)
You may return the answer in any order.  The answer is guaranteed to be unique (except for the order that it is in.)

Example 1:
Input: points = [[1,3],[-2,2]], K = 1
Output: [[-2,2]]
Explanation:
The distance between (1, 3) and the origin is sqrt(10).
The distance between (-2, 2) and the origin is sqrt(8).
Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin.
We only want the closest K = 1 points from the origin, so the answer is just [[-2,2]].

A
def kClosest(self, points: List[List[int]], K: int) -> List[List[int]]:
// сортируем координаты по сумме их квадратов, возвращаем срез массива до нужного числа
        points.sort(key=lambda i: i[0]**2 + i[1]**2)
        return points[:K]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
70
Q

Edit Distance
# strings
Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2.
You have the following 3 operations permitted on a word:
Insert a character
Delete a character
Replace a character

Example 1:
Input: word1 = "horse", word2 = "ros"
Output: 3
Explanation: 
horse -> rorse (replace 'h' with 'r')
rorse -> rose (remove 'r')
rose -> ros (remove 'e')
A
// задача о расстоянии Левенштейна
def minDistance(self, word1: str, word2: str) -> int:
// сохраняем длины слов (если первое слово длиннее второго, меняем местами)
        n, m = len(word1), len(word2)
        if n > m:
            word1, word2 = word2, word1
            n, m = m, n
// устанавливаем текущий ряд - диапазон до длины первого слова + 2
        current_row = range(n + 1)
// циклом проходимся от 1 до длины второго слова + 1: определяем предыдущий ряд и текущий ряд (т.е. работаем только с этими рядами, а не со всей матрицей): текущий меняем на предыдущий, а новый делаем из значения текущего индекса и нулей (длина первого слова)
        for i in range(1, m + 1):
            previous_row, current_row = current_row, [i] + [0] * n
// внутренний цикл от 1 до длины первого слова + 1: определяем стоимости операций с буквами: добавить - к значению по индексу j прибавляем 1, удалить - к значению по индексу j-1 прибавляем 1, заменить - значение по индексу i-1
            for j in range(1, n + 1):
                add, delete, change = previous_row[j] + 1, current_row[j - 1] + 1, previous_row[j - 1]
// если буква первого слова по индексу j-1 не равна букве второго слова по индексу i-1, к операции замены прибавляем 1
                if word1[j - 1] != word2[i - 1]:
                    change += 1
// в значение текущего ряда по индексу j записываем минимум из операций
                current_row[j] = min(add, delete, change)
// возвращаем значение из текущего ряда по индексу длина первого слова (т.е. последнее)
        return current_row[n]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
71
Q

Invert Binary Tree
# trees # graphs
Invert a binary tree.

Example:
Input:

     4
   /   \
  2     7
 / \   / \
1   3 6   9

Output:

     4
   /   \
  7     2
 / \   / \
9   6 3   1
A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
// используем рекурсию: если дерево пустое (корень пустой), возвращаем None, для левой ветки дерева выполняем инверсию с правой веткой, а для правой ветки инверсию с левой. В конце возвращаем корень
class Solution:
    def invertTree(self, root: TreeNode) -> TreeNode:
        if root is None:
            return None
        root.left, root.right = self.invertTree(root.right), self.invertTree(root.left)
        return root
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
72
Q
Delete Node in a Linked List
# linked lists
Write a function to delete a node (except the tail) in a singly linked list, given only access to that node.

Input: head = [4,5,1,9], node = 5
Output: [4,1,9]
Explanation: You are given the second node with value 5, the linked list should become 4 -> 1 -> 9 after calling your function.

The linked list will have at least two elements.
All of the nodes’ values will be unique.
The given node will not be the tail and it will always be a valid node of the linked list.
Do not return anything from your function.

A
# Definition for singly-linked list.
# class ListNode:
#     def \_\_init\_\_(self, x):
#         self.val = x
#         self.next = None
// просто записываем в значение ноды значение следующей ноды, и передвигаем указатель через след.ноду
class Solution:
    def deleteNode(self, node):
        if node.next:
            node.val, node.next = node.next.val, node.next.next
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
73
Q

Two City Scheduling
# numbers # arrays
There are 2N people a company is planning to interview. The cost of flying the i-th person to city A is costs[i][0], and the cost of flying the i-th person to city B is costs[i][1].
Return the minimum cost to fly every person to a city such that exactly N people arrive in each city.

Input: [[10,20],[30,200],[400,50],[30,20]]
Output: 110
Explanation:
The first person goes to city A for a cost of 10.
The second person goes to city A for a cost of 30.
The third person goes to city B for a cost of 50.
The fourth person goes to city B for a cost of 20.

The total minimum cost is 10 + 30 + 50 + 20 = 110 to have half the people interviewing in each city.

A
def twoCitySchedCost(self, costs: List[List[int]]) -> int:
// сортируем массив по разнице стоимости поездки в города (тогда в левой части массива окажутся люди, кому дешевле ехать в А, а в правой - кому дешевле ехать в В)
        costs.sort(key=lambda cost: cost[0] - cost[1])
// высчитываем суммарную стоимость поездок в город А (первое число из пары, первая половина списка)
        costs_for_A = sum([cost[0] for cost in costs[:len(costs) // 2]])
// высчитываем суммарную стоимость поездок в город В (второе число из пары, вторая половина списка)
        costs_for_B = sum([cost[1] for cost in costs[len(costs) // 2:]])
// в конце возвращаем полную сумму
        return costs_for_A + costs_for_B
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
74
Q
Reverse String
# strings
Write a function that reverses a string. The input string is given as an array of characters char[].
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
You may assume all the characters consist of printable ascii characters.

Example 1:
Input: [“h”,”e”,”l”,”l”,”o”]
Output: [“o”,”l”,”l”,”e”,”h”]

A
def reverseString(self, s: List[str]) -> None:
// используем два указателя, i = длина строки -1, j = 0
        i=len(s)-1
        j=0
// проходимся циклом, пока i не меньше j: меняем местами символы по индексам указателей, i уменьшаем на единицу, а j увеличиваем на единицу
        while i>=j:
            s[j],s[i]=s[i],s[j]
            i=i-1
            j=j+1
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
75
Q
Random Pick with Weight
# arrays # numbers # random
Given an array w of positive integers, where w[i] describes the weight of index i, write a function pickIndex which randomly picks an index in proportion to its weight.
A
class Solution:
// в конструкторе сохраняем массив с весами, сохраняем длину массива, проходимся циклом по индексам, к каждому весу прибавляем вес предыдущего, сохраняем отдельно последний вес массива
    def \_\_init\_\_(self, w: List[int]):
        self.w = w
        self.n = len(w)
        for i in range(1,self.n):
            w[i] += w[i-1]
        self.s = self.w[-1]
    def pickIndex(self) -> int:
// выбираем случайное число от 1 до последнего веса, определяем левую и правую границу (0 и длина-1)
        seed = random.randint(1,self.s)
        l,r = 0, self.n-1
// используем алгоритм бинарного поиска: пока левая граница меньше правой, определяем середину, если случайное число не больше веса по индексу середины, правую границу переносим на середину, иначе левую границу переносим на середину + 1. В конце возвращаем левую границу
        while l
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
76
Q
Queue Reconstruction by Height
# arrays # numbers
Suppose you have a random list of people standing in a queue. Each person is described by a pair of integers (h, k), where h is the height of the person and k is the number of people in front of this person who have a height greater than or equal to h. Write an algorithm to reconstruct the queue.

Input:
[[7,0], [4,4], [7,1], [5,0], [6,1], [5,2]]

Output:
[[5,0], [7,0], [5,2], [6,1], [4,4], [7,1]]

A

def reconstructQueue(self, people: List[List[int]]) -> List[List[int]]:
// сортируем массив по убыванию роста (первое число пары)
people = sorted(people, key = lambda x: (-x[0], x[1]))
res = []
// в итоговый массив вставляем пары, где индекс равен второму числу (кол-во высоких человек перед текущим)
for p in people:
res.insert(p[1], p)
return res

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
77
Q
Coin Change 2
# arrays # numbers # dp # knapsack
You are given coins of different denominations and a total amount of money. Write a function to compute the number of combinations that make up that amount. You may assume that you have infinite number of each kind of coin.
Example 1:
Input: amount = 5, coins = [1, 2, 5]
Output: 4
Explanation: there are four ways to make up the amount:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
A

def change(self, amount: int, coins: List[int]) -> int:
// делаем массив из нулей длиной количество + 1, первым элементом ставим единицу
dp = [0] * (amount + 1)
dp[0] = 1
// проходимся циклом по номиналам, внутренний цикл по индексам от 1 до количество + 1: если индекс больше-равно номинала, то к элементу массива по текущему индексу прибавляем элемент по индексу (индекс - номинал). В конце возвращаем последний элемент массива
for i in coins:
for j in range(1, amount + 1):
if j >= i:
dp[j] += dp[j - i]
return dp[amount]

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
78
Q
Power of Two
# numbers # math # binary
Given an integer, write a function to determine if it is a power of two.

Example 1:
Input: 1
Output: true
Explanation: 2^0 = 1

Example 2:
Input: 16
Output: true
Explanation: 2^4 = 16

Example 3:
Input: 218
Output: false

A
// у числа-степени двойки только первый бит равен единицы, у числа меньше на 1 все биты единицы, кроме первого. Сравниваем числа побитовым И
def isPowerOfTwo(self, n: int) -> bool:
        return n > 0 and (n &amp; (n-1) == 0)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
79
Q

Метод скользящего окна

A

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

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

максимальная сумма подмассива размера «K» (лёгкий);
самая длинная подстрока с различными «K» символами (средний);
анаграммы строки (сложный).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
80
Q

Метод с двумя указателями

A

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

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

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

возведение в квадрат отсортированного массива (лёгкий);
триплеты, суммирующие до нуля (средний);
сравнение строк, содержащих пробелы (средний).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
81
Q

Метод с быстрыми и медленными указателями

A

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

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

Как определить, когда использовать шаблон быстрого и медленного указателя:

задача касается цикла в связанном списке или массиве;
нужно узнать положение определённого элемента или общую длину связанного списка.
Когда использовать его вместо двух указателей?

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

цикл связанного списка (лёгкий);
является ли связанный список палиндромом (средний);
цикл в круговом массиве (сложный).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
82
Q

Метод слияния интервалов

A

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

нужно составить список только с взаимоисключающими интервалами;
вы слышите термин «пересекающиеся интервалы».
Задачи, для которых подойдёт шаблон слияния интервалов:

пересечение интервалов (средний);
максимальная нагрузка на процессор (сложный).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
83
Q

Метод циклической сортировки

A

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

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

найти недостающий номер (лёгкий);
найти наименьшее недостающее положительное число (средний).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
84
Q

Метод разворота связанного списка

A

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

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

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

перевернуть подсписок (средний);
перевернуть каждый K-элемент подсписка (средний).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
85
Q

Метод дерева BFS

A

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

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

Как определить, когда использовать шаблон дерево BFS:

вас просят обойти дерево поэтапно (или поуровнево).
Задачи, для которых подойдёт шаблон дерево BFS:

поуровневый обход двоичного дерева (лёгкий);
зигзагообразный обход (средний).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
86
Q

Метод дерева DFS

A

Дерево DFS основано на методе поиска в глубину (DFS) для обхода дерева.

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

Дерево DFS работает начиная с корня дерева. Если узел не является листом, нужно сделать две вещи:

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

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

сумма номеров путей (средний);
все пути для суммы (средний).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
87
Q

Метод двух куч

A

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

Этот шаблон использует две кучи: Min Heap, чтобы найти самый маленький элемент, и Max Heap, чтобы найти самый большой. Шаблон работает, сохраняя первую половину чисел в Max Heap, потому что вы ищите наибольшее число в первой половине. Затем вы сохраняете вторую половину чисел в Min Heap, так как хотите найти наименьшее число во второй половине. В любой момент медиана текущего списка чисел может быть вычислена из верхнего элемента двух куч.

Как определить, когда использовать шаблон две кучи:

приоритетные очереди, планирование;
нужно найти самые маленькие / самые большие / медианные элементы набора;
иногда полезен в задачах с бинарной структурой данных.
Задачи, для которых подойдёт шаблон две кучи:

найти медиану потока чисел (средний).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
88
Q

Метод подмножеств

A

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

Шаблон выглядит так:

Дан набор из [1, 5, 3].

Начните с пустого набора: [[]].
Добавьте первое число (1) ко всем существующим подмножествам, чтобы создать новые подмножества: [[], [1]].
Добавьте второе число (5) ко всем существующим подмножествам: [[], [1], [5], [1,5]].
Добавьте третье число (3) ко всем существующим подмножествам: [[], [1], [5], [1,5], [3], [1,3], [5,3], [1, 5,3]].

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
89
Q

Метод с модифицированным бинарным поиском

A

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

Для набора по возрастанию шаблоны выглядят так:

Сначала найдите середину начала и конца. Простой способ найти середину был бы: middle = (start + end) / 2. Но от этого может быть целочисленное переполнение, поэтому рекомендуется представлять середину как: middle = start + (end – start) / 2.
Если ключ равен числу в середине индекса, верните середину.
Если «ключ» не равен середине индекса:
Если ключ < arr [middle], уменьшите поиск до end = middle — 1.
Если ключ > arr [middle], уменьшите поиск до to end = middle + 1.

Задачи, для которых подойдёт шаблон модифицированный бинарный поиск:

Бинарный поиск, не зависящий от порядка (лёгкий);
Поиск в отсортированном бесконечном массиве (средний).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
90
Q

Метод Топ К-элементов

A

Любая задача, в которой требуется найти самые большие / самые маленькие / частые K-элементы среди данного набора, подпадает под этот шаблон.

Лучшая структура данных для отслеживания K-элементов — куча. Этот шаблон будет использовать кучу для решения задач, связанных с K-элементами одновременно из набора заданных элементов. Шаблон выглядит так:

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

Как определить, когда использовать шаблон Топ К-элементов:

если нужно найти самые большие / самые маленькие / частые K-элементы в данном наборе;
если нужно отсортировать массив, чтобы найти верный элемент.
Задачи, для которых подойдёт шаблон Топ К-элементов:

топ K-номеров (лёгкий);
топ K-частых номеров (средний).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
91
Q

K-Way слияние

A

K-way слияние поможет решить задачи, связанные с набором отсортированных массивов.

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

Вставьте первый элемент каждого массива в Min Heap.
Извлеките самый маленький (большой) элемент из кучи и добавьте в объединённый список.
После удаления наименьшего элемента из кучи вставьте следующий элемент из того же списка в кучу.
Повторите шаги 2 и 3, чтобы заполнить объединённый список в отсортированном порядке.
Как определить, когда использовать шаблон K-Way слияние:

задача состоит из отсортированных массивов, списков или матрицы;
требуется объединить отсортированные списки или найти самый маленький элемент в отсортированном списке.
Задачи, для которых подойдёт шаблон K-Way слияние:

слияние K-сортированных списков (средний);
K-пары с самыми большими суммами (сложный).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
92
Q

Топологическая сортировка

A

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

Этот шаблон — простой способ понять методику выполнения топологической сортировки набора элементов.
Шаблон работает так:

Инициализация.
Храните график в списках смежности, используя HashMap.
Для нахождения всех источников используйте HashMap, чтобы сохранить количество степеней.
Постройте график и найдите степени всех вершин.
Постройте график из входных данных и заполните хэш-карту степенями.
Найдите все источники.
Все вершины с «0» степенями будут источниками и будут храниться в очереди.
Сортировка.
Для каждого источника сделайте следующее:
добавьте его в отсортированный список,
получите все дочерние элементы из графа,
уменьшите степень каждого дочернего элемента на 1,
если степень дочернего элемента становится «0», добавьте её в очередь источников.
Повторяйте, пока исходная очередь не станет пустой.
Как определить, когда следует использовать шаблон Топологической сортировки?

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

планирование задач (средний);
минимальная высота дерева (сложный).

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
93
Q

Is Subsequence
# strings
Given a string s and a string t, check if s is subsequence of t.

A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, “ace” is a subsequence of “abcde” while “aec” is not).

Example 1:
Input: s = “abc”, t = “ahbgdc”
Output: true

Example 2:
Input: s = “axc”, t = “ahbgdc”

A
def isSubsequence(self, s: str, t: str) -> bool:
// если первая строка (которая должна быть подпоследовательностью) пустая, сразу возвращаем истину
        if len(s) == 0:
// если вторая строка пустая, возвращаем ложь 
            return True
        if len(t) == 0:
            return False
// заводим два указателя
        i, j = 0, 0
// проходим циклом, пока указатели меньше длин строк
        while i < len(s) and j < len(t):
// если символы строк по текущим индексам совпадают, сдвигаем первый указатель
            if s[i] == t[j]:
                i += 1
// все время сдвигаем второй указатель
            j += 1
// в конце проверяем, равен ли первый указатель длине первой строке (все символы первой строки входят во вторую)
        return i == len(s)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
94
Q
Search Insert Position
# arrays # numbers
Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.

You may assume no duplicates in the array.

Example 1:
Input: [1,3,5,6], 5
Output: 2

Example 2:
Input: [1,3,5,6], 2
Output: 1

Example 3:
Input: [1,3,5,6], 7
Output: 4

A
// используем бинарный поиск
def searchInsert(self, nums: List[int], target: int) -> int:
// определяем левую и правую границы
        l , r = 0, len(nums)-1
// циклом проходимся, пока левая граница не больше правой
        while l <= r:
// определяем середину, если элемент по индексу середины равен искомому числу, возвращаем индекс (т.е. середину), если элемент по индексу середины меньше искомого числа, сдвигаем левую границу (середина + 1), иначе сдвигаем правую границу (середина - 1)
            mid=(l+r)//2
            if nums[mid] == target:
                return mid
            if nums[mid] < target:
                l = mid+1
            else:
                r = mid-1
// в конце возвращаем индекс левой границы
        return l
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
95
Q

Sort Colors
# arrays # numbers
Given an array with n objects colored red, white or blue, sort them in-place so that objects of the same color are adjacent, with the colors in the order red, white and blue.
Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.
Note: You are not suppose to use the library’s sort function for this problem.

Example:
Input: [2,0,2,1,1,0]
Output: [0,0,1,1,2,2]

A

// так называемая задача о голландском флаге
def sortColors(self, nums: List[int]) -> None:
// заводим три указателя по цветам, красный и белые нулевые, синий равен длине массива -1
red, white, blue = 0, 0, len(nums) - 1
// проходимся циклом, пока белый указатель не больше синего
while white <= blue:
// если число по индексу белого указателя равно 0, меняем местами числа по белому и красному указателям, увеличиваем красный и белый указатели на 1
if nums[white] == 0:
nums[red], nums[white] = nums[white], nums[red]
red += 1
white += 1
// если число по белому указателю равно 2, меняем местами числа по белому и синему указателям, синий указатель уменьшаем на 1
elif nums[white] == 2:
nums[white], nums[blue] = nums[blue], nums[white]
blue -= 1
// в противном случае увеличиваем белый указатель
else:
white += 1

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
96
Q
Insert Delete GetRandom O(1)
# numbers # structures # oop
Design a data structure that supports all following operations in average O(1) time.

insert(val): Inserts an item val to the set if not already present.
remove(val): Removes an item val from the set if present.
getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned.

A
class RandomizedSet(object):
// объявляем массив и словарь для хранения значений и их индексов
    def \_\_init\_\_(self):
        self.nums, self.pos = [], {}

// если значения нет в словаре, добавляем значение в массив, в словарь добавляем запись значение: длина массива -1
def insert(self, val):
if val not in self.pos:
self.nums.append(val)
self.pos[val] = len(self.nums) - 1
return True
return False

// если значение есть в словаре, заводим переменные для индекса (значение в словаре по ключу значения) и последнего элемента в массиве, потом меняем их, удаляем последний элемент массива, удаляем элемент по индексу значения
    def remove(self, val):
        if val in self.pos:
            idx, last = self.pos[val], self.nums[-1]
            self.nums[idx], self.pos[last] = last, idx
            self.nums.pop(); self.pos.pop(val, 0)
            return True
        return False
// возвращаем элемент массива по случайному индексу от 0 до длины массива -1
    def getRandom(self):
        return self.nums[random.randint(0, len(self.nums) - 1)]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
97
Q
алгоритм Евклида (поиск НОД)
# numbers #math
A
def gcd(a, b):
    if a == 0:
        return b
    elif b == 0:
        return a
    elif a >= b:
        return gcd(a%b, b)
    else:
        return gcd(a, b%a)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
98
Q
Largest Divisible Subset
#numbers #arrays #math
Given a set of distinct positive integers, find the largest subset such that every pair (Si, Sj) of elements in this subset satisfies:
Si % Sj = 0 or Sj % Si = 0.
If there are multiple solutions, return any subset is fine.

Example 1:
Input: [1,2,3]
Output: [1,2] (of course, [1,3] will also be ok)

A
def largestDivisibleSubset(self, nums: List[int]) -> List[int]:
        if len(nums) == 0:
            return []
// составляем дополнительный массив массивов из чисел
        output_list = [[i] for i in nums]
// сортируем массив
        nums.sort()
// проходимся по индексам до длины массива
        for i in range(len(nums)):
// второй индекс от 0 до первого индекса + 1
            for j in range(0,i+1):
// если число по первому индексу нацело делится на число по второму индексу и они не равны
                if nums[i]%nums[j] == 0 and nums[i]!=nums[j]:
// длина списка доп.массива по второму индексу плюс число из массива по первому индексу не меньше длины списка по первому индексу
                    if len(output_list[j] + [nums[i]]) >= len(output_list[i]):
// в список по первому индексу добавляем список по второму индексу и число из массива по первому индексу
                        output_list[i] = output_list[j] + [nums[i]]
// сортируем дополнительный массив по убыванию
        output_list.sort(key=lambda x: -len(x))
// в конце возвращаем первый список массива
        return output_list[0]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
99
Q

Cheapest Flights Within K Stops
# graphs
There are n cities connected by m flights. Each flight starts from city u and arrives at v with a price w.
Now given all the cities and flights, together with starting city src and the destination dst, your task is to find the cheapest price from src to dst with up to k stops. If there is no such route, output -1.

Example 1:
Input: 
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 1
Output: 200
A
def findCheapestPrice(self, n: int, flights: List[List[int]], src: int, dst: int, K: int) -> int:
// составляем массив из бесконечно больших значений длиной количество городов
        dist = [math.inf]*n
//делаем элемент массива с индексом отправного города 0
        dist[src] = 0
//проходимся циклом до значения количества пересадок +1
        for _ in range(K+1):
// делаем копию массива
            olddist = dist[:]
// проходимся циклом в массиве перелетов
            for f in flights:
//присваиваем элементу массива по индексу второго значения из тройки (отправление-назначение-цена) меньшее из элемента массива по индексу второго значения из тройки / элемента из копии массива по индексу (первое значение из тройки плюс третье значение из тройки)
                dist[f[1]] = min(dist[f[1]], olddist[f[0]] + f[2])
// в конце возвращаем элемент по индексу города назначения, если он меньше бесконечности, иначе -1
        return dist[dst] if dist[dst] < math.inf else -1
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
100
Q
Search in a Binary Search Tree
# trees #graphs #search
Given the root node of a binary search tree (BST) and a value. You need to find the node in the BST that the node's value equals the given value. Return the subtree rooted with that node. If such node doesn't exist, you should return NULL.
A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
// обычный рекурсивный поиск: если значение больше корня, выполняем поиск по правой ветке, если меньше, то поиск по левой, пока не найдем нужную ноду (или None, если такой ноды нет)
    def searchBST(self, root: TreeNode, val: int) -> TreeNode:
        if not root:
            return None
        if root.val == val:
            return root
        elif val > root.val:
            return self.searchBST(root.right, val)
        else:
            return self.searchBST(root.left, val)
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
101
Q

Validate IP Address
# strings
Write a function to check whether an input string is a valid IPv4 address or IPv6 address or neither.
IPv4 addresses are canonically represented in dot-decimal notation, which consists of four decimal numbers, each ranging from 0 to 255, separated by dots (“.”), e.g.,172.16.254.1;
Besides, leading zeros in the IPv4 is invalid. For example, the address 172.16.254.01 is invalid.
IPv6 addresses are represented as eight groups of four hexadecimal digits, each group representing 16 bits. The groups are separated by colons (“:”). For example, the address 2001:0db8:85a3:0000:0000:8a2e:0370:7334 is a valid one. Also, we could omit some leading zeros among four hexadecimal digits and some low-case characters in the address to upper-case ones, so 2001:db8:85a3:0:0:8A2E:0370:7334 is also a valid IPv6 address(Omit leading zeros and using upper cases).
However, we don’t replace a consecutive group of zero value with a single empty group using two consecutive colons (::) to pursue simplicity. For example, 2001:0db8:85a3::8A2E:0370:7334 is an invalid IPv6 address.
Besides, extra leading zeros in the IPv6 is also invalid. For example, the address 02001:0db8:85a3:0000:0000:8a2e:0370:7334 is invalid.
Note: You may assume there is no extra space or special characters in the input string.

Example 1:
Input: “172.16.254.1”
Output: “IPv4”
Explanation: This is a valid IPv4 address, return “IPv4”.

Example 2:
Input: “2001:0db8:85a3:0:0:8A2E:0370:7334”
Output: “IPv6”
Explanation: This is a valid IPv6 address, return “IPv6”.

Example 3:
Input: “256.256.256.256”
Output: “Neither”
Explanation: This is neither a IPv4 address nor a IPv6 address.

A
def validIPAddress(self, IP: str) -> str:
// если в строке есть точка, проверяем на соответствие IPv4: разделяем адрес по точке, должно быть 4 блока, не должно быть пустых блоков или начинающихся с 0, не должно быть букв или чисел больше 255
        if "." in IP:
            splitted = IP.split(".")
            if len(splitted) != 4: return "Neither"
            for part in splitted:
                if len(part) == 0 or (len(part)>1 and part[0] == "0"): return "Neither"
                if not part.isnumeric() or int(part) > 255: return "Neither"                
            return "IPv4"        
// если в строке есть двоеточие, проверяем на соответствие IPv6: разделяем адрес по двоеточию, блоков должно быть 8, они не должны быть пустыми или быть длиннее 4, в блоках должны быть только цифры от 0 до 9 и буквы от a до f
        elif ":" in IP:
            symbols = "0123456789abcdefABCDEF"
            splitted = IP.split(":")
            if len(splitted) != 8: return "Neither"
            for part in splitted:
                if len(part) == 0 or len(part) > 4: return "Neither"
                for elem in part:
                    if elem not in symbols: return "Neither"                 
            return "IPv6"
// если ничего не подошло, возвращаем "Neither"    
        return "Neither"
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
102
Q

Принципы жадных алгоритмов

A

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

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
103
Q

Покрыть отрезки точками
# greedy #numbers
По данным nn отрезкам необходимо найти множество точек минимального размера, для которого каждый из отрезков содержит хотя бы одну из точек.

A
// сортируем массив отрезков по правой границе, делаем массив точек, в него добавляем первую правую точку. Циклом проходимся по отрезкам: если левая граница отрезка больше последней точки из массива, добавляем правую границу в массив точек
def minPoints(arr):
    arr.sort(key=lambda x: x[1])
    points = [arr[0][1]]
    for i in arr:
        if i[0] > points[-1]:
            points.append(i[1])
    return points
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
104
Q

Непрерывный рюкзак
# greedy #knapsack
Выведите максимальную стоимость частей предметов (от каждого предмета можно отделить любую часть, стоимость и объём при этом пропорционально уменьшатся), помещающихся в данный рюкзак

A
def list_continuous_knapsack(capacity, item_list):
// сортируем список предметов по стоимости за единицу веса по убыванию
    item_list.sort(key=lambda x: x[0] / x[1], reverse=True)
    full_cost = 0
// проходимся циклом по списку: если общий вес предмета легче вместимости рюкзака, к общей стоимости прибавляем общую стоимость предмета и убавляем вместимость, иначе к общей стоимости прибавляем отношение цены к весу умноженное на вместимость
    for cost, weight in item_list:
        if weight < capacity:
            full_cost += cost
            capacity -= weight
        else:
            full_cost += cost / weight * capacity
            break
return float("{:.3f}".format(full_cost))
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
105
Q

Различные слагаемые
# greedy #numbers
По данному числу n найдите максимальное число k, для которого nn можно представить как сумму k различных натуральных слагаемых

A
def different_addends_iterative(n):
    k = 1
    addends = []
// проходимся циклом, пока число не меньше 2k+1: добавляем k в массив, из n вычитаем k, k увеличиваем на 1
    while n >= 2 * k + 1:
        addends.append(k)
        n -= k
        k += 1
// в конце добавляем в массив n
    addends.append(n)
    return k, addends
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
106
Q

Surrounded Regions
# matrices
Given a 2D board containing ‘X’ and ‘O’ (the letter O), capture all regions surrounded by ‘X’.
A region is captured by flipping all ‘O’s into ‘X’s in that surrounded region.

Example:
X X X X
X O O X
X X O X
X O X X
After running your function, the board should be:
X X X X
X X X X
X X X X
X O X X
A

def solve(self, board: List[List[str]]) -> None:

        if not board or not board[0]:
            return
// заводим переменные для рядов и колонок
        R, C = len(board), len(board[0])
        if R <= 2 or C <= 2:
            return

// обходим границы матрицы, заменяем все О на N
for r in range(R):
self.dfs(board, r, 0, R, C)
self.dfs(board, r, C-1, R, C)

    for c in range(C):

        self. dfs(board, 0, c, R, C)
        self. dfs(board, R-1, c, R, C)
// обходим матрицу, заменяем O на X, N на O
        for r in range(R):
            for c in range(C):
                if board[r][c] == "O":
                    board[r][c] = "X"
                if board[r][c] == "N":
                    board[r][c] = "O"
// функция обхода в глубину                    
    def dfs(self, board, r, c, R, C):
// если ряд большен-равен 0 и меньше числа рядов и колонка больше-равна 0 и меньше числа колонок и ячейка по данным индексам содержит О, заменяем на N и обходим соседей
        if 0<=r
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
107
Q
H-Index II
# arrays # numbers
Given an array of citations sorted in ascending order (each citation is a non-negative integer) of a researcher, write a function to compute the researcher's h-index.
According to the definition of h-index on Wikipedia: "A scientist has index h if h of his/her N papers have at least h citations each, and the other N − h papers have no more than h citations each."

Example:
Input: citations = [0,1,3,5,6]
Output: 3
Explanation: [0,1,3,5,6] means the researcher has 5 papers in total and each of them had received 0, 1, 3, 5, 6 citations respectively. Since the researcher has 3 papers with at least 3 citations each and the remaining two with no more than 3 citations each, her h-index is 3.

A
// используем обычный бинарный поиск
def hIndex(self, citations):
    n = len(citations)
    l, r = 0, n-1
// цикл, пока левая граница не больше правой: устанавливаем середину, если число по индексу середины больше-равно разности общего числа и середины, сдвигаем правую границу (середина -1), иначе сдвигаем левую (середина + 1)
    while l <= r:
        mid = (l+r)//2
        if citations[mid] >= n-mid:
            r = mid - 1
        else:
            l = mid + 1
// в конце возвращаем разность общего числа и левой границы
    return n-l
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
108
Q

Longest Duplicate Substring
# strings
Given a string S, consider all duplicated substrings: (contiguous) substrings of S that occur 2 or more times. (The occurrences may overlap.)
Return any duplicated substring that has the longest possible length. (If S does not have a duplicated substring, the answer is “”.)

Example 1:
Input: “banana”
Output: “ana”

A
// используем функцию хеширования и бинарный поиск
def longestDupSubstring(self, S: str) -> str:
        A = [ord(c) - ord('a') for c in S]
        mod = 2**63 - 1
        def test(L):
            p = pow(26, L, mod)
            cur = reduce(lambda x, y: (x * 26 + y) % mod, A[:L], 0)
            seen = {cur}
            for i in range(L, len(S)):
                cur = (cur * 26 + A[i] - A[i - L] * p) % mod
                if cur in seen: return i - L + 1
                seen.add(cur)
        res, lo, hi = 0, 0, len(S)
        while lo < hi:
            mi = (lo + hi + 1) // 2
            pos = test(mi)
            if pos:
                lo = mi
                res = pos
            else:
                hi = mi - 1
        return S[res:res + lo]
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
109
Q

Кодирование Хаффмана
# greedy # strings
По данной непустой строке s длины не более 10^4, состоящей из строчных букв латинского
алфавита, постройте оптимальный беспрефиксный код. В первой строке выведите количество
различных букв k, встречающихся в строке, и размер получившейся закодированной строки.

Sample Input:
abacabad

Sample Output:
4 14
a: 0
b: 10
c: 110
d: 111
01001100100111
A

from collections import Counter
import heapq

def huffman_encoding_v1(s):
    encoding_dict = {}
    heap = [(freq, char) for char, freq in Counter(s).items()]
    heapq.heapify(heap)
    if len(heap) == 1:  # если в строке только один символ
        _freq, char = heapq.heappop(heap)
        encoding_dict[char] = str(0)  # the only type of characters is encoded by zero
    while len(heap) >= 2:  # если в строке как минимум два символа
        min_freq, min_char = heapq.heappop(heap)
        min2_freq, min2_char = heapq.heappop(heap)
    heapq.heappush(heap, (min_freq + min2_freq, min_char + min2_char))

    for i, char_string in enumerate([min_char, min2_char]):  # 0 для min_char, 1 для min2_char
        for char in char_string:  # каждый последующий символ кодируется с 0/1
            if char in encoding_dict:
                encoding_dict[char] = str(i) + encoding_dict[char]
            else:
                encoding_dict[char] = str(i)

return encoding_dict
def main():
    s = input()
encoding_dict = huffman_encoding_v1(s)

encoded_str = ''.join([encoding_dict[char] for char in s])

print(len(encoding_dict), len(encoded_str))
for key, value in sorted(encoding_dict.items()):
    print('{}: {}'.format(key, value))
print(encoded_str)

if __name__ == ‘__main__’:
main()

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
110
Q

декодирование Хаффмана
# greedy # strings
Восстановите строку по её коду и беспрефиксному коду символов.

В первой строке входного файла заданы два целых числа kk и ll через пробел — количество различных букв, встречающихся в строке, и размер получившейся закодированной строки, соответственно. В следующих kk строках записаны коды букв в формате “letter: code”. Ни один код не является префиксом другого. Буквы могут быть перечислены в любом порядке. В качестве букв могут встречаться лишь строчные буквы латинского алфавита; каждая из этих букв встречается в строке хотя бы один раз. Наконец, в последней строке записана закодированная строка. Исходная строка и коды всех букв непусты. Заданный код таков, что закодированная строка имеет минимальный возможный размер.

Sample Input :
4 14
a: 0
b: 10
c: 110
d: 111
01001100100111

Sample Output :
abacabad

A
def huffman_decoding(encoding_dict, encoded_str):
    decoded_str = ''
    encoding_dict = {value: key for key, value in encoding_dict.items()}
    sequence = ''
    for char in encoded_str:
        sequence += char
        if sequence in encoding_dict:
            decoded_str += encoding_dict[sequence]
            sequence = ''
return decoded_str
def main():
    k, _l = (int(i) for i in input().split())
encoding_dict = {}
for _ in range(k):
    key, value = (i.strip() for i in input().split(':'))
    encoding_dict[key] = value

encoded_str = input()
print(huffman_decoding(encoding_dict, encoded_str))

if __name__ == ‘__main__’:
main()

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
111
Q
Permutation Sequence
# numbers # arrays # permutations
The set [1,2,3,...,n] contains a total of n! unique permutations. Given n and k, return the kth permutation sequence.

Example 1:
Input: n = 3, k = 3
Output: “213”

A
def getPermutation(self, n: int, k: int) -> str:
// делаем массив с числами от 1 до n
        baselist = [i + 1 for i in range(n)]
// вычисляем количество перестановок
        numperm = 1
        for i in range(2, n + 1):
            numperm *= i
        string = ""
// проходимся циклом для определения каждого числа в k-й перестановке
        for i in range(n):
            # i-th character
// количество перестановок делим на разность n - i
            numperm /= n - i
// вычисляем индекс: делим k - 1 на число перестановок
            idx = int((k - 1) / numperm)
// берем из массива значение по вычисленному индексу, добавляем его в строку
            val = baselist.pop(idx)
            string += str(val)
// от k отнимаем произведение индекса на количество перестановок 
            k -= idx * numperm
// в конце возвращаем строку
        return string
112
Q

Dungeon Game
# arrays # matrices # numbers
The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess.

The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately.

Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0’s) or contain magic orbs that increase the knight’s health (positive integers).

In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step.
Write a function to determine the knight’s minimum initial health so that he is able to rescue the princess.

A
def calculateMinimumHP(self, dungeon: List[List[int]]) -> int:
	m, n = len(dungeon), len(dungeon[0])
	# вспомогательная функция для вычисления здоровья
	def calculate(i, j):
// если индексы равны измерениям матрицы, возвращаем очень большое число
		if i == m or j == n:
			return float('inf')
// если индексы на 1 меньше измерений матрицы, возвращаем либо 1, либо 1 - число по индексам (что больше)
		elif i == m-1 and j == n-1:
			return max(1,  1 - dungeon[i][j])
// если индексы есть в словаре, возвращаем значение по их ключу
		elif (i, j) in memory:
			return memory[i, j]
// рекурсивно вычисляем минимальное здоровье, если пойти вниз или направо
		down = calculate(i+1, j) 
		right = calculate(i, j+1)
// определяем текущее значение: минимум из максимума вниз - значение по индексам либо 1 и максимума направо - значение по индексам либо 1
		cur = min(max(down - dungeon[i][j], 1), max(right - dungeon[i][j], 1))
// в словарь записываем это значение с ключами-индексами
		memory[i, j] = cur
// возвращаем значение
		return cur
	memory = {}
	return calculate(0, 0)
113
Q

Single Number II
# numbers # arrays
Given a non-empty array of integers, every element appears three times except for one, which appears exactly once. Find that single one.
Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

Example 1:
Input: [2,2,3,2]
Output: 3

A
def singleNumber(self, nums: List[int]) -> int:
        return (sum(set(nums))*3 - sum(nums)) // 2
114
Q

Count Complete Tree Nodes
# trees # graphs
Given a complete binary tree, count the number of nodes.
Note:
Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2^h nodes inclusive at the last level h.

A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
// вариант за О(n): рекурсивно считаем все вершины
class Solution:
    def countNodes(self, root: TreeNode) -> int:
        if root:
            return 1 + self.countNodes(root.left) + self.countNodes(root.right)
        return 0
// вариант за О(logn*logn): определяем высоту левого и правого поддерева вспомогательной функцией, если они одинаковы, то возвращаем 2 в степени высота - 1, иначе складываем 1 и рекурсивные вызовы для левого и правого поддеревьев
class Solution:
    def countNodes(self, root):
        leftdepth = self.getdepth(root, True)
        rightdepth = self.getdepth(root, False)
    if leftdepth == rightdepth:
        return 2 ** leftdepth - 1
    else:
        return 1 + self.countNodes(root.left) + self.countNodes(root.right)

def getdepth(self, root, isLeft):
    if root is None:
        return 0
    if isLeft:
        return 1 + self.getdepth(root.left, isLeft)
    else:
        return 1 + self.getdepth(root.right, isLeft)
115
Q
Unique Binary Search Trees
# trees # graphs
Given n, how many structurally unique BST's (binary search trees) that store values 1 ... n?
Example:
Input: 3
Output: 5
Explanation:
Given n = 3, there are a total of 5 unique BST's:
   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3
A
// решение за O(n^2) с методом динамического программирования: нужно определить, сколько вершин в левом и правом поддеревьях (увеличивая значение корня, увеличивается количество в левом поддереве и уменьшается в правом), тогда можно воспользоваться рекуррентной формулой
def numTrees1(self, n):
// делаем массив нулей длины n, первым элементом записываем 1
    res = [0] * (n+1)
    res[0] = 1
// циклом проходимся от 1 до n+1, внутренний цикл до i: в массив по текущему индексу записываем произведение значений по второму индексу и по индексу разности i-1-j
    for i in range(1, n+1):
        for j in range(i):
            res[i] += res[j] * res[i-1-j]
//возвращаем последнее значение
    return res[n]
// решение за O(n) с использованием комбинаторной формулы чисел Каталана
f[n] = (2n)!/(n! * n! * (n+1))
def numTrees(self, n: int) -> int:
        return factorial(2*n)//factorial(n)//factorial(n)//(n+1)
116
Q
Find the Duplicate Number
# arrays #numbers

Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.

Example 1:
Input: [1,3,4,2,2]
Output: 2

Note:
You must not modify the array (assume the array is read only).
You must use only constant, O(1) extra space.
Your runtime complexity should be less than O(n2).
There is only one duplicate number in the array, but it could be repeated more than once.

A

// используем бинарный поиск
def findDuplicate(self, nums: List[int]) -> int:
// определяем левую и правую границу
left, right = 1, len(nums) - 1
// цикл, пока левая граница меньше правой
while left < right :
// определяем середину, заводим переменную-счетчик
mid = left + (right - left) // 2
count = 0
// проходимся циклом по массиву
for k in nums:
// если текущее число больше середины и не больше правой границы, увеличиваем счетчик
if mid < k <= right:
count += 1
// если счетчик больше разности правой границы и середины, сдвигаем левую границу (середина + 1), иначе сдвигаем правую границу (заменяем на середину)
if count > right - mid:
left = mid + 1
else:
right = mid
// в конце возвращаем правую границу
return right

117
Q

Sum Root to Leaf Numbers
# trees # graphs
Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number.
An example is the root-to-leaf path 1->2->3 which represents the number 123.
Find the total sum of all root-to-leaf numbers.
Note: A leaf is a node with no children.

Example:
Input: [1,2,3]
    1
   / \
  2   3
Output: 25
Explanation:
The root-to-leaf path 1->2 represents the number 12.
The root-to-leaf path 1->3 represents the number 13.
Therefore, sum = 12 + 13 = 25.
A

используем обход в глубину и стек
def sumNumbers1(self, root):
if not root:
return 0
// в стек записываем пары (нода, значение)
stack, res = [(root, root.val)], 0
// цикл, пока стек не пуст
while stack:
node, value = stack.pop()
if node:
// если у ноды нет детей, записываем ее значение в результат, иначе добавляем в стек правого/левого ребенка и их значения, умноженные на 10
if not node.left and not node.right:
res += value
if node.right:
stack.append((node.right, value10+node.right.val))
if node.left:
stack.append((node.left, value
10+node.left.val))
// в конце возвращаем результат
return res

# рекурсивное решение с обходом в глубину
def sumNumbers(self, root):
    self.res = 0
    self.dfs(root, 0)
    return self.res

def dfs(self, root, value):
if root:
// обход в глубину левой и правой ветки, к значению умноженному на 10 прибавляется значение детей
self.dfs(root.left, value10+root.val)
self.dfs(root.right, value
10+root.val)
// если нет детей, в результат прибавляется значение умноженное на 10 и значение ноды
if not root.left and not root.right:
self.res += value*10 + root.val

118
Q
Perfect Squares
# numbers # square
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.

Example 1:
Input: n = 12
Output: 3
Explanation: 12 = 4 + 4 + 4.

Example 2:
Input: n = 13
Output: 2
Explanation: 13 = 4 + 9.

A

// используем обход в ширину: глубина графа будет равна количеству чисел-квадратов
def numSquares(self, n: int) -> int:
// делаем список квадратов чисел, меньших n
s = [i*i for i in range(1, int(math.sqrt(n))+1)]
l = 0
// устанавливаем текущий уровень
curLevel = [0]
while True:
// устанавливаем следующий уровень
nextLevel = set()
// циклом проходимся по числам в текущем уровне и числам в списке квадратов
for i in curLevel:
for j in s:
// если их сумма равна n, возвращаем значение уровня + 1
if i+j == n:
return l+1
// если сумма меньше n, добавляем ее в след.уровень
if i+j < n:
nextLevel.add(i+j)
// меняем текущий уровень на следующий, увеличиваем значение глубины
curLevel = nextLevel
l += 1

119
Q

Reconstruct Itinerary
# graphs
Given a list of airline tickets represented by pairs of departure and arrival airports [from, to], reconstruct the itinerary in order. All of the tickets belong to a man who departs from JFK. Thus, the itinerary must begin with JFK.
Note:
If there are multiple valid itineraries, you should return the itinerary that has the smallest lexical order when read as a single string. For example, the itinerary [“JFK”, “LGA”] has a smaller lexical order than [“JFK”, “LGB”].
All airports are represented by three capital letters (IATA code).
You may assume all tickets form at least one valid itinerary.
One must use all the tickets once and only once.

Example 1:

Input: [[“MUC”, “LHR”], [“JFK”, “MUC”], [“SFO”, “SJC”], [“LHR”, “SFO”]]
Output: [“JFK”, “MUC”, “LHR”, “SFO”, “SJC”]

A

def findItinerary(self, tickets: List[List[str]]) -> List[str]:
// заводим defaultdict, проходимся циклом по обратно отсортированному списку, записываем в defaultdict пары аэропортов
targets = collections.defaultdict(list)
for a, b in sorted(tickets)[::-1]:
targets[a] += b,
// заводим списки для маршрута и стека с первым аэропортом
route, stack = [], [‘JFK’]
// цикл, пока стек не пустой и пока не пустая запись в словаре по ключу последнего элемента в стеке: добавляем в стек список по ключу последнего элемента в списке (и убираем его из стека), в маршрут добавляем первый элемент стека
while stack:
while targets[stack[-1]]:
stack += targets[stack[-1]].pop(),
route += stack.pop(),
// в конце возвращаем маршрут в обратном порядке
return route[::-1]

120
Q

Unique Paths
# graphs # matrices
A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).
How many possible unique paths are there?

Example 1:
Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Right -> Down
2. Right -> Down -> Right
3. Down -> Right -> Right
A
// решение с помощью комбинаторной формулы: количество сочетаний из m+n-2 по m-1
 def uniquePaths(self, m: int, n: int) -> int:
        return math.comb(m + n - 2, m - 1)
// решение динамическим программированием: делаем массив из единиц длины n, проходимся циклом от 1 до m и от 1 до n: в элемент по индексу j записывается сумма предыдущего элемента и текущего
def uniquePaths(self, m: int, n: int) -> int:
        dp = [1] * n
        for i in range(1, m):
            for j in range(1, n):
                dp[j] = dp[j - 1] + dp[j]
// возвращаем последний элемент массива, если размерность не пустая, иначе 0
        return dp[-1] if m and n else 0
121
Q

Word Search II
# strings # matrices # search
Given a 2D board and a list of words from the dictionary, find all words in the board.
Each word must be constructed from letters of sequentially adjacent cell, where “adjacent” cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.

Example:
Input: 
board = [
  ['o','a','a','n'],
  ['e','t','a','e'],
  ['i','h','k','r'],
  ['i','f','l','v']
]
words = ["oath","pea","eat","rain"]
Output: ["eat","oath"]
A

def findWords(self, board, words):
// делаем словарь-префиксное дерево
trie = {}
// проходимся циклом по словам в наборе, делая копию словаря, и буквам в каждом слове - составляем префиксные деревья, в конце ставим заглушку из символа решетки
for w in words:
t = trie
for c in w:
if c not in t:
t[c] = {}
t = t[c]
t[’#’] = ‘#’
res = []
// проходимся циклом по матрице букв, выполняем поиск по индексам, префиксному дереву, строке-пути и массиву-результату
for i in range(len(board)):
for j in range(len(board[0])):
self.find(board, i, j, trie, ‘’, res)
// в конце возвращаем список-сет результата
return list(set(res))

// вспомогательная функция поиска
def find(self, board, i, j, trie, path, res):
// если в префиксном дереве есть решетка, добавляем в результат строку-путь
if ‘#’ in trie:
res.append(path)
// если индексы меньше 0 или больше размеров матрицы или элемента по индексам нет в префиксном дереве, выходим
if i<0 or i>=len(board) or j<0 or j>=len(board[0]) or board[i][j] not in trie:
return
// записываем во временную переменную текущий элемент матрицы, его меняем на знак собачки
tmp = board[i][j]
board[i][j] =”@”
// рекурсивно выполняем поиск по соседям, префиксному дереву по ключу текущего элемента, к строке-пути прибавляем текущий элемент
self.find(board, i+1, j, trie[tmp], path+tmp, res)
self.find(board, i, j+1, trie[tmp], path+tmp, res)
self.find(board, i-1, j, trie[tmp], path+tmp, res)
self.find(board, i, j-1, trie[tmp], path+tmp, res)
// в текущий элемент обратно записываем исходную букву
board[i][j] = tmp

122
Q
Arranging Coins
# math # numbers
You have a total of n coins that you want to form in a staircase shape, where every k-th row must have exactly k coins.
Given n, find the total number of full staircase rows that can be formed.
n is a non-negative integer and fits within the range of a 32-bit signed integer.
Example 1:
n = 5
The coins can form the following rows:
¤
¤ ¤
¤ ¤
Because the 3rd row is incomplete, we return 2.
A
// используя математическую формулу:  общее количество монет - s*(s+1)/2, нужно s*(s+1)/2 <= n или s^2 + s - 2n = 0, решаем квадратное уравнение
def arrangeCoins(self, n):
        return int(sqrt(2*n + 0.25) - 0.5)
// линейный поиск: заводим переменные для текущего, предыдущего значений, номера ряда, циклом вычисляем значения, пока текущее меньше n, в конце возвращаем ряд
def arrangeCoins(self, n):
if n == 0:
            return 0
        prev = 1
        row = 1
        while True:
            cur = prev + row + 1
            prev = cur
            if cur > n:
                break
            else:
                row += 1
        return row
// бинарный поиск
def arrangeCoins(self, n: int) -> int:
        left, right = 0, n
        while left <= right:
            k = (right + left) // 2
            curr = k * (k + 1) // 2
            if curr == n:
                return k
            if n < curr:
                right = k - 1
            else:
                left = k + 1
        return right
123
Q
Binary Tree Level Order Traversal II
# graphs # trees
Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root).
For example:
Given binary tree [3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
return its bottom-up level order traversal as:
[
  [15,7],
  [9,20],
  [3]
]
A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:
        res = []
        self.dfs(root, 0, res)
        return res

// используем рекурсивный обход в глубину: если нода непустая и длина результирующего списка меньше, чем высота дерева+1, в начало массива добавляем пустой подмассив, затем добавляем значение ноды по отрицательному индексу высоты+1 (чтобы поставить в конец), и делаем обход по левым и правым детям, увеличив высоту
def dfs(self, root, level, res):
if root:
if len(res) < level + 1:
res.insert(0, [])
res[-(level+1)].append(root.val)
self.dfs(root.left, level+1, res)
self.dfs(root.right, level+1, res)

124
Q

Prison Cells After N Days
# numbers # arrays
There are 8 prison cells in a row, and each cell is either occupied or vacant.
Each day, whether the cell is occupied or vacant changes according to the following rules:
If a cell has two adjacent neighbors that are both occupied or both vacant, then the cell becomes occupied.
Otherwise, it becomes vacant.
(Note that because the prison is a row, the first and the last cells in the row can’t have two adjacent neighbors.)
We describe the current state of the prison in the following way: cells[i] == 1 if the i-th cell is occupied, else cells[i] == 0.
Given the initial state of the prison, return the state of the prison after N days (and N such changes described above.)

Input: cells = [0,1,0,1,1,0,0,1], N = 7
Output: [0,0,1,1,0,0,0,0]
Explanation: 
The following table summarizes the state of the prison on each day:
Day 0: [0, 1, 0, 1, 1, 0, 0, 1]
Day 1: [0, 1, 1, 0, 0, 0, 0, 0]
Day 2: [0, 0, 0, 0, 1, 1, 1, 0]
Day 3: [0, 1, 1, 0, 0, 1, 0, 0]
Day 4: [0, 0, 0, 0, 0, 1, 0, 0]
Day 5: [0, 1, 1, 1, 0, 1, 0, 0]
Day 6: [0, 0, 1, 0, 1, 1, 0, 0]
Day 7: [0, 0, 1, 1, 0, 0, 0, 0]
A

// надо учитывать, что массив состояний становится как был каждые 14 дней, при этом первая и последняя клетка всегда будут 0
def prisonAfterNDays(self, cells: List[int], N: int) -> List[int]:
// если N делится без остатка на 14, то меняем его значение на 14, иначе меняем на остаток от деления на 14
if N%14 == 0:
N = 14
else:
N = N%14

// проходимся циклом от 1 до N+1, делаем временные массивы нулей, проходимся циклом от 1 до длины массива-1, если предыдущая клетка равна следующей, то во временный массив по текущему индексу записываем 1, иначе 0, меняем исходный массив на временный
for i in range(1, N+1):
temp = [0]*len(cells)
for i in range(1, len(cells)-1):
if cells[i-1] == cells[i+1]:
temp[i] = 1
else:
temp[i] = 0
cells = temp
return(cells)

// решение с хранением состояний массива
def prisonAfterNDays(self, cells: List[int], N: int) -> List[int]:
// выносим в отдельную функцию обновление массива по правилам (если предыдущая клетка равна следующей, то во временный массив по текущему индексу записываем 1, иначе 0)
def nextday(cells):
next_day_cells = [0] *len(cells)
for i in range(1,len(cells)-1):
if cells[i-1] == cells[i+1]:
next_day_cells[i] = 1
else:
next_day_cells[i] = 0
return next_day_cells
// заводим словарь состояний, цикл пока N больше 0, заводим переменную-кортеж массива, если на есть в словаре, то в N записываем остаток от деления на разность значения по ключу кортежа и N, добавляем в словарь запись кортеж массива: N
seen = {}
while N > 0:
c = tuple(cells)
if c in seen:
N %= seen[c] - N
seen[c] = N
// если N больше-равно 1, уменьшаем его на 1, в массив записываем новое значение по вспомогательной функции
if N >= 1:
N -= 1
cells = nextday(cells)

    return cells
125
Q

Ugly Number II
# arrays # numbers
Write a program to find the n-th ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5.

Example:
Input: n = 10
Output: 12
Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.

Note:
1 is typically treated as an ugly number.
n does not exceed 1690.

A
// решаем методом динамического программирования: делаем массив из нулей длины n, первым элементом записываем единицу, заводим переменные для множителей на 2, 3, 5
def nthUglyNumber(self, n: int) -> int:
        nums = [0 for _ in range(n)]
        nums[0] = 1
        m2, m3, m5 = 0, 0, 0
// циклом проходимся от 1 до n, в массив записываем меньшее из произведений элементов массива по индексу множителя на 2, 3 или 5; если число по текущему массиву равно какому-то произведению множителей, увеличиваем переменную множителя на 1, в конце возвращаем последний элемент массива
        for i in range(1, n):
            nums[i] = min(nums[m2] * 2, nums[m3] * 3, nums[m5] * 5)
            if nums[i] == nums[m2]*2:
                m2 += 1
            if nums[i] == nums[m3]*3:
                m3 += 1
            if nums[i] == nums[m5]*5:
                m5 += 1
        return nums[-1]
126
Q
Hamming Distance
# numbers # bitwise
Given two integers x and y, calculate the Hamming distance.
Note:
0 ≤ x, y < 2^31.
Example:
Input: x = 1, y = 4
Output: 2
Explanation:
1   (0 0 0 1)
4   (0 1 0 0)
         ↑    ↑
A
// нужно воспользоваться операцией исключающего ИЛИ (^) и вычислением количества 1-битов в числе (t = t&amp;(t-1), удаляем последний 1-бит)
def hammingDistance(self, x, y):
        Out, t = 0, x^y 
        while t:
            t, Out = t &amp; (t-1), Out + 1
        return Out
// во временную переменную сохраняем исключающее ИЛИ исходных чисел, в цикле к результату прибавляем вычисление побитового И временной переменной и 1, временную переменную побитово сдвигаем влево на 1 (делим на 2)
def hammingDistance(self, x: int, y: int) -> int:
        temp = x ^ y
        res = 0
        while temp:
            res += temp &amp; 1
            temp = temp >> 1
        return res
127
Q

Plus One
# numbers # arrays
Given a non-empty array of digits representing a non-negative integer, plus one to the integer.
The digits are stored such that the most significant digit is at the head of the list, and each element in the array contain a single digit.
You may assume the integer does not contain any leading zero, except the number 0 itself.

Example 1:
Input: [1,2,3]
Output: [1,2,4]
Explanation: The array represents the integer 123.

A
// идем по массиву справа налево, если цифра меньше 9, прибавляем 1 и останавливаемся, иначе меняем на 0, если есть остаток, то добавляем 1 в начало массива
def plusOne(self, digits: List[int]) -> List[int]:
        i = len(digits) - 1
        carry = False
        while i >= 0:
            if digits[i] < 9:
                digits[i] += 1
                carry = False
                break
            else:
                digits[i] = 0
                carry = True
            i -= 1
        if carry:
            digits.insert(0,1)
        return digits
128
Q

Island Perimeter
# numbers # matrices
You are given a map in form of a two-dimensional integer grid where 1 represents land and 0 represents water.
Grid cells are connected horizontally/vertically (not diagonally). The grid is completely surrounded by water, and there is exactly one island (i.e., one or more connected land cells).
The island doesn’t have “lakes” (water inside that isn’t connected to the water around the island). One cell is a square with side length 1. The grid is rectangular, width and height don’t exceed 100. Determine the perimeter of the island.

Example:
Input:
[[0,1,0,0],
 [1,1,1,0],
 [0,1,0,0],
 [1,1,0,0]]
Output: 16
A

// линейно проходимся по матрице: если в текущей ячейке 1, прибавляем к периметру 4, если индексы меньше границ-1 и есть соседняя 1 справа и/или снизу, из периметра вычитаем 2
def islandPerimeter(self, grid: List[List[int]]) -> int:
m = len(grid)
n = len(grid[0])
P = 0
for i in range(m):
for j in range(n):
if grid[i][j] == 1:
P += 4
if i < m - 1 and grid[i+1][j] == 1:
P -= 2
if j < n - 1 and grid[i][j+1] == 1:
P -= 2
return P

// решение с обходом в глубину
def islandPerimeter(self, g):
        m, n = len(g), len(g[0])
        self.peri = 0
        def dfs(x, y):
            if not (0 <= x < m and 0 <= y < n) or g[x][y] == 0:
                # если индексы пограничные или ячейка нулевая, прибавляем к периметру 1
                self.peri += 1
                return
            elif g[x][y] == -1:
                # если ячейка уже посещена, выходим
                return
        g[x][y] = -1 # отмечаем ячейку как посещенную
            # посещаем все соседние ячейки
            dfs(x - 1, y)
            dfs(x + 1, y)
            dfs(x, y - 1)
            dfs(x, y + 1)
// циклом проходимся по матрице и делаем поиск в глубину для всех единичных ячеек      
        for i in range(m):
            for j in range(n):
                if g[i][j] == 1:
                    dfs(i, j)
                    return self.peri
129
Q

3Sum
# numbers # arrays
Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
The solution set must not contain duplicate triplets.

Example:
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]
A

// решение с указателями
def threeSum(self, nums: List[int]) -> List[List[int]]:
res = []
n = len(nums)
// сортируем массив, проходимся по индексам: если индекс больше 0 и числа по текущему и предыдущему индексу совпадают, идем дальше
nums = sorted(nums)
for i in range(n-2):
if i > 0 and nums[i] == nums[i-1]:
continue
// заводим 2 указателя, переменную с противоположным числом по текущему индексу
j = i+1
k = n-1
new_target = -nums[i]
// пока первый указатель меньше второго, заводим сумму чисел по этим указателям, если она меньше целевого числа, увеличиваем первый указатель, если больше, уменьшаем второй указатель
while j < k:
summ = nums[j] + nums[k]
if summ < new_target:
j += 1
elif summ > new_target:
k -= 1
// иначе добавляем в массив числа по трем индексам, циклами увеличиваем первый указатель и уменьшаем второй указатель
else:
res.append([nums[i], nums[j], nums[k]])
while j < k and nums[j+1] == nums[j]:
j += 1
j += 1
while k > j and nums[k-1] == nums[k]:
k -= 1
k -= 1
return res

// решение с бинарным поиском
def threeSum(self, nums: List[int]) -> List[List[int]]:
// заводим словарь Counter для массива чисел, сортируем его
counter = collections.Counter(nums)
nums = sorted(counter)
ret = []
// проходимся по индексам и числам
for i, num in enumerate(nums):
# 1 случай: все числа одинаковы - [0,0,0], число равно 0 и встречается больше 2 раз
if num==0:
if counter[num] > 2:
ret.append([0, 0, 0])
# 2 случай: 2 числа из тройки одинаковы, число встречается больше 1 раза и в словаре есть ключ-противоположное число, в 2 раза большее
elif counter[num] > 1 and -2 * num in counter:
ret.append([num, num, -2 * num])
# 3 случай: все числа разные
// если число отрицательное, заводим противоположное ему число и определяем границы поиска оставшейся пары чисел
if num < 0:
opposite = -num
// выполняем левый поиск от разности противоположного числа и последнего числа до индекса + 1, и правый поиск от противоположного числа пополам до левой границы
left = bisect_left(nums, opposite - nums[-1], i + 1)
right = bisect_right(nums, opposite / 2, left)
// циклом проходимся по срезу чисел, заводим переменную-разность противоположного числа минус текущее, если оно есть в словаре и они не равны, записываем тройку чисел в ответ
for a in nums[left:right]:
b = opposite - a
if b in counter and a!=b:
ret.append([num, a, b])
return ret

130
Q
Maximum Width of Binary Tree
# trees # graphs
Given a binary tree, write a function to get the maximum width of the given tree. The width of a tree is the maximum width among all levels. The binary tree has the same structure as a full binary tree, but some nodes are null.
The width of one level is defined as the length between the end-nodes (the leftmost and right most non-null nodes in the level, where the null nodes between the end-nodes are also counted into the length calculation.

Example 1:
Input:

           1
         /   \
        3     2
       / \     \  
      5   3     9 

Output: 4
Explanation: The maximum width existing in the third level with the length 4 (5,3,null,9).

Example 2:
Input:

          1
         /  
        3    
       / \       
      5   3     

Output: 2
Explanation: The maximum width existing in the third level with the length 2 (5,3).

Example 3:
Input:

          1
         / \
        3   2 
       /        
      5      

Output: 2
Explanation: The maximum width existing in the second level with the length 2 (3,2).

Example 4:
Input:

          1
         / \
        3   2
       /     \  
      5       9 
     /         \
    6           7
Output: 8
Explanation:The maximum width existing in the fourth level with the length 8 (6,null,null,null,null,null,null,7).
A

Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def widthOfBinaryTree(self, root: TreeNode) -> int:
// заводим стек для нод и уровней
self.stack = [[]]
// функция для обхода дерева (аргументы - уровень, позиция и корень поддерева): если длина стека не больше уровня, то в стек добавляем подмассив с позицией, иначе добавляем позицию в подмассив по индексу уровня. Рекурсивно обходим левые и правые поддеревья, увеличив уровень на 1, и сдвинув позицию (умножив на 2 или умножив на 2 + 1)
def traverse(level, pos, root):
if root:
if len(self.stack) <= level:
self.stack.append([pos])
else:
self.stack[level].append(pos)
traverse(level+1, 2pos, root.left)
traverse(level+1, 2
pos+1, root.right)
traverse(0,0,root)
// в конце возвращаем максимум из разностей (максимальная нода - минимальная нода + 1 на каждом уровне)
return max(max(s)-min(s)+1 for s in self.stack)

131
Q
Flatten a Multilevel Doubly Linked List
# linked lists
You are given a doubly linked list which in addition to the next and previous pointers, it could have a child pointer, which may or may not point to a separate doubly linked list. These child lists may have one or more children of their own, and so on, to produce a multilevel data structure, as shown in the example below.
Flatten the list so that all the nodes appear in a single-level, doubly linked list. You are given the head of the first level of the list.

Input: head = [1,2,null,3]
Output: [1,3,2]
Explanation:
The input multilevel linked list is as follows:

1—2—NULL
|
3—NULL

A
// рекурсивное решение
def flatten(self, head: 'Node') -> 'Node':
        if not head:
            return (None)
        self.travel(head)
        return (head)
    def travel(self, cur):
        while cur:
            next_node = cur.next # нужно отдельно хранить следующую ноду, потому что указатель может перезаписаться на ноду-потомка
            if not next_node: tail = cur  # если следующих нод нет, мы дошли до хвостовой ноды текущего уровня
            if cur.child: # если у текущей ноды есть потомок, надо обработать его и других потомков: предыдущий указатель потомка переставляем на текущую ноды, следующий указатель текущей ноды переставляем на потомка
                cur.child.prev = cur
                cur.next = cur.child
                child_tail = self.travel(cur.child) # рекурсивно находим хвостовую ноду уровня потомка
                if next_node:     # если на предыдущем уровне есть следующая нода, то ее предыдущий указатель надо переставить на хвост уровня потомка 
                    next_node.prev = child_tail
                child_tail.next = next_node  # присоединяем хвост к уровню выше, к следующей ноде
                cur.child = None  # удаляем указатели на потомков
            cur = cur.next  # переставляем текущую ноду (перейдет либо на потомка, либо на следующую)
        return (tail)  # возвращаем хвост текущего уровня

// итеративное решение со стеком
def flatten(self, head: ‘Node’) -> ‘Node’:
if not head: return None
// в стек записываем голову, заводим переменную для предыдущей ноды
stack = [head]; p = None
// пока стек не пустой, извлекаем из него текущую ноду
while stack:
r = stack.pop()
// если есть предыдущая нода, то меняем ее след.указатель на пред.указатель текущей ноды, и предыдущая нода становится текущей
if p:
p.next,r.prev = r,p
p = r
// если у текущей ноды есть след.нода, добавляем ее в стек, если есть потомок, тоже добавляем его в стек, а указатель стираем
if r.next:
stack.append(r.next)
if r.child:
stack.append(r.child)
r.child = None
return head

132
Q
Subsets
# numbers # arrays # math
Given a set of distinct integers, nums, return all possible subsets (the power set).

Note: The solution set must not contain duplicate subsets.

Example:

Input: nums = [1,2,3]
Output:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
A

// итеративное решение: проходим циклом по массиву чисел, в итоговому массиву добавляем подмножества итогового массива с числами
def subsets(self, nums: List[int]) -> List[List[int]]:
res = [[]]
for n in nums:
res.extend([subset + [n] for subset in res])
return res

// решение с битами: проходимся по степеням двойки в диапазоне размера массива, делаем временный массив, проходимся циклом по индексам массива, если степень и 1 - это степень индекса, то во временный массив добавляем число по текущему индексу, итоговый временный массив добавляем в результат
def subsets(self, nums: List[int]) -> List[List[int]]:
        res = []
        for i in range(1<
133
Q
Reverse Bits
# bit manipulation
Reverse bits of a given 32 bits unsigned integer.

Example 1:
Input: 00000010100101000001111010011100
Output: 00111001011110000010100101000000
Explanation: The input binary string 00000010100101000001111010011100 represents the unsigned integer 43261596, so return 964176192 which its binary representation is 00111001011110000010100101000000.

Example 2:
Input: 11111111111111111111111111111101
Output: 10111111111111111111111111111111
Explanation: The input binary string 11111111111111111111111111111101 represents the unsigned integer 4294967293, so return 3221225471 which its binary representation is 10111111111111111111111111111111.

A

def reverseBits(self, n):
out = 0
for i in range(32):
out = (out &laquo_space;1)^(n & 1) // добавляем последний бит числа к перевертышу
n&raquo_space;= 1 // убираем последний бит из числа
return out

134
Q
Same Tree
# graphs # trees
Given two binary trees, write a function to check if they are the same or not.
Two binary trees are considered the same if they are structurally identical and the nodes have the same value.

Example 1:
Input: 1 1
/ \ / \
2 3 2 3

    [1,2,3],   [1,2,3]

Output: true

Example 2:
Input: 1 1
/ \
2 2

    [1,2],     [1,null,2]

Output: false

Example 3:
Input: 1 1
/ \ / \
2 1 1 2

    [1,2,1],   [1,1,2]

Output: false

A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
// если обеих нод нет, возвращаем истину
        if not p and not q:
            return True
// если нет одной из нод или значения не совпадают, возвращаем ложь
        if not p and q or p and not q:
            return False
        if p.val != q.val:
            return False
// рекурсивно проверяем левые и правые поддеревья
        return self.isSameTree(p.left,q.left) and self.isSameTree(p.right, q.right)
// в одной строке: проверяем, что обе ноды есть, их значения равны, рекурсивно равны левые и правые поддеревья, или же обеих нод нет
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        return p and q and p.val == q.val and self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right) or p == q
// решение с помощью кортежа и рекурсии
def isSameTree(self, p: TreeNode, q: TreeNode) -> bool:
        def t(n):
            return n and (n.val, t(n.left), t(n.right))
        return t(p) == t(q)
135
Q

Angle between hands of a clock
# math
Given two numbers, hour and minutes. Return the smaller angle (in degrees) formed between the hour and the minute hand.

Input: hour = 12, minutes = 30
Output: 165

A
Если весь циферблат = 360 градусов, то 1 час = 30 градусов, 1 минута = 6 градусов. Минутная стрелка влияет на часовую, поэтому к углу часовой стрелки надо прибавить количество минут * 0.5 градуса (60 делений, 30 / 60), затем из этого угла вычесть угол минутной стрелки. В конце определить какой угол меньше, полученный или разность 360 - угол
def angleClock(self, hour: int, minutes: int) -> float:
        a = abs((hour * 30 + minutes * 0.5) - (minutes * 6))
        return min(a, 360 - a)
136
Q

Pow(x, n)
# math
Implement pow(x,n)
Note:

-100.0 < x < 100.0
n is a 32-bit signed integer, within the range [−231, 231 − 1]

A
// подход разделяй-и-властвуй
def myPow(self, x: float, n: int) -> float:
        if n == 0:
            return 1
// случай для отрицательных степеней
        if n < 0:
            return 1/self.myPow(x, -n)
// вычисляем "половину": число в степени вдвое меньше исходной
        half = self.myPow(x, n//2)
// если n четное, возвращаем квадрат половины, умноженный на число, иначе просто квадрат половины
        if n%2:
            return half*half*x
        return half*half
// итеративное решение
    def myPow(self, x: float, n: int) -> float:
            if n<0:
                x = 1/x
                n = abs(n)
// заводим переменную-результат
            res = 1
// цикл, пока степень больше 0
            while n > 0:
// если степень нечетная, то результат умножаем на число, число так же умножаем на себя, а степень делим нацело пополам
                if n%2 == 1:
                    res *= x
                x *= x
                n //= 2
            return res
137
Q
Top K Frequent Elements
# arrays # numbers
Given a non-empty array of integers, return the k most frequent elements.

Example 1:
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]

Example 2:
Input: nums = [1], k = 1
Output: [1]
Note:

You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
Your algorithm’s time complexity must be better than O(n log n), where n is the array’s size.
It’s guaranteed that the answer is unique, in other words the set of the top k frequent elements is unique.
You can return the answer in any order.

A
// решение с кучей: делаем словарь-счетчик чисел, возвращаем список, применив метод кучи nlargest по числу k, ключам словаря, основание-значение ключей по методу get)
from collections import Counter
class Solution:
    def topKFrequent(self, nums: List[int], k: int) -> List[int]:
        if k == len(nums):
            return nums
        count = Counter(nums)   
        return heapq.nlargest(k, count.keys(), key=count.get) 
// решение с сортировкой bucket sort: делаем массив массивов длиной исходного массива +1, делаем словарь-счетчик чисел и сохраняем его как список кортежей (ключ, значение), проходимся по нему циклом и сохраняем в массиве массивов числа по индексу частотности, затем делаем один большой массив из подмассивов (itertools.chain), разворачиваем его и возвращаем первые к элементов
class Solution:
    def topKFrequent(self, nums, k):
        bucket = [[] for _ in range(len(nums) + 1)]
        Count = Counter(nums).items()  
        for num, freq in Count: bucket[freq].append(num) 
        flat_list = list(chain(*bucket))
        return flat_list[::-1][:k]
138
Q

Course Schedule II
# graphs # numbers
There are a total of n courses you have to take, labeled from 0 to n-1.

Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1]

Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses.

There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array.

Example 1:

Input: 2, [[1,0]]
Output: [0,1]
Explanation: There are a total of 2 courses to take. To take course 1 you should have finished
course 0. So the correct course order is [0,1] .

A

// используются топологическая сортировка и обход в глубину

def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
// делаем словари вершин и соседей, заполняем их
dic = collections.defaultdict(set)
neigh = collections.defaultdict(set)
for i, j in prerequisites:
dic[i].add(j)
neigh[j].add(i)
// делаем стек значений, недостающих в словаре
stack = [i for i in range(numCourses) if not dic[i]]
res = []
// пока стек непустой, достаем из него последнюю ноду, добавляем ее в результирующий массив, проходимся по значениям ключа-ноды в словаре соседей: если его нет в словаре вершин, то добавляем его в стек, потом убираем из словаря саму ноду
while stack:
node = stack.pop()
res.append(node)
for i in neigh[node]:
dic[i].remove(node)
if not dic[i]:
stack.append(i)
dic.pop(node)
// в конце возвращаем результирующий массив, если словарь стал пустым, иначе пустой массив
return res if not dic else []

def findOrder(self, n, pres):
// делаем массив-граф и массив-счетчик выходящих вершин
        ind = [[] for _ in range(n)]  # indegree
        oud = [0] * n  # outdegree
        for p in pres:
            oud[p[0]] += 1
            ind[p[1]].append(p[0])
        ans = []
// циклом заполняем результирующий массив: если нет выходящих вершин по текущему индексу, добавляем индекс в массив
        for i in range(n):
            if oud[i] == 0:
                ans.append(i)
        l = 0
// пока l не равна длине результата, записываем значение из результата по индексу l, l увеличиваем
        while l != len(ans):
            x = ans[l]
            l += 1
// проходимся по вершинам графа по текущему индексу, счетчик выходящих вершин уменьшаем, а если он нулевой, то индекс записываем в результат
            for i in ind[x]:
                oud[i] -= 1
                if oud[i] == 0:
                    ans.append(i)
// возвращаем результат, если l равна числу всех курсов, иначе пустой массив
        return ans if l == n else []
139
Q
Add Binary
# strings # math
Given two binary strings, return their sum (also a binary string).
The input strings are both non-empty and contains only characters 1 or 0.

Example 1:
Input: a = “11”, b = “1”
Output: “100”

Example 2:
Input: a = “1010”, b = “1011”
Output: “10101”

A

def addBinary(self, a: str, b: str) -> str:
// заводим переменную-остаток и строку-результат
carry = 0
result = ‘’
// из строк делаем списки
a = list(a)
b = list(b)
// пока один из списков непустой или есть остаток:
while a or b or carry:
// если список непустой, к остатку добавляем последнюю цифру списка
if a:
carry += int(a.pop())
if b:
carry += int(b.pop())
// к строке-результату прибавляем остаток от деления остатка на 2, остаток делим на 2
result += str(carry %2)
carry //= 2
// в конце возвращаем перевернутую строку
return result[::-1]

def addBinary(self, a: str, b: str) -> str:
// заводим переменную-индекс, длины строк, список-результат и остаток
i, m, n, result, carry = 1, len(a), len(b), [], 0
// пока индекс не больше одной из строк:
while i <= m or i <= n:
// во временную переменную записываем остаток
temp = carry
// если индекс не больше длины исходной строки, к временной переменной добавляем цифру с конца (отрицательный индекс)
if i <= m:
temp += int(a[-i])
if i <= n:
temp += int(b[-i])
// остаток равен делению временной переменной на 2, к результату добавляем остаток от деления временной переменной на 2, индекс увеличиваем
carry = temp // 2
result.append(str(temp % 2))
i += 1
// если остался остаток, добавляем его в результат
if carry:
result.append(str(carry))
// в конце возвращаем перевернутый список, преобразованный в строку
return ‘‘.join(result[::-1])

140
Q
Remove Linked List Elements
# linked lists
Remove all elements from a linked list of integers that have value val.

Example:

Input: 1->2->6->3->4->5->6, val = 6
Output: 1->2->3->4->5

A
# Definition for singly-linked list.
# class ListNode:
#     def \_\_init\_\_(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeElements(self, head: ListNode, val: int) -> ListNode:
// удаляемая нода может быть в начале списка, поэтому надо сначала передвинуть циклом указатель
        while head and head.val == val:
            head = head.next
// заводим переменные для текущей и предыдущей ноды
        curr = head
        prev = curr
// пока текущая нода существует, проверяем ее значение, если оно равно удаляемому, указатель пред. ноды передвигаем на указатель текущей ноды, иначе делаем предыдущую ноду текущей, также сдвигаем текущую ноду
        while curr:
            if curr.val == val:
                prev.next = curr.next
            else:
                prev = curr
            curr = curr.next
        return head
class Solution:
    def removeElements(self, head: ListNode, val: int) -> ListNode:
        if not head:
            return
// делаем ноду-заглушку перед головной
        dummy = ListNode(-1)
        dummy.next = head
// делаем текущую ноду равной заглушке, проходимся циклом, пока есть следующая нода после текущей: если значение след.ноды равно удаляемому, передвигаем указатель через ноду, иначе сдвигаем текущую ноду
        cur = dummy
        while cur.next:
            if cur.next.val == val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        return dummy.next
141
Q
Word Search
# strings # matrices

Given a 2D board and a word, find if the word exists in the grid.

The word can be constructed from letters of sequentially adjacent cell, where “adjacent” cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.

Example:

board =
[
  ['A','B','C','E'],
  ['S','F','C','S'],
  ['A','D','E','E']
]

Given word = “ABCCED”, return true.
Given word = “SEE”, return true.
Given word = “ABCB”, return false.

A
// решение с обходом в глубину
def exist(self, board: List[List[str]], word: str) -> bool:
        if not board:
            return False
        for i in range(len(board)):
            for j in range(len(board[0])):
                if self.dfs(board, i, j, word):
                    return True
        return False

функция для обхода в глубину
def dfs(self, board, i, j, word):
if len(word) == 0: # в случае если все буквы проверены
return True
// если индексы меньше 0 или больше размеров доски или первая буква не равна букве по текущим индексам, возвращаем ложь
if i<0 or i>=len(board) or j<0 or j>=len(board[0]) or word[0]!=board[i][j]:
return False
tmp = board[i][j] # находим первую букву и проверяем оставшиеся
board[i][j] = “#” решеткой отмечаем посещенные буквы
# рекурсивно обходим соседние буквы по разным индексам
res = self.dfs(board, i+1, j, word[1:]) or self.dfs(board, i-1, j, word[1:]) \
or self.dfs(board, i, j+1, word[1:]) or self.dfs(board, i, j-1, word[1:])
board[i][j] = tmp
return res

// аналогичное решение с обходом
def exist(self, board, word):
        if not word:
            return True
        if not board:
            return False
        for i in range(len(board)):
            for j in range(len(board[0])):
                if self.exist_helper(board, word, i, j):
                    return True
        return False
def exist_helper(self, board, word, i, j):
    if board[i][j] == word[0]:
        if not word[1:]:
            return True
        board[i][j] = " " # отмечаем посещенную букву
        # проверяем соседние буквы по индексам и рекурсивному обходу
        if i > 0 and self.exist_helper(board, word[1:], i-1, j):
            return True
        if i < len(board)-1 and self.exist_helper(board, word[1:], i+1, j):
            return True
        if j > 0 and self.exist_helper(board, word[1:], i, j-1):
            return True
        if j < len(board[0])-1 and self.exist_helper(board, word[1:], i, j+1):
            return True
        board[i][j] = word[0] # меняем значение ячейки обратно на букву
        return False
    else:
        return False
142
Q
Binary Tree Zigzag Level Order Traversal
# graphs # trees
Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).
For example:
Given binary tree [3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
return its zigzag level order traversal as:
[
  [3],
  [20,9],
  [15,7]
]
A

// решение с обходом в ширину и очередью
def zigzagLevelOrder(self, root):
// заводим переменные для результата-массива и очереди с парами (вершина, уровень)
res, queue = [], [(root, 0)]
// пока очередь непустая:
while queue:
// извлекаем из очереди текущую ноду и очередь
curr, level = queue.pop(0)
// если нода существует и длина результирующего массива меньше текущего уровня+1, в результат добавляем подмассив, если уровень четный, то в подмассив результата по индексу текущего уровня добавляем значение текущей ноды, иначе добавляем в тот же подмассив, но в начало
if curr:
if len(res) < level+1:
res.append([])
if level % 2 == 0:
res[level].append(curr.val)
else:
res[level].insert(0, curr.val)
// в массив очереди добавляем левого и правого ребенка, увеличиваем уровень на 1
queue.append((curr.left, level+1))
queue.append((curr.right, level+1))
// в конце возращаем результирующий массив
return res

// решение с обходом в глубину
def zigzagLevelOrder(self, root):
    res = []
    self.dfs(root, 0, res)
    return res

def dfs(self, root, level, res):
// если нода есть
if root:
// если длина результирующего массива меньше, чем уровень +1, до добавляем туда пустой подмассив
if len(res) < level + 1:
res.append([])
// если уровень четный, то в подмассив по текущему уровню добавляем значение текущей ноды, иначе добавляем значение в начало подмассива
if level % 2 == 0:
res[level].append(root.val)
else:
res[level].insert(0, root.val)
// рекурсивно обходим левое и правое поддерево, увеличив уровень на 1
self.dfs(root.left, level+1, res)
self.dfs(root.right, level+1, res)

143
Q

Single Number III
# numbers # arrays
Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.

Example:

Input: [1,2,1,3,2,5]
Output: [3,5]
Note:

The order of the result is not important. So in the above example, [5, 3] is also correct.
Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?

A
// решение со словарем-счетчиком
from collections import Counter
class Solution:
    def singleNumber(self, nums: List[int]) -> List[int]:
        n = Counter(nums)
        res = []
        for k, v in n.items():
            if v == 1:
                res.append(k)
        return res
// решение с манипуляцией битов
 def singleNumber(self, nums):
    # выполняем исключающее или для всех чисел массива
    tmp = 0
    for num in nums:
        tmp ^= num
    # находим самый правый 1-бит
    i = 0
    while tmp &amp; 1 == 0:
        tmp >>= 1
        i += 1
    tmp = 1 << i
    # определяем два уникальных числа отдельно, проходясь по массиву
    first, second = 0, 0
    for num in nums:
        if num &amp; tmp:
            first ^= num
        else:
            second ^= num
    return [first, second]
144
Q

Find Minimum in Rotated Sorted Array II
# numbers # arrays
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).

Find the minimum element.

The array may contain duplicates.

Example 1:

Input: [1,3,5]
Output: 1
Example 2:

Input: [2,2,2,0,1]
Output: 0

A
// решение с бинарным поиском
def findMin(self, nums: List[int]) -> int:
// хадаем левые и правые границы
        lo, hi = 0, len(nums) - 1
// цикл, пока левый индекс меньше правого
        while lo < hi:
// задаем середину
            mid = lo + (hi -lo) // 2
// если число по индексу середины больше числа по правому индексу, значит, в этом отрезке точка разворота и нужно сдвинуть левую границу
            if nums[mid] > nums[hi]:
                lo = mid + 1
// иначе меняем правую границу на середину, если числа по их индексам не равны, иначе уменьшаем правую границу на 1
            else:
                hi = mid if nums[hi] != nums[mid] else hi - 1
// в конце возвращаем число по левому индексу
        return nums[lo]
// немного другое решение с бинарным поиском
def findMin(self, nums: List[int]) -> int:
        l, r = 0, len(nums) - 1
        while l < r:
// середину определяем битовым сдвигом
            m = (l + r) >> 1
            if nums[m] > nums[r]:
                l = m + 1
            elif nums[m] < nums[r]:
                r = m
            else:
                r = r - 1
        return nums[l]
145
Q
All Paths From Source to Target
# graphs
Given a directed, acyclic graph of N nodes.  Find all possible paths from node 0 to node N-1, and return them in any order.

The graph is given as follows: the nodes are 0, 1, …, graph.length - 1. graph[i] is a list of all nodes j for which the edge (i, j) exists.

Example:
Input: [[1,2], [3], [3], []] 
Output: [[0,1,3],[0,2,3]] 
Explanation: The graph looks like this:
0--->1
|       |
v      v
2--->3
There are two paths: 0 -> 1 -> 3 and 0 -> 2 -> 3.
A

// решение с обходом в глубину
def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]:
def dfs(formed):
// если последняя нода подмассива равна последней ноде графа (т.е. целевой), то добавляем подмассив в решение и останавливаемся
if formed[-1] == n - 1:
sol.append(formed)
return
// циклом проходимся по детям подмассива и рекурсивно делаем поиск для подмассива с детьми
for child in graph[formed[-1]]:
dfs(formed + [child])

    sol, n = [], len(graph)            
    dfs([0])
    return sol

// итеративное решение
def allPathsSourceTarget(self, graph: List[List[int]]) -> List[List[int]]:
N = len(graph) - 1
// заводим массив для путей с вершиной 0
paths = [[0]]
ans = []
// пока массив путей непустой, вытаскиваем из него последний подмассив
while paths:
path = paths.pop()
// проходимся по вершинам в последнем подмассиве подмассива
for n in graph[path[-1]]:
// если вершина конечная, добавляем путь и ее в ответ, иначе добавляем их в массив путей
if n == N:
ans.append(path + [n])
else:
paths.append(path + [n])
return ans

146
Q
Add Digits
# numbers # math
Given a non-negative integer num, repeatedly add all its digits until the result has only one digit.

Example:

Input: 38
Output: 2
Explanation: The process is like: 3 + 8 = 11, 1 + 1 = 2.
Since 2 has only one digit, return it.

A
//  используемые цифры только от 1 до 9, т.е. надо брать остаток от деления на 9, а в случае, когда в числе есть 9, надо отнимать 1 и прибавлять после
def addDigits(self, num: int) -> int:
        if num == 0:
            return 0
        else:
            return (num - 1) % 9 + 1
147
Q
Construct Binary Tree from Inorder and Postorder Traversal
# graphs # trees
Given inorder and postorder traversal of a tree, construct the binary tree.

Note:
You may assume that duplicates do not exist in the tree.

For example, given

inorder = [9,3,15,20,7]
postorder = [9,15,7,20,3]
Return the following binary tree:

    3
   / \
  9  20
    /  \
   15   7
A
// рекурсивное решение за квадратичное время
def buildTree(self, inorder, postorder):
        if not inorder or not postorder:
            return None
    root = TreeNode(postorder.pop()) //делаем корневую ноду из последнего элемента постордер-массива
    inorderIndex = inorder.index(root.val) # находим индекс корневой ноду в инордер-массиве

    root. right = self.buildTree(inorder[inorderIndex+1:], postorder) # рекурсивно строим правое поддерево из части инордер-массива справа от корневой ноды
    root. left = self.buildTree(inorder[:inorderIndex], postorder) # рекурсивно строим левое поддерево из части инордер-массива слева от корневой ноды

    return root
// решение за линейное время с использованием словаря
def buildTree(self, inorder, postorder):
        map_inorder = {}
// заполняем словарь индексами и значениями из массива инордер
        for i, val in enumerate(inorder): map_inorder[val] = i
// вспомогательная функция
        def recur(low, high):
// если нижний индекс больше верхнего, возвращаем нулл
            if low > high: return None
// делаем ноду из последнего значения постордер-массива
            x = TreeNode(postorder.pop())
// находим серединный индекс по ключу ноды
            mid = map_inorder[x.val]
// рекурсивно строим правое и левое поддерево
            x.right = recur(mid+1, high)
            x.left = recur(low, mid-1)
            return x
        return recur(0, len(inorder)-1)
148
Q
Task Scheduler
# arrays
You are given a char array representing tasks CPU need to do. It contains capital letters A to Z where each letter represents a different task. Tasks could be done without the original order of the array. Each task is done in one unit of time. For each unit of time, the CPU could complete either one task or just be idle.

However, there is a non-negative integer n that represents the cooldown period between two same tasks (the same letter in the array), that is that there must be at least n units of time between any two same tasks.

You need to return the least number of units of times that the CPU will take to finish all the given tasks.

Input: tasks = [“A”,”A”,”A”,”B”,”B”,”B”], n = 2
Output: 8
Explanation:
A -> B -> idle -> A -> B -> idle -> A -> B
There is at least 2 units of time between any two same tasks.

A
// составляем список частотности заданий, возвращаем максимальное значение, либо общее количество заданий, либо максимальное значение из частотных - 1, умноженное на n+1 плюс его частота в массиве
def leastInterval(self, tasks: List[str], n: int) -> int:
        v = list(collections.Counter(tasks).values())
        return max((max(v)-1) * (n+1) + v.count(max(v)), len(tasks))

// жадное решение: делаем массив с отсортированными по убыванию частотностями заданий: если массив частот не меньше n+1, то ставим в выполнение первые n+1 задач, обновляем отсортированные частотности и повторяем сначала, если массив частот меньше n+1, добавляем простои, пока все задания не выполнятся
def leastInterval(self, tasks: List[str], n: int) -> int:
res = 0
freqs = sorted(list(Counter(tasks).values()), reverse=True)
while len(freqs) >= n + 1:
for i in range(n + 1):
freqs[i] -= 1
res += n + 1
freqs = sorted([f for f in freqs if f > 0], reverse=True)
if freqs == []:
return res
f_max = freqs[0]
num_f_max = freqs.count(f_max)
res += num_f_max + (f_max - 1) * (n + 1)
return res

149
Q
Best Time to Buy and Sell Stock with Cooldown
# arrays # numbers
Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:

You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)
Example:

Input: [1,2,3,0,2]
Output: 3
Explanation: transactions = [buy, sell, cooldown, buy, sell]

A
// заводим 3 переменные: free - максимальный профит, когда можно покупать акции, have - максимальный профит, когда уже есть акции, cool - максимальный профит, когда ничего не делаешь
def maxProfit(self, prices: List[int]) -> int:
        free = 0
        have = cool = float('-inf')
// проходимся по массиву цен и определяем максимум для каждого из состояний: free - максимум из free/cooldown, have - максимум из have/free - цена, cool приравниваем have + цена
        for p in prices:
            free, have, cool = max(free, cool), max(have, free - p), have + p
// в конце возвращаем максимум из free/cooldown
        return max(free, cool)
150
Q
Word Break II
# strings
Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, add spaces in s to construct a sentence where each word is a valid dictionary word. Return all such possible sentences.

Note:
The same word in the dictionary may be reused multiple times in the segmentation.
You may assume the dictionary does not contain duplicate words.

Example 1:
Input:
s = "catsanddog"
wordDict = ["cat", "cats", "and", "sand", "dog"]
Output:
[
  "cats and dog",
  "cat sand dog"
]
Example 2:
Input:
s = "pineapplepenapple"
wordDict = ["apple", "pen", "applepen", "pine", "pineapple"]
Output:
[
  "pine apple pen apple",
  "pineapple pen apple",
  "pine applepen apple"
]
Explanation: Note that you are allowed to reuse a dictionary word.
Example 3:
Input:
s = "catsandog"
wordDict = ["cats", "dog", "sand", "and", "cat"]
Output:
[]
A
def wordBreak(self, s, wordDict):
// вспомогательная функция для обхода по индексам
        def dfs(i):
// если индекс равен длине строки, возвращаем массив с пустой строкой
            if i == len(s):
                return [""]
// если индекс есть в словаре, возвращаем его значение
            if i in dic:
                return dic[i]
// заводим массив-результат
            res = []
// проходимся по индексам от i до длины строки
            for j in range(i, len(s)):
// заводим начало строки от i до j+1
                head = s[i:j+1]
// если этот кусок есть в списке слов, то рекурсивно делаем обход по индексу j+1
                if head in wordSet:
                    tmp = dfs(j+1)
// проходимся по строкам рекурсивного обхода, добавляем к ним кусок head, добавляем в результат
                    for string in tmp:
                        string = head +" "+string
                        res.append(string.strip())
// в словарь по ключу-индексу добавляем результирующий массив, в конце возвращаем результат
            dic[i] = res
            return res
// заводим пустой словарь, делаем из списка слов сет, выполняем обход с 0        
        dic = {}
        wordSet = set(wordDict)
        return dfs(0)
151
Q
Climbing Stairs
# numbers
You are climbing a stair case. It takes n steps to reach to the top.

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

Example 1:

Input: 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps
Example 2:
Input: 3
Output: 3
Explanation: There are three ways to climb to the top.
1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step
A
def climbStairs(self, n: int) -> int:
        a, b = 1, 1
// проходимся циклом и увеличиваем количество шагов
        for i in range(n):
            a, b = b, a + b
        return a
// формула Фибоначчи
def climbStairs(self, n: int) -> int:
        return int(round(1/5**0.5 * (((1+5**0.5)/2.0)**(n+1) - ((1-5**0.5)/2.0)**(n+1))))
152
Q

Detect Capital
# strings
Given a word, you need to judge whether the usage of capitals in it is right or not.

We define the usage of capitals in a word to be right when one of the following cases holds:

All letters in this word are capitals, like “USA”.
All letters in this word are not capitals, like “leetcode”.
Only the first letter in this word is capital, like “Google”.
Otherwise, we define that this word doesn’t use capitals in a right way.

Example 1:
Input: “USA”
Output: True

Example 2:
Input: “FlaG”
Output: False

A
// простое решение с методами строки
def detectCapitalUse(self, word: str) -> bool:
        return word.isupper() or word.islower() or word.istitle()
// решение со вспомогательной функцией
def detectCapitalUse(self, word: str) -> bool:
        def is_capital(character):
            return ord('A') <= ord(character) <= ord('Z')
    all_capital = all([is_capital(char) for char in word])
    all_non_capital = all([not is_capital(char) for char in word])
    first_capital = is_capital(word[0]) and all([not is_capital(char) for char in word[1:]])

    return all_capital or all_non_capital or first_capital
// решение с регулярными выражениями
def detectCapitalUse(self, word: str) -> bool:
        return re.fullmatch(r"[A-Z]*|.[a-z]*", word)
153
Q

Design HashSet
# hashsets
Design a HashSet without using any built-in hash table libraries.

To be specific, your design should include these functions:

add(value): Insert a value into the HashSet.
contains(value) : Return whether the value exists in the HashSet or not.
remove(value): Remove a value in the HashSet. If the value does not exist in the HashSet, do nothing.

Example:

MyHashSet hashSet = new MyHashSet();
hashSet.add(1);         
hashSet.add(2);         
hashSet.contains(1);    // returns true
hashSet.contains(3);    // returns false (not found)
hashSet.add(2);          
hashSet.contains(2);    // returns true
hashSet.remove(2);          
hashSet.contains(2);    // returns false (already removed)
A

class MyHashSet:

// в конструкторе устанавливаем размер хеш-таблицы и делаем массив массивов (матрицу)
    def \_\_init\_\_(self):
        self.capacity= 1000
        self.nums = [[] for _ in range(self.capacity + 1)]
def add(self, key: int) -> None: // определяем ряд и колонку для ключа, используя divmod (возвращает пару частное-остаток от деления), если в массиве нет подмассива данного ряда, то делаем подмассив из None
    row,col = divmod(key,self.capacity)
    if not self.nums[row]:
        self.nums[row] = [None for _ in range(self.capacity)] // в ячейку по данным ряду и колонке записываем единицу
    self.nums[row][col] = 1

def remove(self, key: int) -> None: // определяем ряд и колонку для ключа, используя divmod (возвращает пару частное-остаток от деления), если в массиве есть подмассив ряда и ячейка с рядом и колонкой, то убираем из нее значение
    row,col = divmod(key,self.capacity)
    if self.nums[row] and self.nums[row][col]:
        self.nums[row][col] = None

def contains(self, key: int) -> bool: // определяем ряд и колонку для ключа, используя divmod (возвращает пару частное-остаток от деления), если в массиве нет подмассива ряда или нет значения в ячейке по ряду и колонке, то возвращаем False, иначе True
    row,col = divmod(key,self.capacity)
    if not self.nums[row]:
        return False
    if self.nums[row][col] == None:
        return False

    return True
154
Q
Valid Palindrome
# strings
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
Note: For the purpose of this problem, we define empty string as valid palindrome.

Example 1:
Input: “A man, a plan, a canal: Panama”
Output: true

Example 2:
Input: “race a car”
Output: false

A
def isPalindrome(self, s: str) -> bool:
        temp = [char.lower() for char in s if char.isalnum()]
        return temp == temp[::-1]
// решение с двумя указателями
def isPalindrome(self, s: str) -> bool:
        l, r = 0, len(s)-1
        while l < r:
// двигаем указатели, пока символы небуквенные
            while l < r and not s[l].isalnum():
                l += 1
            while l
155
Q
Power of Four
# numbers # math # binary
Given an integer (signed 32 bits), write a function to check whether it is a power of 4.

Example 1:
Input: 16
Output: true

Example 2:
Input: 5
Output: false

A
// проверяем, что число положительное, является степенью двойки, и число меньше на 1 делится без остатка на 3 
def isPowerOfFour(self, num: int) -> bool:
        if num <= 0:
            return False
        return num&amp;(num-1)==0 and (num-1)%3==0
156
Q
Add and Search Word - Data structure design
# strings
Design a data structure that supports the following two operations:
void addWord(word)
bool search(word)
search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means it can represent any one letter.

Example:

addWord("bad")
addWord("dad")
addWord("mad")
search("pad") -> false
search("bad") -> true
search(".ad") -> true
search("b..") -> true
Note:
You may assume that all words are consist of lowercase letters a-z.
A
class WordDictionary(object):
    def \_\_init\_\_(self):
// воспользуемся defaultdict для хранения слов
        self.len2words = collections.defaultdict(list) 
    def addWord(self, word):
// в словарь по ключу длины слова добавляем слово
        self.len2words[len(word)].append(word)
    def search(self, word):
// сохраняем список всех слов той же длины, что искомое слово
        words = self.len2words[len(word)]
// проходимся по списку пар индекс-буква слова
        for i, char in enumerate(word):
// составляем список слов с такой же буквой или точкой
            words = [w for w in words if char in ('.', w[i])]
// если слов не нашлось, значит, искомого слова нет
            if not words: return False
        return True
157
Q
Find All Duplicates in an Array
# arrays
Given an array of integers, 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.

Find all the elements that appear twice in this array.

Could you do it without extra space and in O(n) runtime?

Example:
Input:
[4,3,2,7,8,2,3,1]

Output:
[2,3]

A
def findDuplicates(self, nums: List[int]) -> List[int]:
        res = []
// проходимся циклом, всем повторяющимся числам меняем значение на отрицательное, записываем их в результат
        for x in nums:
            if nums[abs(x)-1] < 0:
                res.append(abs(x))
            else:
                nums[abs(x)-1] *= -1
        return res
158
Q
Vertical Order Traversal of a Binary Tree
# trees # graphs
Given a binary tree, return the vertical order traversal of its nodes values.

For each node at position (X, Y), its left and right children respectively will be at positions (X-1, Y-1) and (X+1, Y-1).

Running a vertical line from X = -infinity to X = +infinity, whenever the vertical line touches some nodes, we report the values of the nodes in order from top to bottom (decreasing Y coordinates).

If two nodes have the same position, then the value of the node that is reported first is the value that is smaller.

Return an list of non-empty reports in order of X coordinate. Every report will have a list of values of nodes.

Example 1:
Input: [3,9,20,null,null,15,7]
Output: [[9],[3,15],[20],[7]]
Explanation:
Without loss of generality, we can assume the root node is at position (0, 0):
Then, the node with value 9 occurs at position (-1, -1);
The nodes with values 3 and 15 occur at positions (0, 0) and (0, -2);
The node with value 20 occurs at position (1, -1);
The node with value 7 occurs at position (2, -2).

A

def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
self.arr = []
// вспомогательная функция для обхода в глубину
def dfs(node, x, y):
if node:
// если нода есть, добавляем кортеж с координатами и значением в массив, рекурсивно обходим левого ребенка и правого ребенка, изменив координаты
self.arr.append((x, y, node.val))
dfs(node.left, x - 1, y + 1)
dfs(node.right, x + 1, y + 1)
// обходим дерево с корня
dfs(root, 0, 0)
// возвращаем список нод, сгрупированных по координатам
return [list(map(lambda x: x[-1], g)) for k, g in itertools.groupby(sorted(self.arr), key = lambda x: x[0])]

159
Q

Path Sum III
# graphs # trees
You are given a binary tree in which each node contains an integer value.
Find the number of paths that sum to a given value.
The path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent nodes to child nodes).
The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000.

Example:

root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8

      10
     /  \
    5   -3
   / \    \
  3   2   11
 / \   \
3  -2   1

Return 3. The paths that sum to 8 are:

  1. 5 -> 3
  2. 5 -> 2 -> 1
  3. -3 -> 11
A
def pathSum(self, root, target):
        # заводим переменные для результата и путей
        self.result = 0
        cache = {0:1}
        # рекурсивно вызываем обход в глубину
        self.dfs(root, target, 0, cache)
        # возвращаем результат
        return self.result

// обход в глубину
def dfs(self, root, target, currPathSum, cache):
# условие для выхода
if root is None:
return
# вычисляем сумму текущего пути и старый путь (текущий путь - нужное значение)
currPathSum += root.val
oldPathSum = currPathSum - target
# обновляем результат и словарь путей
self.result += cache.get(oldPathSum, 0)
cache[currPathSum] = cache.get(currPathSum, 0) + 1

    # рекурсивно обходим левое и правое поддерево
    self.dfs(root.left, target, currPathSum, cache)
    self.dfs(root.right, target, currPathSum, cache)
    # когда переходим на другую ветку, уменьшаем сумму текущего пути
    cache[currPathSum] -= 1
160
Q
Rotting Oranges
# arrays # matrices
In a given grid, each cell can have one of three values:

the value 0 representing an empty cell;
the value 1 representing a fresh orange;
the value 2 representing a rotten orange.
Every minute, any fresh orange that is adjacent (4-directionally) to a rotten orange becomes rotten.

Return the minimum number of minutes that must elapse until no cell has a fresh orange. If this is impossible, return -1 instead.

Example 1:
Input: [[2,1,1],[1,1,0],[0,1,1]]
Output: 4

Example 2:
Input: [[2,1,1],[0,1,1],[1,0,1]]
Output: -1
Explanation: The orange in the bottom left corner (row 2, column 0) is never rotten, because rotting only happens 4-directionally.

A

def orangesRotting(self, grid: List[List[int]]) -> int:
// составляем массив с координатами плохих апельсинов
bfs = [(i, j) for i, row in enumerate(grid) for j, val in enumerate(row) if val == 2]
// заводим переменные для времени и размеров матрицы
t = 0
m = len(grid)
n = len(grid[0])
// циклом проходимся по массиву координат, пока он непустой
while bfs:
// создаем новый пустой массив
new = []
// проходимся по координатам и их соседям: если их координаты в пределах матрицы и значение по их индексам равно 1, меняем его на 2 и записываем координаты в новый массив
for i, j in bfs:
for x, y in ((i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)):
if 0 <= x < m and 0 <= y < n and grid[x][y] == 1:
grid[x][y] = 2
new.append((x, y))
// записываем в массив координат новый массив
bfs = new
// увеличиваем переменную времени, если массив непустой
t += bool(bfs)
// возвращаем время, если в массиве не осталось единиц (т.е. свежих апельсинов), иначе -1
return t if all(val != 1 for row in grid for val in row) else -1

161
Q
Excel Sheet Column Number
# strings # numbers
Given a column title as appear in an Excel sheet, return its corresponding column number.

For example:

    A -> 1
    B -> 2
    C -> 3
    ...
    Z -> 26
    AA -> 27
    AB -> 28 
    ...
Example 1:
Input: "A"
Output: 1

Example 2:
Input: “AB”
Output: 28

Example 3:
Input: “ZY”
Output: 701

A
def titleToNumber(self, s):
    res = 0
// циклом проходимся по буквам строки, умножаем результат на 26 и прибавляем разность числового представления буквы и А + 1
    for i in s:
        res = res*26 + ord(i)-ord('A')+1
    return res
162
Q
H-Index
# numbers # arrays
Given an array of citations (each citation is a non-negative integer) of a researcher, write a function to compute the researcher's h-index.

According to the definition of h-index on Wikipedia: “A scientist has index h if h of his/her N papers have at least h citations each, and the other N − h papers have no more than h citations each.”

Example:

Input: citations = [3,0,6,1,5]
Output: 3
Explanation: [3,0,6,1,5] means the researcher has 5 papers in total and each of them had
received 3, 0, 6, 1, 5 citations respectively.
Since the researcher has 3 papers with at least 3 citations each and the remaining
two with no more than 3 citations each, her h-index is 3.

A
def hIndex(self, citations: List[int]) -> int:
// сортируем список, проходимся циклом по индексам списка, если число по текущему индексу не меньше общего числа-индекс, то возвращаем разность число статей - индекс
        citations.sort()
        n = len(citations)
        for i in range(n):
            if citations[i] >= (n-i):
                return n-i
        return 0
// одной строкой: сортируем список по убыванию, делаем из него кортежи с индексам и подсчитываем, сколько чисел меньше индекса
def hIndex(self, citations: List[int]) -> int:
        return sum(i < j for i, j in enumerate(sorted(citations, reverse=True)))
163
Q
Pascal's Triangle II
# numbers # arrays # math
Given a non-negative index k where k ≤ 33, return the kth index row of the Pascal's triangle.

Note that the row index starts from 0.

Example:

Input: 3
Output: [1,3,3,1]

A
def getRow(self, rowIndex: int) -> List[int]:
// делаем массив единиц размер ряд+1
        rt=[1]*(rowIndex+1)
// проходимся циклом от двух до ряд+1 и от 1 до i
        for i in range(2, rowIndex+1):
            for j in range(1, i):
// к числу по индексу i-jприбавляем число по индексу i-j-1
                rt[i-j]+=rt[i-j-1]
        return rt

// циклом складываем предыдущие ряды (справа и слева добавляем 0)
def getRow(self, rowIndex: int) -> List[int]:
row = [1]
for _ in range(rowIndex):
row = [x + y for x, y in zip([0]+row, row+[0])]
return row

164
Q
Iterator for Combination
# arrays # strings
Design an Iterator class, which has:

A constructor that takes a string characters of sorted distinct lowercase English letters and a number combinationLength as arguments.
A function next() that returns the next combination of length combinationLength in lexicographical order.
A function hasNext() that returns True if and only if there exists a next combination.

Example:

CombinationIterator iterator = new CombinationIterator(“abc”, 2); // creates the iterator.

iterator. next(); // returns “ab”
iterator. hasNext(); // returns true
iterator. next(); // returns “ac”
iterator. hasNext(); // returns true
iterator. next(); // returns “bc”
iterator. hasNext(); // returns false

A
// решение с itertools и генератором
from itertools import combinations

class CombinationIterator:

def \_\_init\_\_(self, characters: str, combinationLength: int):

    self. it = combinations(characters, combinationLength)
    self. buffer = ''.join(next(self.it)) if characters else None
    def next(self) -> str:
        res = self.buffer
        try:
            self.buffer = ''.join(next(self.it))
        except:
            self.buffer = None
        return res
    def hasNext(self) -> bool:
        return self.buffer is not None
// решение со стеком индексов
class CombinationIterator:
def \_\_init\_\_(self, characters: str, combinationLength: int):

    self. comb_len = combinationLength
    self. characters = characters
    self. stack = [i for i in range(combinationLength)]
    self. n = len(characters)

def next(self) -> str:
    comb = ''
    for ind in self.stack:
        comb += self.characters[ind]

    while self.stack:
        self.stack[-1] += 1
        ind_from_end = self.comb_len - len(self.stack)
        if self.stack[-1] > self.n - ind_from_end - 1:
            self.stack.pop()
        else: break

    if self.stack:
        while len(self.stack) != self.comb_len:
            self.stack.append(self.stack[-1]+1)
    return comb
    def hasNext(self) -> bool:
        return self.stack and self.stack[-1] < self.n
165
Q
Longest Palindrome
# strings
Given a string which consists of lowercase or uppercase letters, find the length of the longest palindromes that can be built with those letters.

This is case sensitive, for example “Aa” is not considered a palindrome here.

Note:
Assume the length of given string will not exceed 1,010.

Example:

Input:
“abccccdd”

Output:
7

Explanation:
One longest palindrome that can be built is “dccaccd”, whose length is 7.

A

def longestPalindrome(self, s: str) -> int:
freq = collections.Counter(s).values()
ans = 0
// делаем словарь-счетчик со значениями, проходимся по нему циклом, к ответу прибавляем значение разделенное на 2 и умноженное на 2
for v in freq:
ans += v // 2 *2
// если ответ четный, а значение нечетно, прибавляем к ответу единицу
if ans % 2 == 0 and v % 2 == 1:
ans += 1
return ans

def longestPalindrome(self, s: str) -> int:
// считаем, сколько нечетных букв
        odds = sum(v &amp; 1 for v in collections.Counter(s).values())
// из общего количества вычитаем нечетные буквы и прибавляем одну
        return len(s) - odds + bool(odds)
// подсчитываем количество нечетных букв
def longestPalindrome(self, s: str) -> int:
        odds = sum([freq % 2 for freq in collections.Counter(s).values()])
// если нечетных букв не больше 1, то возвращаем всю длину строки, иначе из длины вычитаем нечетные буквы и прибавляем 1
        return len(s) if odds <=1 else len(s) - odds + 1
166
Q
Non-overlapping Intervals
# arrays # numbers
Given a collection of intervals, find the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping.

Example 1:

Input: [[1,2],[2,3],[3,4],[1,3]]
Output: 1
Explanation: [1,3] can be removed and the rest of intervals are non-overlapping.
Example 2:

Input: [[1,2],[1,2],[1,2]]
Output: 2
Explanation: You need to remove two [1,2] to make the rest of intervals non-overlapping.
Example 3:

Input: [[1,2],[2,3]]
Output: 0
Explanation: You don’t need to remove any of the intervals since they’re already non-overlapping.

A
def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int:
        if not intervals: return 0
// сортируем массив интервалов по начальным точкам
        intervals.sort(key=lambda x: x[0])  # sort on start time
// сохраняем текущую конечную точку первого интервала и заводим счетчик
        currEnd, cnt = intervals[0][1], 0
// проходимся по интервалам, начиная со второго
        for x in intervals[1:]:
// если стартовая точка меньше текущей конечной точки, то мы нашли пересечение: увеличиваем счетчик и переопределяем текущую конечную точку (убираем интервал с более длинным концом), иначе сдвигаем текущую конечную точку
            if x[0] < currEnd:  # find overlapping interval
                cnt += 1
                currEnd = min(currEnd, x[1])  # erase the one with larger end time
            else:
                currEnd = x[1]   # update end time
        return cnt
167
Q

Best Time to Buy and Sell Stock III
# numbers # arrays
Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete at most two transactions.

Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).

Example 1:

Input: [3,3,5,0,0,3,1,4]
Output: 6
Explanation: Buy on day 4 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.
Then buy on day 7 (price = 1) and sell on day 8 (price = 4), profit = 4-1 = 3.
Example 2:

Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are
engaging multiple transactions at the same time. You must sell before buying again.
Example 3:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

A
def maxProfit(self, prices: List[int]) -> int:
        if not prices:
            return 0
    # проходимся по массиву вперед, определяем максимальный профит с покупки, записываем в новый массив
    profits = []
    max_profit = 0
    current_min = prices[0]
    for price in prices:
        current_min = min(current_min, price)
        max_profit = max(max_profit, price - current_min)
        profits.append(max_profit)
        # проходимся по массиву назад, определяем максимальный профит с продажи
        total_max = 0    
        max_profit = 0
        current_max = prices[-1]
        for i in range(len(prices) - 1, -1, -1):
            current_max = max(current_max, prices[i])
            max_profit = max(max_profit, current_max - prices[i])
            total_max = max(total_max, max_profit + profits[i])
    return total_max
168
Q
Distribute Candies to People
# arrays # numbers
We distribute some number of candies, to a row of n = num_people people in the following way:

We then give 1 candy to the first person, 2 candies to the second person, and so on until we give n candies to the last person.

Then, we go back to the start of the row, giving n + 1 candies to the first person, n + 2 candies to the second person, and so on until we give 2 * n candies to the last person.

This process repeats (with us giving one more candy each time, and moving to the start of the row after we reach the end) until we run out of candies. The last person will receive all of our remaining candies (not necessarily one more than the previous gift).

Return an array (of length num_people and sum candies) that represents the final distribution of candies.

Example 1:

Input: candies = 7, num_people = 4
Output: [1,2,3,1]
Explanation:
On the first turn, ans[0] += 1, and the array is [1,0,0,0].
On the second turn, ans[1] += 2, and the array is [1,2,0,0].
On the third turn, ans[2] += 3, and the array is [1,2,3,0].
On the fourth turn, ans[3] += 1 (because there is only one candy left), and the final array is [1,2,3,1].
Example 2:

Input: candies = 10, num_people = 3
Output: [5,2,3]
Explanation:
On the first turn, ans[0] += 1, and the array is [1,0,0].
On the second turn, ans[1] += 2, and the array is [1,2,0].
On the third turn, ans[2] += 3, and the array is [1,2,3].
On the fourth turn, ans[0] += 4, and the final array is [5,2,3].

A

def distributeCandies(self, candies: int, num_people: int) -> List[int]:
// составляем результирующий массив по числу людей, заводим счетчик
res = [0] * num_people
i = 0
// цикл, пока не закончились конфеты
while candies > 0:
// по индексу остаток от деления счетчика на число людей прибавляем минимум из общего числа конфет либо счетчик + 1, конфеты уменьшаем на счетчик + 1, сам счетчик увеличиваем
res[i % num_people] += min(candies, i + 1)
candies -= i + 1
i += 1
return res

169
Q
Goat Latin
# strings
A sentence S is given, composed of words separated by spaces. Each word consists of lowercase and uppercase letters only.

We would like to convert the sentence to “Goat Latin” (a made-up language similar to Pig Latin.)

The rules of Goat Latin are as follows:

If a word begins with a vowel (a, e, i, o, or u), append “ma” to the end of the word.
For example, the word ‘apple’ becomes ‘applema’.

If a word begins with a consonant (i.e. not a vowel), remove the first letter and append it to the end, then add “ma”.
For example, the word “goat” becomes “oatgma”.

Add one letter ‘a’ to the end of each word per its word index in the sentence, starting with 1.
For example, the first word gets “a” added to the end, the second word gets “aa” added to the end and so on.
Return the final sentence representing the conversion from S to Goat Latin.

Example 1:

Input: “I speak Goat Latin”
Output: “Imaa peaksmaaa oatGmaaaa atinLmaaaaa”
Example 2:

Input: “The quick brown fox jumped over the lazy dog”
Output: “heTmaa uickqmaaa rownbmaaaa oxfmaaaaa umpedjmaaaaaa overmaaaaaaa hetmaaaaaaaa azylmaaaaaaaaa ogdmaaaaaaaaaa”

Notes:

S contains only uppercase, lowercase and spaces. Exactly one space between each word.
1 <= S.length <= 150.

A

def toGoatLatin(self, S: str) -> str:
words = S.split()
for i in range(len(words)):
if words[i][0] in “AEIOUaeiou”:
words[i] = words[i] + “ma” + “a”(i+1)
else:
words[i] = words[i][1:] + words[i][0] + “ma” + “a”
(i+1)

    return " ".join(words)
170
Q

Reorder List
# linked lists
Given a singly linked list L: L0→L1→…→Ln-1→Ln,
reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…

You may not modify the values in the list’s nodes, only nodes itself may be changed.

Example 1:

Given 1->2->3->4, reorder it to 1->4->2->3.
Example 2:

Given 1->2->3->4->5, reorder it to 1->5->2->4->3.

A
# Definition for singly-linked list.
# class ListNode:
#     def \_\_init\_\_(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reorderList(self, head: ListNode) -> None:
        # сначала находим серединную ноду с помощью быстрого и медленного указателей
        if not head: return []
        slow, fast = head, head
        while fast.next and fast.next.next:
            slow = slow.next
            fast = fast.next.next
        # вторую половину списка разворачиваем
        prev, curr = None, slow.next
        while curr:
            nextt = curr.next
            curr.next = prev
            prev = curr
            curr = nextt    
        slow.next = None
        # объединяем половины списков, чередуя указатели
        head1, head2 = head, prev
        while head2:
            nextt = head1.next
            head1.next = head2
            head1 = head2
            head2 = nextt
171
Q
Sort Array By Parity
# arrays # numbers
Given an array A of non-negative integers, return an array consisting of all the even elements of A, followed by all the odd elements of A.

You may return any answer array that satisfies this condition.

Example 1:

Input: [3,1,2,4]
Output: [2,4,3,1]
The outputs [4,2,3,1], [2,4,1,3], and [4,2,1,3] would also be accepted.

Note:

1 <= A.length <= 5000
0 <= A[i] <= 5000

A
// решение с двумя указателями
def sortArrayByParity(self, A: List[int]) -> List[int]:
// делаем два указателя, один в начале списка, другой в конце
        start = 0
        end = len(A) - 1
// цикл, пока указатели не встретились
        while start < end:
// берем два числа по индексам указателей, если левое число нечетное и правое четное, меняем их местами, если только левое нечетное, второй указатель уменьшаем, если только правое четное, увеличиваем первый указатель, иначе сдвигаем оба указателя
            m = A[start]
            n = A[end]
            if m % 2 == 1 and n % 2 == 0:
                A[start], A[end] = n, m
            elif m % 2 == 1:
                end -= 1
            elif n % 2 == 0:
                start += 1
            else:
                start += 1
                end -= 1
        return A
172
Q

Sum of Left Leaves
# trees # graphs
Find the sum of all left leaves in a given binary tree.

Example:

    3
   / \
  9  20
    /  \
   15   7

There are two left leaves in the binary tree, with values 9 and 15 respectively. Return 24.

A

class Solution:
def sumOfLeftLeaves(self, root: TreeNode) -> int:
res = 0
if root:
// если левое поддерево корня - лист, добавляем его значение в результат
if self.isLeaf(root.left):
res += root.left.val
// иначе рекурсивно обходим левое поддерево
else:
res += self.sumOfLeftLeaves(root.left)
// потом рекурсивно обходим правое поддерево
res += self.sumOfLeftLeaves(root.right)
return res

// вспомогательная функция проверки, что нода - лист
def isLeaf(self, node: TreeNode) -> bool:
if not node:
return False
if not node.left and not node.right:
return True
return False

173
Q
Stream of Characters
# strings
mplement the StreamChecker class as follows:

StreamChecker(words): Constructor, init the data structure with the given words.
query(letter): returns true if and only if for some k >= 1, the last k characters queried (in order from oldest to newest, including this letter just queried) spell one of the words in the given list.

Example:

StreamChecker streamChecker = new StreamChecker(["cd","f","kl"]); // init the dictionary.
streamChecker.query('a');          // return false
streamChecker.query('b');          // return false
streamChecker.query('c');          // return false
streamChecker.query('d');          // return true, because 'cd' is in the wordlist
streamChecker.query('e');          // return false
streamChecker.query('f');          // return true, because 'f' is in the wordlist
streamChecker.query('g');          // return false
streamChecker.query('h');          // return false
streamChecker.query('i');          // return false
streamChecker.query('j');          // return false
streamChecker.query('k');          // return false
streamChecker.query('l');          // return true, because 'kl' is in the wordlist
A
// общий принцип - строим дерево слов (в каждой ноде словарь с нодами-детьми и флаг, является ли листом), из символов строки строим ноды (справа налево)
class TreeNode:
    def \_\_init\_\_(self):
        self.children = {}
        self.isLeaf = False
class WordTree:
    def \_\_init\_\_(self):
        self.root = TreeNode()
    def insert(self, word):
        node = self.root
        for char in word[::-1]:
            if char not in node.children:
                node.children[char] = TreeNode()
            node = node.children[char]
        node.isLeaf = True

class StreamChecker:

    def \_\_init\_\_(self, words: List[str]):
        self.queries = []
        self.tree = WordTree()
        for w in words:
            self.tree.insert(w)

// заводим массив запросов, циклом проходимся по его индексам справа налево: если нода - лист, сразу возвращаем истину, если символа по текущему индексу нет в словаре детей ноды, возвращаем ложь, переходим на следующую ноду по текущему символу из списка запросов, уменьшаем индекс, в конце проверяем, является ли нода листом
def query(self, letter: str) -> bool:
self.queries.append(letter)
node = self.tree.root
i = len(self.queries) - 1
while i >= 0:
if node.isLeaf:
return True
if self.queries[i] not in node.children:
return False
node = node.children[self.queries[i]]
i -= 1
return node.isLeaf

174
Q
Minimum Cost For Tickets
# numbers # arrays
In a country popular for train travel, you have planned some train travelling one year in advance.  The days of the year that you will travel is given as an array days.  Each day is an integer from 1 to 365.

Train tickets are sold in 3 different ways:

a 1-day pass is sold for costs[0] dollars;
a 7-day pass is sold for costs[1] dollars;
a 30-day pass is sold for costs[2] dollars.
The passes allow that many days of consecutive travel. For example, if we get a 7-day pass on day 2, then we can travel for 7 days: day 2, 3, 4, 5, 6, 7, and 8.

Return the minimum number of dollars you need to travel every day in the given list of days.

Example 1:

Input: days = [1,4,6,7,8,20], costs = [2,7,15]
Output: 11
Explanation:
For example, here is one way to buy passes that lets you travel your travel plan:
On day 1, you bought a 1-day pass for costs[0] = $2, which covered day 1.
On day 3, you bought a 7-day pass for costs[1] = $7, which covered days 3, 4, …, 9.
On day 20, you bought a 1-day pass for costs[0] = $2, which covered day 20.
In total you spent $11 and covered all the days of your travel.
Example 2:

Input: days = [1,2,3,4,5,6,7,8,9,10,30,31], costs = [2,7,15]
Output: 17
Explanation:
For example, here is one way to buy passes that lets you travel your travel plan:
On day 1, you bought a 30-day pass for costs[2] = $15 which covered days 1, 2, …, 30.
On day 31, you bought a 1-day pass for costs[0] = $2 which covered day 31.
In total you spent $17 and covered all the days of your travel.

A

def mincostTickets(self, days: ‘List[int]’, costs: ‘List[int]’) -> ‘int’:
// делаем dp-массив из 365 дней, заводим переменную-указатель
dp = [0]*366
j = 0
// проходимся по числам от первого дня до 366 дня
for i in range(days[0], 366):
// если индекс равен дню по индексу указателя, в массив записываем стоимость 1 дня + пред.день
if i == days[j]:
dp[i] = dp[i-1]+costs[0]
// если индекс не меньше 7, в массив записываем минимум из текущей ячейки/элемент - 7 позиций + стоимость недели, иначе записываем минимум из текущей ячейки/стоимость недели
if i >= 7:
dp[i] = min(dp[i-7]+costs[1], dp[i])
else:
dp[i] = min(dp[i], costs[1])
// если индекс не меньше 30, в массив записываем минимум из текущей ячейки/элемент - 30 позиций + стоимость месяца, иначе записываем минимум из текущей ячейки/стоимость месяца
if i >= 30:
dp[i] = min(dp[i-30]+costs[2], dp[i])
else:
dp[i] = min(dp[i], costs[2])
// увеличиваем указатель, если он равен количеству дней поездок, то возвращаем элемент по текущему индексу
j += 1
if j == len(days):
return dp[i]
// иначе записываем в элемент по текущему индексу значение предыдущего, если индекс больше 0
else:
if i > 0:
dp[i] = dp[i-1]

175
Q
Find Right Interval
# arrays # numbers
Given a set of intervals, for each of the interval i, check if there exists an interval j whose start point is bigger than or equal to the end point of the interval i, which can be called that j is on the "right" of i.

For any interval i, you need to store the minimum interval j’s index, which means that the interval j has the minimum start point to build the “right” relationship for interval i. If the interval j doesn’t exist, store -1 for the interval i. Finally, you need output the stored value of each interval as an array.

Note:

You may assume the interval’s end point is always bigger than its start point.
You may assume none of these intervals have the same start point.

Example 1:

Input: [ [1,2] ]

Output: [-1]

Explanation: There is only one interval in the collection, so it outputs -1.

Example 2:

Input: [ [3,4], [2,3], [1,2] ]

Output: [-1, 0, 1]

Explanation: There is no satisfied “right” interval for [3,4].
For [2,3], the interval [3,4] has minimum-“right” start point;
For [1,2], the interval [2,3] has minimum-“right” start point.

Example 3:

Input: [ [1,4], [2,3], [3,4] ]

Output: [-1, 2, -1]

Explanation: There is no satisfied “right” interval for [1,4] and [3,4].
For [2,3], the interval [3,4] has minimum-“right” start point.

A
def findRightInterval(self, intervals: List[List[int]]) -> List[int]:
// сортируем отрезки вместе с их индексами по начальным точкам
        intervals_new = sorted([start,end,idx] for idx,[start,end] in enumerate(intervals))
// заводим отдельный массив начальных точек
        startpoints = [s for s,_,_ in intervals_new]
// заводим результирующий массив с -1 вместо индексов
        res = [-1]*len(intervals)
// проходимся по конечным точкам отсортированного массива
        for _,end,idx in intervals_new:
// для конечной точки определяем индекс в массиве начальных точек: если индекс меньше количества отрезков, то в результирующий массив записываем индекс из отсортированного массива
            i = bisect.bisect_left(startpoints,end)
            if i < len(intervals):
                res[idx] = intervals_new[i][2]
        return res
176
Q
Implement Rand10() Using Rand7()
# numbers # random
Given a function rand7 which generates a uniform random integer in the range 1 to 7, write a function rand10 which generates a uniform random integer in the range 1 to 10.

Do NOT use system’s Math.random().

Example 1:

Input: 1
Output: [7]
Example 2:

Input: 2
Output: [8,4]
Example 3:

Input: 3
Output: [8,1,10]

Note:

rand7 is predefined.
Each testcase has one argument: n, the number of times that rand10 is called.

A

// метод выборки с отклонением (rejection sampling): сначала с помощью данной функции rand7 генерируем случайное число от 0 до 48. Получится несколько групп чисел [0,9]; [10;19]; [20;29]; [30;39]; [40;48] - во всех кроме последней по 10 чисел (в последней 9). Если сгенерированное число меньше 40, берем его остаток от деления на 10 + 1, иначе заново вызываем функцию

def rand10(self):
        c = (rand7() - 1)*7 + rand7() - 1
        return self.rand10() if c >= 40 else (c % 10) + 1
177
Q
Pancake Sorting
# numbers # arrays # sorting
Given an array of integers A, We need to sort the array performing a series of pancake flips.

In one pancake flip we do the following steps:

Choose an integer k where 0 <= k < A.length.
Reverse the sub-array A[0…k].
For example, if A = [3,2,1,4] and we performed a pancake flip choosing k = 2, we reverse the sub-array [3,2,1], so A = [1,2,3,4] after the pancake flip at k = 2.

Return an array of the k-values of the pancake flips that should be performed in order to sort A. Any valid answer that sorts the array within 10 * A.length flips will be judged as correct.

Example 1:

Input: A = [3,2,4,1]
Output: [4,2,4,3]
Explanation:
We perform 4 pancake flips, with k values 4, 2, 4, and 3.
Starting state: A = [3, 2, 4, 1]
After 1st flip (k = 4): A = [1, 4, 2, 3]
After 2nd flip (k = 2): A = [4, 1, 2, 3]
After 3rd flip (k = 4): A = [3, 2, 1, 4]
After 4th flip (k = 3): A = [1, 2, 3, 4], which is sorted.
Notice that we return an array of the chosen k values of the pancake flips.
Example 2:

Input: A = [1,2,3]
Output: []
Explanation: The input is already sorted, so there is no need to flip anything.
Note that other answers, such as [3, 3], would also be accepted.

A
// общий принцип: находим самый большой элемент, переворачиваем часть массива, чтобы он оказался в начале, потом переворачиваем весь массив, чтобы он оказался в конце. Повторяем эти операции, пока не будет отсортирован весь массив
def pancakeSort(self, A: List[int]) -> List[int]:
	n = len(A)
	res = []
// проходимся циклом по индексам массива
	for i in range(n):
// определяем максимальный элемент в подмассиве
		cur_max = max(A[0:n-i])
// определяем индекс максимального элемента
		j = 0
		while A[j] != cur_max:
			j += 1
		# переворачиваем подмассив до индекса + 1
		A[:j+1] = reversed(A[:j+1])
// в результат записываем индекс + 1
		res.append(j+1)
		# переворачиваем весь массив
		A[:n-i] = reversed(A[:n-i])
// в результат записываем последний индекс подмассива
		res.append(n-i)
	return res
178
Q
Largest Component Size by Common Factor
# numbers # graphs
Given a non-empty array of unique positive integers A, consider the following graph:

There are A.length nodes, labelled A[0] to A[A.length - 1];
There is an edge between A[i] and A[j] if and only if A[i] and A[j] share a common factor greater than 1.
Return the size of the largest connected component in the graph.

Example 1:
Input: [4,6,15,35]
Output: 4

A

// 1 - находим все простые числа меньше квадрата самого большого числа
2 - для каждого числа из массива находим множители
3 - используем метод union-find (непересекающиеся множества) для объединения простых чисел-множителей для каждого числа из массива
4 - определяем количество чисел, связанных простыми множителями

class Solution:
def largestComponentSize(self, A: List[int]) -> int:
// находим простые числа от 2 до квадрата самого большого числа из массива
primes = []
for x in range(2, int(max(A)**0.5)+1):
for y in primes:
if x % y == 0:
break
else:
primes.append(x)

        factors = collections.defaultdict(list)         # заводим словарь со списками простых множителей каждого числа 
        for a in A:
            x = a
            for p in primes:
                if p*p > x:
                    break
                if x % p == 0:
                    factors[a].append(p)
                    while x % p == 0:
                        x //= p
            if x > 1:                                   # если нашлось новое простое число, добавляем его в словарь и в список простых чисел
                factors[a].append(x)
                primes.append(x)
// избавляемся от дубликатов в простых числах, сохраняем количество простых чисел                
        primes = list(set(primes))
        n = len(primes)
        p2i = {p: i for i,p in enumerate(primes)}       # делаем словарь индексов и простых чисел
    parent = [i for i in range(n)]                  # делаем массив индексов простых чисел (корневые ноды в графе)
// функция поиска для union-find        
        def find(i):
            if i != parent[i]:
                parent[i] = find(parent[i])
            return parent[i]
// функция объединения для union-find
        def union(i,j):
            pi, pj = find(i), find(j)
            if pi != pj:
                parent[pi] = pj
    for a in A:
        if factors[a]:
            p0 = factors[a][0]
            for p in factors[a][1:]:                # связываем два простых числа, если они оба - множители числа из массива
                union(p2i[p0], p2i[p])
        count = collections.Counter(find(p2i[factors[a][0]]) for a in A if factors[a])      # подсчитываем, сколько чисел связано с индексом каждого простого числа
        return max(count.values()) // в итоге возвращаем самое большое число связанных чисел
179
Q
Delete Node in a BST
# trees # graphs
Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST.

Basically, the deletion can be divided into two stages:

Search for a node to remove.
If the node is found, delete the node.
Note: Time complexity should be O(height of tree).

Example:

root = [5,3,6,2,4,null,7]
key = 3
    5
   / \
  3   6
 / \   \
2   4   7

Given key to delete is 3. So we find the node with value 3 and delete it.

One valid answer is [5,4,6,2,null,null,7], shown in the following BST.

    5
   / \
  4   6
 /     \
2       7

Another valid answer is [5,2,6,null,4,null,7].

    5
   / \
  2   6
   \   \
    4   7
A

def deleteNode(self, root: TreeNode, key: int) -> TreeNode:
if not root:
return None
// если нода содержит нужное значение, возвращаем левое или правое поддерево (если есть только одно из них)
if root.val == key:
if not root.right:
return root.left
if not root.left:
return root.right
// если есть оба ребенка, ищем кандидата на место удаляемой ноды: сначала идем вправо, а потом в самую левую ноду и записываем ее значение; рекурсивно вызываем функцию удаления ноды для правого поддерева
if root.right and root.left:
temp = root.right
while temp.left:
temp = temp.left
root.val = temp.val
root.right = self.deleteNode(root.right, root.val)
// если значение ноды больше удаляемого, рекурсивно вызываем функцию для левого поддерева, иначе вызываем для правого
elif root.val > key:
root.left = self.deleteNode(root.left, key)
else:
root.right = self.deleteNode(root.right, key)
return root

180
Q
Largest Time for Given Digits
# numbers # time
Given an array of 4 digits, return the largest 24 hour time that can be made.

The smallest 24 hour time is 00:00, and the largest is 23:59. Starting from 00:00, a time is larger if more time has elapsed since midnight.

Return the answer as a string of length 5. If no valid time can be made, return an empty string.

Example 1:

Input: [1,2,3,4]
Output: “23:41”
Example 2:

Input: [5,5,5,5]
Output: “”

A
// перебираем перестановки цифр массива, делаем часы и минуты, если они правильные, сохраняем в максимальное время, в конце возвращаем его строкой
from itertools import permutations

class Solution:
def largestTimeFromDigits(self, A: List[int]) -> str:
max_t = None
for i in list(permutations(A, 4)):
h = i[0]10+i[1]
m = i[2]
10+i[3]
if h >= 24 or m > 59:
continue
t = h*60+m
if max_t is None or t > max_t:
max_t = t
if max_t is None:
return “”
else:
return ‘:{:02d}’.format(max_t//60,max_t%60)

181
Q
Contains Duplicate III
# numbers # arrays
Given an array of integers, find out whether there are two distinct indices i and j in the array such that the absolute difference between nums[i] and nums[j] is at most t and the absolute difference between i and j is at most k.

Example 1:

Input: nums = [1,2,3,1], k = 3, t = 0
Output: true
Example 2:

Input: nums = [1,0,1,1], k = 1, t = 2
Output: true
Example 3:

Input: nums = [1,5,9,1,5,9], k = 2, t = 3
Output: false

A

// используем принципы скользящего окна и блочной сортировки (bucket sorting): разбиваем массив на блоки объемом t+1, если нашлось два числа с разницей <=t, то значит они либо в одном блоке, либо в двух соседних.

def containsNearbyAlmostDuplicate(self, nums: List[int], k: int, t: int) -> bool:
        if t < 0: return False
        n = len(nums)
        d = {}
        w = t + 1
        for i in range(n):
            m = nums[i] // w
            if m in d:
                return True
            if m - 1 in d and abs(nums[i] - d[m - 1]) < w:
                return True
            if m + 1 in d and abs(nums[i] - d[m + 1]) < w:
                return True
            d[m] = nums[i]
            if i >= k: del d[nums[i - k] // w]
        return False
182
Q
Repeated Substring Pattern
# strings
Given a non-empty string check if it can be constructed by taking a substring of it and appending multiple copies of the substring together. You may assume the given string consists of lowercase English letters only and its length will not exceed 10000.

Example 1:

Input: “abab”
Output: True
Explanation: It’s the substring “ab” twice.
Example 2:

Input: “aba”
Output: False
Example 3:

Input: “abcabcabcabc”
Output: True
Explanation: It’s the substring “abc” four times. (And the substring “abcabc” twice.)

A
// делаем копию строки: без первого символа+без последнего символа, проверяем, что оригинальная строка туда входит
def repeatedSubstringPattern(self, s: str) -> bool:
        return s in s[1:]+s[:-1]
// проходимся по индексам от 1 до середины длины строки: если длина строки нацело делится на индекс и подстрока до индекса, умноженная на частное длины и индекса, равна всей строке, возвращаем true
def repeatedSubstringPattern(self, s: str) -> bool:
        N = len(s)
        for i in range(1, N//2+1):
            if N % i == 0 and s[:i]*(N//i) == s:
                return True
        return False

// решение с определением самого длинного префикса-суффикса (из алгоритма Кнута-Морриса-Пратта)
// вспомогательная функция с аргументами строки, ее длины и массива длин префиксов-суффиксов
def computeLPS(self, string, n, lps):
length = 0 // длина предыдущего длинного префикса-суффикса
lps[0] = 0 // первый элемент массива длин префиксов-суффиксов всегда равен 0
i = 1
// цикл, пока индекс меньше длины строки
while i < n:
// если символы строки по текущему индексу и по индексу длины префикса-суффикса совпадают, увеличиваем длину префикса-суффикса, записываем это значение в массив, увеличиваем индекс
if string[i] == string[length]:
length += 1
lps[i] = length
i += 1
else:
// если длина префикса-суффикса не равна 0, то в ее значение записываем последнее значение из массива, иначе в массив по индексу i записываем 0, индекс увеличиваем
if length != 0:
length = lps[length - 1]
else:
lps[i] = 0
i += 1
def repeatedSubstringPattern(self, s: str) -> bool:
// делаем массив длин, используем функцию для префиксов-суффиксов, записываем последний элемент из массива
n = len(s)
lps = [0] * n
self.computeLPS(s, n, lps)
length = lps[-1]
// если последняя длина из массива префиксов-суффиксов не нулевая и разность всей длины строки и этой длины делит нацело всю длину, возвращаем true
if length > 0 and n % (n-length) == 0:
return True
else:
return False

183
Q
Partition Labels
# strings
A string S of lowercase English letters is given. We want to partition this string into as many parts as possible so that each letter appears in at most one part, and return a list of integers representing the size of these parts.

Example 1:

Input: S = “ababcbacadefegdehijhklij”
Output: [9,7,8]
Explanation:
The partition is “ababcbaca”, “defegde”, “hijhklij”.
This is a partition so that each letter appears in at most one part.
A partition like “ababcbacadefegde”, “hijhklij” is incorrect, because it splits S into less parts.

A
def partitionLabels(self, S: str) -> List[int]:
        res = []
        d = {}
// сначала составляем словарь из символов и их самых правых индексов
        for i, char in enumerate(S):
            d[char] = i
        currLen = 0
        hi = 0
// снова проходимся по символам и индексам
        for i, char in enumerate(S):
// определяем правый индекс среза (бОльший из текущего или по словарю индексов)
            hi = max(hi, d[char])
// если текущий индекс равен правому, записываем длину среза в результат (вычисляется как разность текущего индекса и текущей длины + 1), текущую длину переопределяем как i+1
            if i == hi:
                res.append(i - currLen + 1)
                currLen = i+1
// в конце возвращаем массив длин
        return res
184
Q

All Elements in Two Binary Search Trees
# trees # graphs
Given two binary search trees root1 and root2.

Return a list containing all the integers from both trees sorted in ascending order.

Example 1:

Input: root1 = [2,1,4], root2 = [1,0,3]
Output: [0,1,1,2,3,4]
Example 2:

Input: root1 = [0,-10,10], root2 = [5,1,7,0,2]
Output: [-10,0,0,1,2,5,7,10]

A

// рекурсивное решение: обходим оба дерева в порядке inorder, сохраняем значения нод в двух списках, возвращаем общий отсортированный список нод
class Solution:
def inorderTraversal(self, root: TreeNode, nodes: List[int]) -> List[int]:
if not root:
return nodes
self.inorderTraversal(root.left, nodes)
nodes.append(root.val)
self.inorderTraversal(root.right, nodes)
return nodes

def getAllElements(self, root1: TreeNode, root2: TreeNode) -> List[int]:
    list1 = []
    list2 = []
    self.inorderTraversal(root1, list1)
    self.inorderTraversal(root2, list2)
    return sorted(list1+list2)
// итеративное решение: обходим оба дерева, сохраняем поддеревья в стеки, спускаемся в левые поддеревья. Затем проходимся по стекам: в результирующий массив добавляем мЕньший последний элемент из стеков, затем переходим в правое поддерево
def getAllElements(self, root1: TreeNode, root2: TreeNode) -> List[int]:
        stack1 = []
        stack2 = []
        res = []
        tree1 = root1
        tree2 = root2
        while tree1 or tree2 or stack1 or stack2:
            while tree1:
                stack1.append(tree1)
                tree1 = tree1.left
            while tree2:
                stack2.append(tree2)
                tree2 = tree2.left
        if not stack2 or (stack1 and stack1[-1].val <= stack2[-1].val):
            tree1 = stack1.pop()
            res.append(tree1.val)
            tree1 = tree1.right
            else:
                tree2 = stack2.pop()
                res.append(tree2.val)
                tree2 = tree2.right
        return res
185
Q

Image Overlap
# numbers # arrays # matrices
Two images A and B are given, represented as binary, square matrices of the same size. (A binary matrix has only 0s and 1s as values.)

We translate one image however we choose (sliding it left, right, up, or down any number of units), and place it on top of the other image. After, the overlap of this translation is the number of positions that have a 1 in both images.

(Note also that a translation does not include any kind of rotation.)

What is the largest possible overlap?

Example 1:

Input: A = [[1,1,0],
            [0,1,0],
            [0,1,0]]
       B = [[0,0,0],
            [0,1,1],
            [0,0,1]]
Output: 3
Explanation: We slide A to right by 1 unit and down by 1 unit.
Notes: 

1 <= A.length = A[0].length = B.length = B[0].length <= 30
0 <= A[i][j], B[i][j] <= 1

A
// делаем массивы координат единиц, затем делаем массив всех возможных сдвигов (из первых координат вычитаем вторые), возвращаем самый частый сдвиг или [0] если его нет
def largestOverlap(self, A: List[List[int]], B: List[List[int]]) -> int:
        A = [(i, j) for i, row in enumerate(A) for j, item in enumerate(row) if item]
        B = [(i, j) for i, row in enumerate(B) for j, item in enumerate(row) if item]
        count = collections.Counter((ax-bx, ay-by) for ax, ay in A for bx, by in B)
        return max(count.values() or [0])
186
Q

Word Pattern
# strings
Given a pattern and a string str, find if str follows the same pattern.

Here follow means a full match, such that there is a bijection between a letter in pattern and a non-empty word in str.

Example 1:

Input: pattern = “abba”, str = “dog cat cat dog”
Output: true
Example 2:

Input:pattern = “abba”, str = “dog cat cat fish”
Output: false
Example 3:

Input: pattern = “aaaa”, str = “dog cat cat dog”
Output: false
Example 4:

Input: pattern = “abba”, str = “dog dog dog dog”
Output: false
Notes:
You may assume pattern contains only lowercase letters, and str contains lowercase letters that may be separated by a single space.

A

def wordPattern(self, pattern: str, s: str) -> bool:
words = s.split()
// если у нас неодинаковое количество символов и слов, мы можем сразу вернуть False
if len(pattern) != len(words):
return False
// делаем словарь соответствий символов и слов + дополнительный сет для слов, уже добавленных в словарь (для проверки, что каждому слову соответствует только один символ)
dic = {}
wordset = set()
for i in range(len(pattern)):
if pattern[i] not in dic:
if words[i] not in wordset:
dic[pattern[i]] = words[i]
wordset.add(words[i])
else:
return False
elif dic[pattern[i]] != words[i]:
return False
return True

// NB: возможно решение с одним словарем, где нужно хранить символы/слова с индексами

187
Q

Sum of Root To Leaf Binary Numbers
# trees # graphs # binary
Given a binary tree, each node has value 0 or 1. Each root-to-leaf path represents a binary number starting with the most significant bit. For example, if the path is 0 -> 1 -> 1 -> 0 -> 1, then this could represent 01101 in binary, which is 13.

For all leaves in the tree, consider the numbers represented by the path from the root to that leaf.

Return the sum of these numbers.

Example 1:

Input: [1,0,1,0,1,0,1]
Output: 22
Explanation: (100) + (101) + (110) + (111) = 4 + 5 + 6 + 7 = 22

A

// итеративное решение со стеком
class Solution:
def sumRootToLeaf(self, root: TreeNode) -> int:
if not root:
return 0
// заводим стек с парами. нода-путь, переменную для результата
stack, res = [(root, ‘’)], 0
// пока стек непустой
while stack:
// извлекаем последнюю пару из стека
current, path = stack.pop()
// если у текущей ноды есть левый или правый ребенок, добавляем его в стек с обновленным путем
if current.left:
stack.append((current.left, path+str(current.val)))
if current.right:
stack.append((current.right, path+str(current.val)))
// если нода-лист, обновляем путь, к результату прибавляем путь, переведенный в число
if not current.right and not current.left:
path += str(current.val)
res += int(path,2)
return res

188
Q

Compare Version Numbers
# strings # numbers # arrays
Compare two version numbers version1 and version2.
If version1 > version2 return 1; if version1 < version2 return -1;otherwise return 0.

You may assume that the version strings are non-empty and contain only digits and the . character.

The . character does not represent a decimal point and is used to separate number sequences.

For instance, 2.5 is not “two and a half” or “half way to version three”, it is the fifth second-level revision of the second first-level revision.

You may assume the default revision number for each level of a version number to be 0. For example, version number 3.4 has a revision number of 3 and 4 for its first and second level revision number. Its third and fourth level revision number are both 0.

Example 1:

Input: version1 = “0.1”, version2 = “1.1”
Output: -1
Example 2:

Input: version1 = “1.0.1”, version2 = “1”
Output: 1
Example 3:

Input: version1 = “7.5.2.4”, version2 = “7.5.3”
Output: -1
Example 4:

Input: version1 = “1.01”, version2 = “1.001”
Output: 0
Explanation: Ignoring leading zeroes, both “01” and “001” represent the same number “1”
Example 5:

Input: version1 = “1.0”, version2 = “1.0.0”
Output: 0
Explanation: The first version number does not have a third level revision number, which means its third level revision number is default to “0”

A
// из строк делаем массивы чисел, в более короткий массив добавляем в конец недостающие нули, чтобы выровнять длины, циклом проходимся по массивам, сравнивая числа 
def compareVersion(self, version1: str, version2: str) -> int:
        arr1 = [int(i) for i in version1.split('.')]
        arr2 = [int(i) for i in version2.split('.')]
        n = len(arr1)
        m = len(arr2)
        if n > m:
            for _ in range(m, n):
                arr2.append(0)
        elif m > n:
            for _ in range(n, m):
                arr1.append(0)
        for i in range(len(arr1)):
            if arr1[i] > arr2[i]:
                return 1
            elif arr1[i] < arr2[i]:
                return -1
        return 0
189
Q
Bulls and Cows
# numbers # strings
You are playing the following Bulls and Cows game with your friend: You write down a number and ask your friend to guess what the number is. Each time your friend makes a guess, you provide a hint that indicates how many digits in said guess match your secret number exactly in both digit and position (called "bulls") and how many digits match the secret number but locate in the wrong position (called "cows"). Your friend will use successive guesses and hints to eventually derive the secret number.

Write a function to return a hint according to the secret number and friend’s guess, use A to indicate the bulls and B to indicate the cows.

Please note that both secret number and friend’s guess may contain duplicate digits.

Example 1:

Input: secret = “1807”, guess = “7810”

Output: “1A3B”

Explanation: 1 bull and 3 cows. The bull is 8, the cows are 0, 1 and 7.
Example 2:

Input: secret = “1123”, guess = “0111”

Output: “1A1B”

Explanation: The 1st 1 in friend’s guess is a bull, the 2nd or 3rd 1 is a cow.
Note: You may assume that the secret number and your friend’s guess only contain digits, and their lengths are always equal.

A

def getHint(self, secret: str, guess: str) -> str:
// подсчитываем цифры в загаданном числе
counter = collections.Counter(secret)
n = len(secret)
A, B = 0, 0
// подсчитываем быков (при этом уменьшая значения в словаре)
for i in range(n):
if guess[i] == secret[i]:
A += 1
counter[guess[i]] -= 1
// подсчитываем коров в отдельном цикле (если в словаре остались ненулевые значения и символы по текущему индексу не совпадают)
for i in range(n):
if counter[guess[i]] != 0 and guess[i] != secret[i]:
B += 1
counter[guess[i]] -= 1
return str(A)+’A’+str(B)+’B’

190
Q
Maximum Product Subarray
# arrays # numbers
Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.

Example 1:

Input: [2,3,-2,4]
Output: 6
Explanation: [2,3] has the largest product 6.
Example 2:

Input: [-2,0,-1]
Output: 0
Explanation: The result cannot be 2, because [-2,-1] is not a subarray.

A
вариация kadane's algorithm: сохраняем текущие максимальное и минимальное произведения (поскольку могут встречаться 0 и отрицательные числа)
def maxProduct(self, nums: List[int]) -> int:
        global_max = prev_max = prev_min = nums[0]
        for num in nums[1:]:
            curr_min = min(prev_max*num, prev_min*num, num)
            curr_max = max(prev_max*num, prev_min*num, num)
            global_max= max(global_max, curr_max)
            prev_max = curr_max
            prev_min = curr_min
        return global_max
191
Q
Insert Interval
# arrays # numbers # interval
Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).

You may assume that the intervals were initially sorted according to their start times.

Example 1:

Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
Output: [[1,5],[6,9]]
Example 2:

Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
Output: [[1,2],[3,10],[12,16]]
Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].

A
def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
// с помощью модуля bisect находим индекс для нового интервала и вставляем его в массив
        bisect.insort(intervals, newInterval)
        res = []
// проходимся по всем интервалам
        for interval in intervals:
// если результирующий массив непустой и конец последнего интервала не меньше начала текущего интервала, то в конец последнего интервала записываем конец текущего интервала, если он больше, иначе в массив добавляем текущий интервал
            if res and res[-1][1] >= interval[0]:
                res[-1][1] = max(res[-1][1], interval[1])
            else:
                res.append(interval)
        return res
// то же решение без bisect
i = 0
        while( i
192
Q
House Robber
# numbers # arrays
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Example 1:

Input: nums = [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
Example 2:

Input: nums = [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
Total amount you can rob = 2 + 9 + 1 = 12.

A
// решение с динамическим программированием: в ходе заполнения массива выбираем, какой дом ограбить, через 1 или 2 слева
def rob(self, nums: List[int]) -> int:
        if not nums:
            return 0
        if len(nums) == 1:
            return nums[0]
        if len(nums) == 2:
            return max(nums)
        dp = [0] * len(nums)
        dp[0] = nums[0]
        dp[1] = max(nums[0], nums[1])
        for i in range(2, len(nums)):
            dp[i] = max(dp[i-2]+nums[i], dp[i-1])
        return dp[-1]

// решение с подсчетом четных и нечетных домов (добавляя новые значения по индексам, также меняем общее число четных и нечетных на большее)
def rob(self, nums: List[int]) -> int:
if len(nums) == 0:
return 0
evens, odds = 0, 0
for i in range(len(nums)):
if i % 2 == 0:
evens += nums[i]
evens = evens if evens > odds else odds
else:
odds += nums[i]
odds = evens if evens > odds else odds
return evens if evens > odds else odds

193
Q

Maximum XOR of Two Numbers in an Array
# numbers # arrays # bitwise
Given a non-empty array of numbers, a0, a1, a2, … , an-1, where 0 ≤ ai < 231.

Find the maximum result of ai XOR aj, where 0 ≤ i, j < n.

Could you do this in O(n) runtime?

Example:

Input: [3, 10, 5, 25, 2, 8]

Output: 28

Explanation: The maximum result is 5 ^ 25 = 28.

A
// надо найти два числа, у которых наибольшее количество старших битов, дающих 1 при операции ^: числа находятся с помощью сдвига по битам (слева направо), маски и сета битов
def findMaximumXOR(self, nums: List[int]) -> int:
        mx,mask=0,0
        for i in range(31,-1,-1):
            possible_mx = mx | 1 << i
            mask = mask | 1 << i
            bits=set()
            for num in nums:
                bits.add(num &amp; mask)
            for bit in bits:
                if bit ^ possible_mx in bits:
                    mx = possible_mx
                    break
        return mx
194
Q
Robot Bounded In Circle
# numbers # arrays # vectors
On an infinite plane, a robot initially stands at (0, 0) and faces north.  The robot can receive one of three instructions:

“G”: go straight 1 unit;
“L”: turn 90 degrees to the left;
“R”: turn 90 degress to the right.
The robot performs the instructions given in order, and repeats them forever.

Return true if and only if there exists a circle in the plane such that the robot never leaves the circle.

Example 1:

Input: “GGLLGG”
Output: true
Explanation:
The robot moves from (0,0) to (0,2), turns 180 degrees, and then returns to (0,0).
When repeating these instructions, the robot remains in the circle of radius 2 centered at the origin.
Example 2:

Input: "GG"
Output: false
Explanation: 
The robot moves north indefinitely.
Example 3:

Input: “GL”
Output: true
Explanation:
The robot moves from (0, 0) -> (0, 1) -> (-1, 1) -> (-1, 0) -> (0, 0) -> …

A

// робот зацикливается, если его итоговые координаты равны 0 или сменился вектор направления (с севера на другое), т.е. нужно проверить эти условия
def isRobotBounded(self, instructions: str) -> bool:
// заводим переменные для координат и вектор направления (сначала на север)
x = 0
y = 0
direction = (0, 1)
// проходимся циклом по инструкциям: если вперед, прибавляем к координатам координаты вектора направления
for i in instructions:
if i == ‘G’:
x += direction[0]
y += direction[1]
// если поворот налево, меняем вектор направления (-y, x), если поворот направо - (y, -x)
elif i == ‘L’:
direction = (-direction[1], direction[0])
else:
direction = (direction[1], -direction[0])
// в конце проверяем координаты и вектор направления
return (x == 0 and y == 0) or direction != (0, 1)

195
Q

Best Time to Buy and Sell Stock
# arrays # numbers
Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Note that you cannot sell a stock before you buy one.

Example 1:

Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Not 7-1 = 6, as selling price needs to be larger than buying price.
Example 2:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

A
def maxProfit(self, prices: List[int]) -> int:
        if not prices:
            return 0
        minprice = prices[0]
        maxprofit = 0
// проходимся по массиву, определяем текущую минимальную цену и максимальную (текущая цена - минимум)
        for p in prices:
            if p < minprice:
                minprice = p
            if p - minprice > maxprofit:
                maxprofit = p - minprice
        return maxprofit
196
Q
Unique Paths III
# numbers # matrices # graphs
On a 2-dimensional grid, there are 4 types of squares:

1 represents the starting square. There is exactly one starting square.
2 represents the ending square. There is exactly one ending square.
0 represents empty squares we can walk over.
-1 represents obstacles that we cannot walk over.
Return the number of 4-directional walks from the starting square to the ending square, that walk over every non-obstacle square exactly once.

Example 1:

Input: [[1,0,0,0],[0,0,0,0],[0,0,2,-1]]
Output: 2
Explanation: We have the following two paths:
1. (0,0),(0,1),(0,2),(0,3),(1,3),(1,2),(1,1),(1,0),(2,0),(2,1),(2,2)
2. (0,0),(1,0),(2,0),(2,1),(1,1),(0,1),(0,2),(0,3),(1,3),(1,2),(2,2)

A
// решение с обходом в глубину
def uniquePathsIII(self, grid: List[List[int]]) -> int:
        self.totalPaths = 0
        empty_cells = 1

// проходимся по матрице, запоминаем координаты начальной точки, конечной точки, считаем ячейки с 0
for i in range(len(grid)):
for j in range(len(grid[0])):
if grid[i][j] == 1:
x, y = (i, j)
elif grid[i][j] == 2:
self.end = (i, j)
elif grid[i][j] == 0:
empty_cells += 1
// делаем обход в глубину, возвращаем количество путей
self.dfs(grid, x, y, empty_cells)
return self.totalPaths

// функция обхода в глубину
def dfs(self, grid, x, y, empty_cells):
// если координаты за пределами матрицы, выходим
if not (0 <= x < len(grid) and 0 <= y < len(grid[0]) and grid[x][y] >= 0):
return
// если координаты конечные, проверяем количество. пустых ячеек: если их 0, увеличиваем счетчик путей, выходим
if (x, y) == self.end:
if empty_cells == 0:
self.totalPaths += 1
return
// отмечаем текущую ячейку как посещенную, рекурсивно обходим соседние ячейки, уменьшая количество пустых ячеек, после этого заново отмечаем ячейку как 0
grid[x][y] = -2
self.dfs(grid, x+1, y, empty_cells - 1)
self.dfs(grid, x-1, y, empty_cells - 1)
self.dfs(grid, x, y+1, empty_cells - 1)
self.dfs(grid, x, y-1, empty_cells - 1)
grid[x][y] = 0

197
Q

Majority Element II
Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times.

Note: The algorithm should run in linear time and in O(1) space.

Example 1:

Input: [3,2,3]
Output: [3]
Example 2:

Input: [1,1,1,3,3,2,2,2]
Output: [1,2]

A

def majorityElement(self, nums):
if not nums:
return []
//заводим два счетчика и два числа-кандидата (разных!)
count1, count2, candidate1, candidate2 = 0, 0, 0, 1
// проходимся по массиву чисел: если число совпадает с одним из кандидатов, увеличиваем их счетчик, если счетчики остались равны 0, делаем текущее число кандидатом и изменяем счетчик на 1, иначе уменьшаем оба счетчика
for n in nums:
if n == candidate1:
count1 += 1
elif n == candidate2:
count2 += 1
elif count1 == 0:
candidate1, count1 = n, 1
elif count2 == 0:
candidate2, count2 = n, 1
else:
count1, count2 = count1 - 1, count2 - 1
// в конце возвращаем массив кандидатов, проверив их встречаемость в массиве
return [n for n in (candidate1, candidate2)
if nums.count(n) > len(nums) // 3]

198
Q
Gas Station
# arrays # numbers
There are N gas stations along a circular route, where the amount of gas at station i is gas[i].

You have a car with an unlimited gas tank and it costs cost[i] of gas to travel from station i to its next station (i+1). You begin the journey with an empty tank at one of the gas stations.

Return the starting gas station’s index if you can travel around the circuit once in the clockwise direction, otherwise return -1.

Note:

If there exists a solution, it is guaranteed to be unique.
Both input arrays are non-empty and have the same length.
Each element in the input arrays is a non-negative integer.
Example 1:

Input:
gas = [1,2,3,4,5]
cost = [3,4,5,1,2]

Output: 3

Explanation:
Start at station 3 (index 3) and fill up with 4 unit of gas. Your tank = 0 + 4 = 4
Travel to station 4. Your tank = 4 - 1 + 5 = 8
Travel to station 0. Your tank = 8 - 2 + 1 = 7
Travel to station 1. Your tank = 7 - 3 + 2 = 6
Travel to station 2. Your tank = 6 - 4 + 3 = 5
Travel to station 3. The cost is 5. Your gas is just enough to travel back to station 3.
Therefore, return 3 as the starting index.

A
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
// если общая сумма бензина меньше суммы стоимости, то решения нет
        if len(gas) == 0 or len(cost) == 0 or sum(gas) < sum(cost):
            return -1
// заводим переменные для позиции и разницы бензина и стоимости
        start_point = 0
        delta = 0
// проходимся по индексам массива, к разнице добавляем разность бензина и стоимости по текущему индексу, если разница стала меньше 0, обнуляем разницу и меняем позицию на текущий индекс + 1, в конце возвращаем позицию
        for i in range(len(gas)):
            delta += gas[i] - cost[i]
            if delta < 0:
                delta = 0
                start_point = i + 1
        return start_point
199
Q
Find the Difference
# strings
Given two strings s and t which consist of only lowercase letters.

String t is generated by random shuffling string s and then add one more letter at a random position.

Find the letter that was added in t.

Example:

Input:
s = “abcd”
t = “abcde”

Output:
e

Explanation:
‘e’ is the letter that was added.

A
// решение с помощью исключающего ИЛИ: получаем числовые представления обеих строк, xor-им их и получаем код новой буквы 
def findTheDifference(self, s: str, t: str) -> str:
        xor_s = 0
        for char in s:
            xor_s ^= ord(char)
        xor_t = 0
        for char in t:
            xor_t ^= ord(char)
        return chr(xor_s^xor_t)
// то же решение одной строкой
def findTheDifference(self, s, t):
        return chr(reduce(operator.xor, map(ord, s + t)))
// решение с помощью словарей-счетчиков
def findTheDifference(self, s, t):
        return list((collections.Counter(t) - collections.Counter(s)))[0]
200
Q
Largest Number
# arrays # numbers

Given a list of non negative integers, arrange them such that they form the largest number.

Example 1:

Input: [10,2]
Output: “210”
Example 2:

Input: [3,30,34,5,9]
Output: “9534330”
Note: The result may be very large, so you need to return a string instead of an integer.

A

from functools import cmp_to_key

// вспомогательная функция для сравнения чисел как строк
def compare(x, y):
    x = str(x)
    y = str(y)
    return 1 if x + y < y + x else (0 if x == y else -1)
class Solution:
// сортируем массив по вспомогательной функции, возвращаем все числа, склеенные в строку
    def largestNumber(self, nums: List[int]) -> str:
        nums.sort(key=cmp_to_key(compare))
        return str(int(''.join(str(i) for i in nums)))
201
Q

Teemo Attacking
# numbers # arrays # intervals
In LOL world, there is a hero called Teemo and his attacking can make his enemy Ashe be in poisoned condition. Now, given the Teemo’s attacking ascending time series towards Ashe and the poisoning time duration per Teemo’s attacking, you need to output the total time that Ashe is in poisoned condition.

You may assume that Teemo attacks at the very beginning of a specific time point, and makes Ashe be in poisoned condition immediately.

Example 1:

Input: [1,4], 2
Output: 4
Explanation: At time point 1, Teemo starts attacking Ashe and makes Ashe be poisoned immediately.
This poisoned status will last 2 seconds until the end of time point 2.
And at time point 4, Teemo attacks Ashe again, and causes Ashe to be in poisoned status for another 2 seconds.
So you finally need to output 4.

Example 2:

Input: [1,2], 2
Output: 3
Explanation: At time point 1, Teemo starts attacking Ashe and makes Ashe be poisoned.
This poisoned status will last 2 seconds until the end of time point 2.
However, at the beginning of time point 2, Teemo attacks Ashe again who is already in poisoned status.
Since the poisoned status won’t add up together, though the second poisoning attack will still work at time point 2, it will stop at the end of time point 3.
So you finally need to output 3.

Note:

You may assume the length of given time series array won’t exceed 10000.
You may assume the numbers in the Teemo’s attacking time series and his poisoning time duration per attacking are non-negative integers, which won’t exceed 10,000,000.

A
// сначала вычисляем общую длительность отравления, затем циклом проходимся по массиву временных точек и вычитаем пересечения интервалов отравления
def findPoisonedDuration(self, timeSeries: List[int], duration: int) -> int:
        if not timeSeries:
            return 0
        total = duration * len(timeSeries)
        for i in range(1, len(timeSeries)):
            total -= max(0, duration - (timeSeries[i]-timeSeries[i-1]))
        return total
// циклом проходимся по массиву временных точек, к общему времени добавляем меньшее из длительности отравления либо разности соседних точек
def findPoisonedDuration(self, timeSeries: List[int], duration: int) -> int:
        if not timeSeries:
            return 0
        total = 0
        for t in range(len(timeSeries)-1):
            total += min(duration, timeSeries[t+1]-timeSeries[t])
        return total+duration
202
Q
Evaluate Division
# arrays # graphs # math
You are given equations in the format A / B = k, where A and B are variables represented as strings, and k is a real number (floating-point number). Given some queries, return the answers. If the answer does not exist, return -1.0.

The input is always valid. You may assume that evaluating the queries will result in no division by zero and there is no contradiction.

Example 1:
Input: equations = [[“a”,”b”],[“b”,”c”]], values = [2.0,3.0], queries = [[“a”,”c”],[“b”,”a”],[“a”,”e”],[“a”,”a”],[“x”,”x”]]
Output: [6.00000,0.50000,-1.00000,1.00000,-1.00000]
Explanation:
Given: a / b = 2.0, b / c = 3.0
queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ?
return: [6.0, 0.5, -1.0, 1.0, -1.0 ]

Example 2:
Input: equations = [[“a”,”b”],[“b”,”c”],[“bc”,”cd”]], values = [1.5,2.5,5.0], queries = [[“a”,”c”],[“c”,”b”],[“bc”,”cd”],[“cd”,”bc”]]
Output: [3.75000,0.40000,5.00000,0.20000]

Example 3:
Input: equations = [[“a”,”b”]], values = [0.5], queries = [[“a”,”b”],[“b”,”a”],[“a”,”c”],[“x”,”y”]]
Output: [0.50000,2.00000,-1.00000,-1.00000]

A

def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]:
// можно представить уравнения как графы, операции деления как путь от одной ноды к другой, а результат операции как вес пути, т.о. составляем словарь путей к нодам (включая обратные) с весами операций (вес обратного пути инвертируем)
nodes = dict()
for i in range(len(equations)):
if equations[i][0] not in nodes:
nodes[equations[i][0]] = [(equations[i][1], values[i])]
else:
nodes[equations[i][0]].append((equations[i][1], values[i]))
if equations[i][1] not in nodes:
nodes[equations[i][1]] = [(equations[i][0], 1 / values[i])]
else:
nodes[equations[i][1]].append((equations[i][0], 1 / values[i]))

// вспомогательная функция обхода графа
def search_path(cur_node, end_node, nodes, n, visited):
// если текущая нода совпала с искомой, возвращаем вес, в сет посещенных добавляем текущую ноду
if cur_node == end_node:
return n
visited.add(cur_node)
// в словаре по ключу текущей ноды проходимся по парам нода-вес: если нода не в посещенных, рекурсивно вызываем функцию, умножив общий вес на вес из пары, если получившийся вес больше 0, возвращаем его, иначе -1
for c, weight in nodes[cur_node]:
if c not in visited:
k = search_path(c, end_node, nodes, n*weight, visited)
if k > 0:
return k
return -1

    visited = set()
    res = [] // для каждой пары нод в запросах вызываем функцию обхода (начиная с 1), результат сохраняем в массиве, список посещенных нод очищаем
    for i, j in queries: // если какой-то ноды нет в словаре, добавляем -1
        if i not in nodes or j not in nodes:
            res.append(float(-1))
        else:
            res.append(float((search_path(i, j, nodes, 1, visited))))
            visited.clear()
    return res
203
Q
Subarray Product Less Than K
# numbers # arrays
Your are given an array of positive integers nums.

Count and print the number of (contiguous) subarrays where the product of all the elements in the subarray is less than k.

Example 1:
Input: nums = [10, 5, 2, 6], k = 100
Output: 8
Explanation: The 8 subarrays that have product less than 100 are: [10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6].
Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k.

A

// решение методом скользящего окна
def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
if k == 0:
return 0
// заводим переменные для подсчета подмассивов, произведения, и левой границы окна
count = 0
product = 1
left = 0
// внешним циклом сдвигаем правую границу окна, произведение умножаем на число по индексу правой границы
for right in range(len(nums)):
product *= nums[right]
// внутренним циклом сдвигаем левую границу окна (пока произведение не больше К и левая граница не больше правой: произведение делим на число по индексу левой границы, увеличиваем левую границу
while product >= k and left <= right:
product //= nums[left]
left += 1
// к счетчику прибавляем разность границ окна + 1 (так учитываются внутренние подмассивы текущего окна, произведения которых меньше К)
count += right - left + 1

    return count
204
Q
Word Break
# strings
Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine if s can be segmented into a space-separated sequence of one or more dictionary words.

Note:

The same word in the dictionary may be reused multiple times in the segmentation.
You may assume the dictionary does not contain duplicate words.
Example 1:

Input: s = “leetcode”, wordDict = [“leet”, “code”]
Output: true
Explanation: Return true because “leetcode” can be segmented as “leet code”.
Example 2:

Input: s = “applepenapple”, wordDict = [“apple”, “pen”]
Output: true
Explanation: Return true because “applepenapple” can be segmented as “apple pen apple”.
Note that you are allowed to reuse a dictionary word.
Example 3:

Input: s = “catsandog”, wordDict = [“cats”, “dog”, “sand”, “and”, “cat”]
Output: false

A

// решение с динамическим программированием:
делаем массив d из булевых переменных размера длины строки
d[i] будет True, если в списке слов есть слово, оканчивающееся на i-ый индекс строки и также нашлось соответствие для пред. слова (d[длина тек.слова - i] тоже True )
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
d = [False] * len(s)
for i in range(len(s)):
for w in wordDict:
if w == s[i-len(w)+1:i+1] and (d[i-len(w)] or i-len(w) == -1):
d[i] = True
return d[-1]

205
Q
First Missing Positive
# numbers # arrays
Given an unsorted integer array, find the smallest missing positive integer.

Example 1:

Input: [1,2,0]
Output: 3
Example 2:

Input: [3,4,-1,1]
Output: 2
Example 3:

Input: [7,8,9,11,12]
Output: 1
Follow up:

Your algorithm should run in O(n) time and uses constant extra space.

A

def firstMissingPositive(self, nums: List[int]) -> int:
// сдвигаем неположительные числа в конец массива, используя два указателя, затем работаем только с левой частью массива, где остались положительные числа
new_len = 0
for i in range(len(nums)):
if nums[i] > 0:
nums[new_len] = nums[i]
new_len += 1
// проходимся по части массива с положительными числами, если число входит в ряд (1, длина массива) то используем его как новый индекс (уменьшив на 1), и меняем знак числа по новому индексу, если оно положительное
for i in range(new_len):
if 1 <= abs(nums[i]) <= new_len:
new_idx = abs(nums[i]) - 1
if nums[new_idx] > 0:
nums[new_idx] *= -1
// в конце снова проходимся по массиву, если число по текущему индексу не поменяло знак, значит, на его месте должно быть недостающее число, т.е. сам индекс (больше на 1), иначе недостающее число выходит за пределы массива и стоит после последнего (вернуть длину массива + 1)
for i in range(new_len):
if nums[i] > 0:
return i+1

    return new_len+1
206
Q
Number of Recent Calls
# numbers # oop # arrays
You have a RecentCounter class which counts the number of recent requests within a certain time frame.

Implement the RecentCounter class:

RecentCounter() Initializes the counter with zero recent requests.
int ping(int t) Adds a new request at time t, where t represents some time in milliseconds, and returns the number of requests that has happened in the past 3000 milliseconds (including the new request). Specifically, return the number of requests that have happened in the inclusive range [t - 3000, t].
It is guaranteed that every call to ping uses a strictly larger value of t than the previous call.

Example 1:

Input
["RecentCounter", "ping", "ping", "ping", "ping"]
[[], [1], [100], [3001], [3002]]
Output
[null, 1, 2, 3, 3]
Explanation
RecentCounter recentCounter = new RecentCounter();
recentCounter.ping(1);     // requests = [1], range is [-2999,1], return 1
recentCounter.ping(100);   // requests = [1, 100], range is [-2900,100], return 2
recentCounter.ping(3001);  // requests = [1, 100, 3001], range is [1,3001], return 3
recentCounter.ping(3002);  // requests = [1, 100, 3001, 3002], range is [2,3002], return 3
A

используем дек, добавляем новое время пинга и удаляем старые временные точки, которые не укладываются в промежуток
from collections import deque

class RecentCounter:

    def \_\_init\_\_(self):
        self.requests = deque()
    def ping(self, t: int) -> int:
        self.requests.append(t)
        while t - self.requests[0] > 3000:
            self.requests.popleft()
        return len(self.requests)
207
Q
Combination Sum
# numbers # arrays
Given an array of distinct integers candidates and a target integer target, return a list of all unique combinations of candidates where the chosen numbers sum to target. You may return the combinations in any order.

The same number may be chosen from candidates an unlimited number of times. Two combinations are unique if the frequency of at least one of the chosen numbers is different.

Example 1:

Input: candidates = [2,3,6,7], target = 7
Output: [[2,2,3],[7]]
Explanation:
2 and 3 are candidates, and 2 + 2 + 3 = 7. Note that 2 can be used multiple times.
7 is a candidate, and 7 = 7.
These are the only two combinations.
Example 2:

Input: candidates = [2,3,5], target = 8
Output: [[2,2,2,2],[2,3,3],[3,5]]
Example 3:

Input: candidates = [2], target = 1
Output: []
Example 4:

Input: candidates = [1], target = 1
Output: [[1]]
Example 5:

Input: candidates = [1], target = 2
Output: [[1,1]]

A
// решение с динамическим программированием
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
// делаем вспогательный массив пустых массивов длины нужного числа (+первый вложенный массив, чтобы не было проблем с индексами)
        dp = [[[]]] + [[] for _ in range(target)]
// цииклом проходимся по исходным числам и индексам от текущего числа до нужного числа + 1
        for num in candidates:
            for i in range(num, target+1):
// в массив по текущего индексу добавляем подмассив с текущим числом и подмассивы из элемента по индексу (текущий индекс - текущее число)
                dp[i] += [subset + [num] for subset in dp[i-num]]
// возвращаем последний элемент вспомогательного массива
        return dp[target]
208
Q
K-diff Pairs in an Array
# numbers # arrays # math
Given an array of integers nums and an integer k, return the number of unique k-diff pairs in the array.

A k-diff pair is an integer pair (nums[i], nums[j]), where the following are true:

0 <= i, j < nums.length
i != j
a <= b
b - a == k

Example 1:

Input: nums = [3,1,4,1,5], k = 2
Output: 2
Explanation: There are two 2-diff pairs in the array, (1, 3) and (3, 5).
Although we have two 1s in the input, we should only return the number of unique pairs.
Example 2:

Input: nums = [1,2,3,4,5], k = 1
Output: 4
Explanation: There are four 1-diff pairs in the array, (1, 2), (2, 3), (3, 4) and (4, 5).
Example 3:

Input: nums = [1,3,1,5,4], k = 0
Output: 1
Explanation: There is one 0-diff pair in the array, (1, 1).
Example 4:

Input: nums = [1,2,4,4,3,3,0,9,2,3], k = 3
Output: 2
Example 5:

Input: nums = [-1,-2,-3], k = 1
Output: 2

Constraints:

1 <= nums.length <= 104
-107 <= nums[i] <= 107
0 <= k <= 107

A

def findPairs(self, nums: List[int], k: int) -> int:
// делаем словарь с подсчетом чисел в массиве
nums_dict = collections.Counter(nums)
res = 0
// проходимся по ключам словаря, проверяем, есть ли в словаре число “текущий ключ + к” (при к > 0) или что число встречается больше 1 раза (при к == 0)
for n in nums_dict:
if (k > 0 and n + k in nums_dict) or (k == 0 and nums_dict[n] > 1):
res += 1
return res

209
Q
Remove Covered Intervals
# numbers # arrays
Given a list of intervals, remove all intervals that are covered by another interval in the list.

Interval [a,b) is covered by interval [c,d) if and only if c <= a and b <= d.

After doing so, return the number of remaining intervals.

Example 1:

Input: intervals = [[1,4],[3,6],[2,8]]
Output: 2
Explanation: Interval [3,6] is covered by [2,8], therefore it is removed.
Example 2:

Input: intervals = [[1,4],[2,3]]
Output: 1
Example 3:

Input: intervals = [[0,10],[5,12]]
Output: 2
Example 4:

Input: intervals = [[3,10],[4,10],[5,11]]
Output: 2
Example 5:

Input: intervals = [[1,2],[1,4],[3,4]]
Output: 1

Constraints:

1 <= intervals.length <= 1000
intervals[i].length == 2
0 <= intervals[i][0] < intervals[i][1] <= 10^5
All the intervals are unique.

A
def removeCoveredIntervals(self, intervals: List[List[int]]) -> int:
// сортируем интервалы по первой координате, заводим переменную-счетчик, указатель на предыдущий интервал
        intervals.sort()
        count = 0
        prev = 0
// циклом проходимся по индексам интервалов (начиная с 1)
        for i in range(1, len(intervals)):
// если начальные координаты предыдущего и текущего совпадают, увеличиваем счетчик и сдвигаем предыдущий указатель на текущий
            if intervals[prev][0] == intervals[i][0]:
                count += 1
                prev = i
// если вторая координата предыдущего интервала не меньше чем у текущего, только увеличиваем счетчик, в противном случае сдвигаем предыдущий указатель на текущий
            elif intervals[prev][1] >= intervals[i][1]:
                count +=1
            else:
                prev = i
// в конце возвращаем разность длины и счетчика
        return len(intervals) - count
210
Q
Complement of Base 10 Integer
# numbers # bitwise
Every non-negative integer N has a binary representation.  For example, 5 can be represented as "101" in binary, 11 as "1011" in binary, and so on.  Note that except for N = 0, there are no leading zeroes in any binary representation.

The complement of a binary representation is the number in binary you get when changing every 1 to a 0 and 0 to a 1. For example, the complement of “101” in binary is “010” in binary.

For a given number N in base-10, return the complement of it’s binary representation as a base-10 integer.

Example 1:

Input: 5
Output: 2
Explanation: 5 is “101” in binary, with complement “010” in binary, which is 2 in base-10.
Example 2:

Input: 7
Output: 0
Explanation: 7 is “111” in binary, with complement “000” in binary, which is 0 in base-10.
Example 3:

Input: 10
Output: 5
Explanation: 10 is “1010” in binary, with complement “0101” in binary, which is 5 in base-10.

Note:

0 <= N < 10^9

A
// делаем левый сдвиг на количество битов числа, затем вычитаем 1 и само число
def bitwiseComplement(self, N: int) -> int:
        return (1 << N.bit_length()) - 1 - N if N != 0 else 1
211
Q

Rotate List
# linked lists
Given a linked list, rotate the list to the right by k places, where k is non-negative.

Example 1:

Input: 1->2->3->4->5->NULL, k = 2
Output: 4->5->1->2->3->NULL
Explanation:
rotate 1 steps to the right: 5->1->2->3->4->NULL
rotate 2 steps to the right: 4->5->1->2->3->NULL
Example 2:

Input: 0->1->2->NULL, k = 4
Output: 2->0->1->NULL
Explanation:
rotate 1 steps to the right: 2->0->1->NULL
rotate 2 steps to the right: 1->2->0->NULL
rotate 3 steps to the right: 0->1->2->NULL
rotate 4 steps to the right: 2->0->1->NULL

A
class Solution:
    def rotateRight(self, head: ListNode, k: int) -> ListNode:
        if not head or k == 0:
            return head
        n = 0
        temp1 = tail = head
// сначала определяем длину списка и хвостовую ноду
        while temp1:
            tail = temp1
            temp1 = temp1.next
            n += 1
//  определяем точку поворота списка (если она нулевая, сразу возвращаем список, если нет, вычитаем 1)   
        pivot = n - (k % n)
        if pivot == 0:
            return head
        pivot -= 1
        start = 0
        temp2 = head
// проходимся по списку до точки поворота
        while start != pivot and temp2:
            temp2 = temp2.next
            start += 1
// ставим указатель конца на начало, делаем началом следующую ноду после точки поворота, удаляем указатель на точке поворота 
        tail.next = head
        head = temp2.next
        temp2.next = None
        return head
212
Q
Serialize and Deserialize BST
# graphs # trees
Serialization is converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.

Design an algorithm to serialize and deserialize a binary search tree. There is no restriction on how your serialization/deserialization algorithm should work. You need to ensure that a binary search tree can be serialized to a string, and this string can be deserialized to the original tree structure.

The encoded string should be as compact as possible.

Example 1:

Input: root = [2,1,3]
Output: [2,1,3]
Example 2:

Input: root = []
Output: []

Constraints:

The number of nodes in the tree is in the range [0, 104].
0 <= Node.val <= 104
The input tree is guaranteed to be a binary search tree.

A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Codec:

    def serialize(self, root: TreeNode) -> str:
// выполняем обход дерева, кладем текущую ноду на стек, записываем ее в строку
        if not root:
            return ""
        stack = [root]
        res = ""
        while stack:
            node = stack.pop()
            if res:
                res += ','
            res += str(node.val)
            if node.right:
                stack.append(node.right)
            if node.left:
                stack.append(node.left)
        return res
def deserialize(self, nodes: str) -> TreeNode: // получаем из строки список значений нод, первую делаем корнем, кладем на стек
    if not nodes:
        return None
    order = list(map(int, nodes.split(',')))
    root = TreeNode(order[0])
    stack = [root] // проходимся по остальным значениям
    for n in order[1:]:
        temp = None // ищем место для текущей ноды: достаем последнее значение стека, пока стек не пустой и значение больше последнего значения в стеке
        while stack and n > stack[-1].val:
            temp = stack.pop() // если текущая нода не пустая, делаем правую ноду со значением и добавляем ее в стек
        if temp:
            temp.right = TreeNode(n)
            stack.append(temp.right) // иначе в текущую ноду записываем последний элемент стека, делаем левую ноду со значением и добавляем ее в стек
        else:
            temp = stack[-1]
            temp.left = TreeNode(n)
            stack.append(temp.left)
    return root
213
Q
Minimum Number of Arrows to Burst Balloons
# numbers # arrays # intervals
There are some spherical balloons spread in two-dimensional space. For each balloon, provided input is the start and end coordinates of the horizontal diameter. Since it's horizontal, y-coordinates don't matter, and hence the x-coordinates of start and end of the diameter suffice. The start is always smaller than the end.

An arrow can be shot up exactly vertically from different points along the x-axis. A balloon with xstart and xend bursts by an arrow shot at x if xstart ≤ x ≤ xend. There is no limit to the number of arrows that can be shot. An arrow once shot keeps traveling up infinitely.

Given an array points where points[i] = [xstart, xend], return the minimum number of arrows that must be shot to burst all balloons.

Example 1:

Input: points = [[10,16],[2,8],[1,6],[7,12]]
Output: 2
Explanation: One way is to shoot one arrow for example at x = 6 (bursting the balloons [2,8] and [1,6]) and another arrow at x = 11 (bursting the other two balloons).
Example 2:

Input: points = [[1,2],[3,4],[5,6],[7,8]]
Output: 4
Example 3:

Input: points = [[1,2],[2,3],[3,4],[4,5]]
Output: 2
Example 4:

Input: points = [[1,2]]
Output: 1
Example 5:

Input: points = [[2,3],[2,3]]
Output: 1

Constraints:

0 <= points.length <= 104

points. length == 2
- 231 <= xstart < xend <= 231 - 1

A
def findMinArrowShots(self, points: List[List[int]]) -> int:
        if not points:
            return 0
// сортируем интервалы по начальной точке, определяем минимальное количество стрел как количество интервалов, заводим переменную для текущей конечной точки (берем первую из интервала)
        points.sort()
        minArrows = len(points)
        currEnd = points[0][1]
// проходимся по интервалам со второго, если текущая начальная точка не больше конца, вычитаем стрелу и переопределяем текущий конец (либо текущее значение, либо конец текущего интервала), иначе делаем текущую конечную точку концом
        for p in points[1:]:
            if p[0] <= currEnd:
                minArrows -= 1
                currEnd = min(currEnd, p[1])
            else:
                currEnd = p[1]
        return minArrows
214
Q

Remove Duplicate Letters
# strings
Given a string s, remove duplicate letters so that every letter appears once and only once. You must make sure your result is the smallest in lexicographical order among all possible results.

Note: This question is the same as 1081: https://leetcode.com/problems/smallest-subsequence-of-distinct-characters/

Example 1:

Input: s = “bcabc”
Output: “abc”
Example 2:

Input: s = “cbacdcbc”
Output: “acdb”

Constraints:

1 <= s.length <= 104
s consists of lowercase English letters.

A

// решение с помощью стека
def removeDuplicateLetters(self, s: str) -> str:
// делаем словарь последних индексов всех символов строки
last_index = {}
for i, ch in enumerate(s):
last_index[ch] = i
stack = []
// проходимся по парам индекс-символ в строке
for i, ch in enumerate(s):
// если символа нет в стеке, удаляем последние символы в стеке, пока он не пустой, текущий символ лексикографически меньше последнего символа и индекс меньше последнего индекса последнего символа
if ch not in stack:
while stack and ch < stack[-1] and i < last_index[stack[-1]]:
stack.pop()
// после этого добавляем символ в стек, в конце делаем из стека строку
stack.append(ch)
return ““.join(stack)

215
Q
House Robber II
# numbers # arrays
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, adjacent houses have a security system connected, and it will automatically contact the police if two adjacent houses were broken into on the same night.

Given a list of non-negative integers nums representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.

Example 1:

Input: nums = [2,3,2]
Output: 3
Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2), because they are adjacent houses.
Example 2:

Input: nums = [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
Example 3:

Input: nums = [0]
Output: 0

Constraints:

1 <= nums.length <= 100
0 <= nums[i] <= 1000

A
// делаем вспомогательную функцию с простым ограблением
def simple_rob(self, nums, i, j):
        now, prev = 0, 0
        for idx in range(i, j):
            num = nums[idx]
            now, prev = max(now, prev + num), now
        return now
// используем вспомогательную функцию на двух частях массива (с первого элемента до предпоследнего, со второго до последнего), возвразщаем бОльшее значение        
    def rob(self, nums: List[int]) -> int:
        n = len(nums)      
        if n == 1:
            return nums[0]
        return max(self.simple_rob(nums, 0, n-1), self.simple_rob(nums, 1, n))
216
Q

Rotate Array
# nums # arrays
Given an array, rotate the array to the right by k steps, where k is non-negative.

Follow up:

Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem.
Could you do it in-place with O(1) extra space?

Example 1:

Input: nums = [1,2,3,4,5,6,7], k = 3
Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]
rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]
Example 2:

Input: nums = [-1,-100,3,99], k = 2
Output: [3,99,-1,-100]
Explanation:
rotate 1 steps to the right: [99,-1,-100,3]
rotate 2 steps to the right: [3,99,-1,-100]

A

// решения за линейное время и константную память

// решение с циклическими заменами
def rotate(self, nums: List[int], k: int) -> None:
n = len(nums)
// k переопределяем как остаток от деления на n
k %= n
// заводим переменные для старта и счетчика
start = count = 0
// цикл, пока счетчик меньше длины массива
while count < n:
// заводим текущее и предыдущее значения: начало и число по индексу начала
current, prev = start, nums[start]
// внутренний цикл
while True:
// определяем след. индекс: остаток от деления суммы текущего + к на n
next_idx = (current + k) % n
// меняем местами число по след. индексу и предыдущее
nums[next_idx], prev = prev, nums[next_idx]
// переопределяем текущее значение как след. индекс, увеличиваем счетчик
current = next_idx
count += 1
// если старт равен текущему, выходим из цикла, вне цикла увеличиваем старт на 1
if start == current:
break
start += 1

// решение с циклическими заменами и наибольшим общим делителем
def rotate(self, nums: List[int], k: int) -> None:
        n = len(nums)
        if k:
// определяем НОД к и длины массива
            g = math.gcd(k, n)
// проходимся по индексам в пределах НОД, и по индексам начиная от i+k до (длина массива/НОД)*k, через шаг k
            for i in range(g):
                for j in range(i+k, (n//g)*k, k):
// меняем местами элементы по индексам i, j%n
                    nums[i], nums[j%n] = nums[j%n], nums[i]

// решение с разворотом массива
// вспомогательная функция с разворотом массива
def reverse(self, nums: List[int], start: int, end: int) -> None:
while start < end:
nums[start], nums[end] = nums[end], nums[start]
start += 1
end -= 1

def rotate(self, nums: List[int], k: int) -> None:
    n = len(nums) // k переопределяем как остаток от деления на n
    k %= n // сначала разворачиваем весь массив, потом первые k чисел, потом последние n-k чисел        
    self.reverse(nums, 0, n-1)
    self.reverse(nums, 0, k-1)
    self.reverse(nums, k, n-1)
217
Q

Search a 2D Matrix
# numbers # arrays # matrices
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

Integers in each row are sorted from left to right.
The first integer of each row is greater than the last integer of the previous row.

Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,50]], target = 3
Output: true

A
// нужно работать с матрицей как с единым массивом: для этого используем вспомогательную функцию получения элемента матрицы по одному индексу
def getElem(self, matrix: List[List[int]], cols: int, idx: int) -> int:
// для получения первой координаты нужно разделить индекс на количество колонок, для второй - взять остаток от деления индекса на количество колонок
        return matrix[idx//cols][idx%cols]
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        if not matrix or target is None:
            return False
        rows = len(matrix)
        cols = len(matrix[0])
// определяем нижнюю и верхнюю границы поиска
        low = 0
        high = rows * cols - 1
// выполняем обычный бинарный поиск через цикл
        while low <= high:
// определяем серединный индекс, по нему вспомогательной функцией находим элемент матрицы
            mid_idx = (low+high)//2
// если он совпадает с искомым числом, возвращаем true, если искомое число больше, сдвигаем левую границу (серединный индекс + 1), иначе сдвигаем правую (серединный индекс - 1)
            middle = self.getElem(matrix, cols, mid_idx)
            if target == middle:
                return True
            elif target > middle:
                low = mid_idx + 1               
            else:
                high = mid_idx - 1
        return False
218
Q
Repeated DNA Sequences
# strings
All DNA is composed of a series of nucleotides abbreviated as 'A', 'C', 'G', and 'T', for example: "ACGAATTCCG". When studying DNA, it is sometimes useful to identify repeated sequences within the DNA.

Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule.

Example 1:

Input: s = “AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT”
Output: [“AAAAACCCCC”,”CCCCCAAAAA”]
Example 2:

Input: s = “AAAAAAAAAAAAA”
Output: [“AAAAAAAAAA”]

A
// простое решение со словарем-счетчиком и sliding window
def findRepeatedDnaSequences(self, s: str) -> List[str]:
        res = []
        subs = Counter()
        i = 0
        j = 10
        while j <= len(s):
            chunk = s[i:j]
            subs[chunk] += 1
            i += 1
            j += 1
        for k, v in subs.items():
            if v > 1:
                res.append(k)
        return res

// решение с битовыми преобразованиями
def findRepeatedDnaSequences(self, s: str) -> List[str]:
// делаем словарь соответствий букв битам
toInt = {‘A’: 0b00, ‘T’: 0b01, ‘G’: 0b10, ‘C’: 0b11}
res = []
subs = Counter()
key = 0
// делаем 20-битную маску из единиц
mask = (1 &laquo_space;20) - 1
// циклом проходимся по индексам строки
for i in range(len(s)):
// делаем число-ключ: сдвигаем влево на два бита, добавляем бит буквы и делаем лог. И с маской (чтобы очистить два бита)
key = ((key &laquo_space;2) | toInt[s[i]]) & mask
// если индекс больше нужной длины подстроки, добавляем ключ в словарь, если частотность ключа уже равна 2, добавляем в результат подстроку по индексам i-9:i+1
if i >= 9:
subs[key] += 1
if subs[key] == 2:
res.append(s[i-9:i+1])
return res

219
Q
Best Time to Buy and Sell Stock IV
# arrays # numbers
You are given an integer array prices where prices[i] is the price of a given stock on the ith day.

Design an algorithm to find the maximum profit. You may complete at most k transactions.

Notice that you may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again).

Example 1:

Input: k = 2, prices = [2,4,1]
Output: 2
Explanation: Buy on day 1 (price = 2) and sell on day 2 (price = 4), profit = 4-2 = 2.
Example 2:

Input: k = 2, prices = [3,2,6,5,0,3]
Output: 7
Explanation: Buy on day 2 (price = 2) and sell on day 3 (price = 6), profit = 6-2 = 4. Then buy on day 5 (price = 0) and sell on day 6 (price = 3), profit = 3-0 = 3.

Constraints:

0 <= k <= 109
0 <= prices.length <= 104
0 <= prices[i] <= 1000

A
// решение с динамическим программированием
def maxProfit(self, k: int, prices: List[int]) -> int:
        if not prices:
            return 0
        n = len(prices)
// если количество транзакций не меньше длины массива пополам, возвращаем сумму разностей склеенных частей массива
        if k >= n // 2:
            return sum(x-y for x, y in zip(prices[1:], prices[:-1]) if x > y)
// заводим массив из нулей длины массива цен
        profits = [0] * n
// внешний цикл в пределах числа транзакций
        for j in range(k):
// объявляем переменные для общего профита, предыдущего и текущего профита
            global_profit = prev_profit = cur_profit = 0
// внутренний цикл от 1 до длины массива
            for i in range(1, n):
// определяем профит (из цены по текущему индексу вычитаем предыдущую)
                profit = prices[i] - prices[i-1]
// определяем текущий профит: наибольший из текущий профит + профит, пред. профит + профит, пред. профит
                cur_profit = max(cur_profit + profit, prev_profit + profit, prev_profit)
// пред. профит определяем как число из ДП-массива по текущему индексу
                prev_profit = profits[i]
// число из ДП-массива по текущему индексу и общий профит определяем как наибольшее из общего профита или глобального профита
                profits[i] = global_profit = max(global_profit, cur_profit)
// в конце возвращаем последнее число из ДП-массива
        return profits[-1]
220
Q
Minimum Domino Rotations For Equal Row
# numbers # arrays
In a row of dominoes, A[i] and B[i] represent the top and bottom halves of the ith domino.  (A domino is a tile with two numbers from 1 to 6 - one on each half of the tile.)

We may rotate the ith domino, so that A[i] and B[i] swap values.

Return the minimum number of rotations so that all the values in A are the same, or all the values in B are the same.

If it cannot be done, return -1.

A

def minDominoRotations(self, A: List[int], B: List[int]) -> int:
n = len(A)
// делаем массива для подсчета чисел сверху, снизу и общего количества
ups = [0] * 6
bottoms = [0] * 6
totals = [0] * 6
// цикл по индексам массива
for i in range(n):
if A[i] != B[i]:
ups[A[i]-1] += 1
bottoms[B[i]-1] += 1
totals[A[i]-1] += 1
totals[B[i]-1] += 1
else:
totals[A[i]-1] += 1
min_rotate = None
// цикл по индексам чисел
for i in range(6):
// если число встретилось столько же, сколько всего костяшек домино, в переменную для подсчета перестановок записываем минимальное число из встреченных сверху или снизу
if totals[i] == n:
if min_rotate is None or ups[i] < min_rotate:
min_rotate = ups[i]
if min_rotate is None or bottoms[i] < min_rotate:
min_rotate = bottoms[i]
// если такого числа не попалось, возвращаем -1
return -1 if min_rotate is None else min_rotate

221
Q

Clone Graph
# graphs # numbers
Given a reference of a node in a connected undirected graph.

Return a deep copy (clone) of the graph.

Each node in the graph contains a val (int) and a list (List[Node]) of its neighbors.

class Node {
    public int val;
    public List neighbors;
}

Test case format:

For simplicity sake, each node’s value is the same as the node’s index (1-indexed). For example, the first node with val = 1, the second node with val = 2, and so on. The graph is represented in the test case using an adjacency list.

Adjacency list is a collection of unordered lists used to represent a finite graph. Each list describes the set of neighbors of a node in the graph.

The given node will always be the first node with val = 1. You must return the copy of the given node as a reference to the cloned graph.

Constraints:

1 <= Node.val <= 100
Node.val is unique for each node.
Number of Nodes will not exceed 100.
There is no repeated edges and no self-loops in the graph.
The Graph is connected and all nodes can be visited starting from the given node.

A

”””
# Definition for a Node.
class Node:
def __init__(self, val = 0, neighbors = None):
self.val = val
self.neighbors = neighbors if neighbors is not None else []
“””

class Solution:
// решение с обходом в глубину
def dfs(self, node, visited):
// создаем новую ноду, отмечаем ее в списке посещенных
new_node = Node(node.val, [])
visited[new_node.val-1] = new_node
// проходимся по соседям ноды: если текущая нода уже есть в посещенных, добавляем ее в соседи новой ноды, иначе рекурсивно обходим текущую ноду и добавляем соседей
for n in node.neighbors:
if visited[n.val-1]:
new_node.neighbors.append(visited[n.val-1])
else:
new_node.neighbors.append(self.dfs(n, visited))
// в конце возвращаем новую ноду
return new_node

def cloneGraph(self, node: 'Node') -> 'Node': // проверяем, не пустой ли граф, создаем список посещенных нод и выполняем обход в глубину
    if not node:
        return node
    visited = [None] * 100
    return self.dfs(node, visited)
222
Q
Asteroid Collision
# numbers # arrays
We are given an array asteroids of integers representing asteroids in a row.

For each asteroid, the absolute value represents its size, and the sign represents its direction (positive meaning right, negative meaning left). Each asteroid moves at the same speed.

Find out the state of the asteroids after all collisions. If two asteroids meet, the smaller one will explode. If both are the same size, both will explode. Two asteroids moving in the same direction will never meet.

Example 1:

Input: asteroids = [5,10,-5]
Output: [5,10]
Explanation: The 10 and -5 collide resulting in 10. The 5 and 10 never collide.
Example 2:

Input: asteroids = [8,-8]
Output: []
Explanation: The 8 and -8 collide exploding each other.
Example 3:

Input: asteroids = [10,2,-5]
Output: [10]
Explanation: The 2 and -5 collide resulting in -5. The 10 and -5 collide resulting in 10.
Example 4:

Input: asteroids = [-2,-1,1,2]
Output: [-2,-1,1,2]
Explanation: The -2 and -1 are moving left, while the 1 and 2 are moving right. Asteroids moving the same direction never meet, so no asteroids will meet each other.

Constraints:

1 <= asteroids <= 104
-1000 <= asteroids[i] <= 1000
asteroids[i] != 0

A

// решение с откатами индексов и удалением на месте
def asteroidCollision(self, asteroids: List[int]) -> List[int]:
// заводим переменную-индекс
i = 0
// цикл, пока индекс меньше длины массива-1 и в массиве больше одного астероида
while i < len(asteroids)-1 and len(asteroids) > 1:
// если индекс отрицательный, делаем его нулевым
if i < 0:
i = 0
// если следующий астероид меняет знак на минус, удаляем меньший из них по модулю и откатываем индекс назад на 2
if asteroids[i] > 0 and asteroids[i+1] < 0:
if abs(asteroids[i]) > abs(asteroids[i+1]):
del asteroids[i+1]
i-=2
elif abs(asteroids[i]) < abs(asteroids[i+1]):
del asteroids[i]
i-=2
// если астероиды одинаковы по величине, удаляем оба (по одному индексу), откатываем индекс на 3
else:
del asteroids[i]
del asteroids[i]
i-=3
// увеличиваем индекс на 1
i += 1
return asteroids

// решение с 2мя указателями: все взорвавшиеся астероиды оказываются в правой части массива, нужно вернуть левую часть
def asteroidCollision(self, asteroids: List[int]) -> List[int]:
if len(asteroids) <= 1:
return asteroids
// заводим два указателя
i = 0
j = 1
// цикл, пока второй указатель меньше длины массива
while j < len(asteroids):
// если 1ый указатель отрицательный или число по 1му указателю отрицательное или число по 2му указателью положительное, увеличиваем 1ый указатель, меняем местами числа по указателям, увеличиваем 2й указатель
if i < 0 or asteroids[i] < 0 or asteroids[j] > 0:
i += 1
asteroids[i] = asteroids[j]
j += 1
// если число по 1му указателю меньше числа по 2му указателю * - 1, уменьшаем 1й указатель
elif asteroids[i] < -1 * asteroids[j]:
i -= 1
// если число по 1му указателю равно числу по 2му указателю * - 1, уменьшаем 1й указатель и увеличиваем 2й
elif asteroids[i] == -1 * asteroids[j]:
i -= 1
j += 1
// иначе увеличиваем только 2й указатель
else:
j += 1
// возвращаем срез массива до 1го указателя включительно
return asteroids[:i+1]

// решение со стеком
def asteroidCollision(self, asteroids):
stack = []
// проходимся по числам в массиве
for num in asteroids:
// если число положительное, добавляем его в стек
if num>0:
stack.append(num)
// иначе удаляем последнее число из стека, пока стек непустой и последнее число стека положительное и последнее число стека меньше текущего числа по модулю
else:
while stack and stack[-1]>0 and stack[-1]

223
Q

Minimum Depth of Binary Tree
# trees # graphs
Given a binary tree, find its minimum depth.

The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.

Note: A leaf is a node with no children.

A
class Solution:
// обход дерева в глубину с подсчетом пути
    def dfs(self, root, cur_len, min_path):
        if not root:
            return min_path
// если у ноды нет детей, то переопределяем мин.путь
        if not root.right and not root.left:
            min_path = min(cur_len, min_path)
// рекурсивно обходим левое и правое поддерево, увеличивая длину текущего пути
        min_path = self.dfs(root.left, cur_len+1, min_path)
        min_path = self.dfs(root.right, cur_len+1, min_path)
// в конце возвращаем мин.путь
        return min_path
    def minDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
// запускаем обход дерева, начиная с корня, тек.путь = 1, мин. путь заведомо большой
        return self.dfs(root, 1, 10**5)
224
Q
132 Pattern
# numbers # arrays
Given an array of n integers nums, a 132 pattern is a subsequence of three integers nums[i], nums[j] and nums[k] such that i < j < k and nums[i] < nums[k] < nums[j].

Return true if there is a 132 pattern in nums, otherwise, return false.

Follow up: The O(n^2) is trivial, could you come up with the O(n logn) or the O(n) solution?

Example 1:

Input: nums = [1,2,3,4]
Output: false
Explanation: There is no 132 pattern in the sequence.
Example 2:

Input: nums = [3,1,4,2]
Output: true
Explanation: There is a 132 pattern in the sequence: [1, 4, 2].
Example 3:

Input: nums = [-1,3,2,0]
Output: true
Explanation: There are three 132 patterns in the sequence: [-1, 3, 2], [-1, 3, 0] and [-1, 2, 0].

A

// решение со стеком: число из массива, которое больше третьего числа из комбинации и идет до него, должно храниться в стеке
def find132pattern(self, nums: List[int]) -> bool:
n = len(nums)
// заводим стек и третье число (заведомо маленькое)
stack = []
third_num = -10**9-1
// проходимся по массиву слева направо
for i in range(n-1,-1,-1):
// если текущее число меньше третьего, сразу возвращаем истину
if nums[i]< third_num:
return True
// цикл, пока стек не пустой и текущее число больше последнего в стеке, переопределяем третье число как последнее из стека
while stack and nums[i]>stack[-1]:
third_num = stack.pop()
// в стек добавляем текущее число
stack.append(nums[i])
return False

// решение со вспомогательным массивом интервалов
def find132pattern(self, nums: List[int]) -> bool:
// заводим массив, текущий индекс и индекс минимума
        intervals = []
        i = 1
        s = 0
// цикл, пока текущий индекс меньше длины массива
        while i < len(nums):
// если число по текущему индексу меньше предыдущего числа, проверяем, что индекс минимума меньше текущего -1, тогда в массив добавляем интервал от минимума до индекса-1, в индекс минимума записываем текущий
            if nums[i] < nums[i-1]:
                if s < i - 1:
                    intervals.append((nums[s], nums[i-1]))
                s = i
// проходимся по интервалам, если текущее число входит в какой-либо интервал, возвращаем истину
            for x in intervals:
                if x[0] < nums[i] < x[1]:
                    return True
// увеличиваем индекс
            i += 1
        return False
225
Q

Bag of Tokens
# numbers # arrays
You have an initial power of P, an initial score of 0, and a bag of tokens where tokens[i] is the value of the ith token (0-indexed).

Your goal is to maximize your total score by potentially playing each token in one of two ways:

If your current power is at least tokens[i], you may play the ith token face up, losing tokens[i] power and gaining 1 score.
If your current score is at least 1, you may play the ith token face down, gaining tokens[i] power and losing 1 score.
Each token may be played at most once and in any order. You do not have to play all the tokens.

Return the largest possible score you can achieve after playing any number of tokens.

Example 1:

Input: tokens = [100], P = 50
Output: 0
Explanation: Playing the only token in the bag is impossible because you either have too little power or too little score.
Example 2:

Input: tokens = [100,200], P = 150
Output: 1
Explanation: Play the 0th token (100) face up, your power becomes 50 and score becomes 1.
There is no need to play the 1st token since you cannot play it face up to add to your score.

A

def bagOfTokensScore(self, tokens: List[int], P: int) -> int:
// сортируем массив, заводим два указателя (левый и правый), переменную для счета
tokens.sort()
left = 0
right = len(tokens) - 1
score = 0
// цикл, пока левый указатель не больше правого
while left <= right:
// если power не меньше фишки по левому указателю, вычитаем ее стоимость из power, увеличиваем счет, сдвигаем левый указатель вперед
if P >= tokens[left]:
P -= tokens[left]
score += 1
left += 1
// если счет ненулевой и указатели не равны, к power прибавляем фишку по правому указателю, из счета вычитаем 1 и сдвигаем правый указатель назад
elif score and left != right:
P += tokens[right]
score -= 1
right -= 1
// иначе выходим из цикла и возвращаем счет
else:
break
return score

226
Q

Stone Game IV
# arrays # numbers
Alice and Bob take turns playing a game, with Alice starting first.

Initially, there are n stones in a pile. On each player’s turn, that player makes a move consisting of removing any non-zero square number of stones in the pile.

Also, if a player cannot make a move, he/she loses the game.

Given a positive integer n. Return True if and only if Alice wins the game otherwise return False, assuming both players play optimally.

Example 1:

Input: n = 1
Output: true
Explanation: Alice can remove 1 stone winning the game because Bob doesn’t have any moves.
Example 2:

Input: n = 2
Output: false
Explanation: Alice can only remove 1 stone, after that Bob removes the last one winning the game (2 -> 1 -> 0).
Example 3:

Input: n = 4
Output: true
Explanation: n is already a perfect square, Alice can win with one move, removing 4 stones (4 -> 0).
Example 4:

Input: n = 7
Output: false
Explanation: Alice can’t win the game if Bob plays optimally.
If Alice starts removing 4 stones, Bob will remove 1 stone then Alice should remove only 1 stone and finally Bob removes the last one (7 -> 3 -> 2 -> 1 -> 0).
If Alice starts removing 1 stone, Bob will remove 4 stones then Alice only can remove 1 stone and finally Bob removes the last one (7 -> 6 -> 2 -> 1 -> 0).
Example 5:

Input: n = 17
Output: false
Explanation: Alice can’t win the game if Bob plays optimally.

A
// решение с динамическим программированием
def winnerSquareGame(self, n: int) -> bool:
// делаем дп-массив из Falseдлины n+1
        dp = [False] * (n+1)
// цикл от 1 до n+1: в массив по текущему индексу записываем противоположный рез-т оценки пред. элементов по индексу i-квадрат к, к в диапазоне от 1 до кв.корня i + 1
        for i in range(1, n+1):
            dp[i] = not all(dp[i - k*k] for k in range(1, int(i**0.5)+1))
        return dp[-1]
227
Q

Champagne Tower
# numbers # arrays
We stack glasses in a pyramid, where the first row has 1 glass, the second row has 2 glasses, and so on until the 100th row. Each glass holds one cup (250ml) of champagne.

Then, some champagne is poured in the first glass at the top. When the topmost glass is full, any excess liquid poured will fall equally to the glass immediately to the left and right of it. When those glasses become full, any excess champagne will fall equally to the left and right of those glasses, and so on. (A glass at the bottom row has its excess champagne fall on the floor.)

For example, after one cup of champagne is poured, the top most glass is full. After two cups of champagne are poured, the two glasses on the second row are half full. After three cups of champagne are poured, those two cups become full - there are 3 full glasses total now. After four cups of champagne are poured, the third row has the middle glass half full, and the two outside glasses are a quarter full, as pictured below.

Now after pouring some non-negative integer cups of champagne, return how full the jth glass in the ith row is (both i and j are 0-indexed.)

Example 1:

Input: poured = 1, query_row = 1, query_glass = 1
Output: 0.00000
Explanation: We poured 1 cup of champange to the top glass of the tower (which is indexed as (0, 0)). There will be no excess liquid so all the glasses under the top glass will remain empty.

A
// решение с динамическим программированием
def champagneTower(self, poured: int, query_row: int, query_glass: int) -> float:
// составляем массив с первым стаканом и нулями размера заданного ряда
        res = [poured] + [0] * query_row
// цикл по рядам от 1 до ряд+1
        for row in range(1, query_row + 1):
// цикл внутри рядов справа налево
            for i in range(row, -1, -1):
// по текущему индексу записываем сумму отношений соседних элементов
                res[i] = max(res[i]-1, 0) / 2.0 + max(res[i-1] - 1, 0) / 2.0
// возвращаем меньшее из значений: элемент по индексу нужного стакана или 1 
        return min(res[query_glass], 1)

// решение с построением треугольника Паскаля
def champagneTower(self, poured: int, query_row: int, query_glass: int) -> float:
// строим массив значений треугольника, в первое записываем количество налитых чашек
A = [[0] * k for k in range(1, 102)]
A[0][0] = poured
// цикл по рядам и столбцам
for r in range(query_row+1):
for c in range(r+1):
// определяем количество налитой жидкости: из текущего элемента вычитаем 1 и делим на 2, если количество больше 0, в нижние соседние ячейки прибавляем это количество
q = (A[r][c] - 1) / 2.0
if q > 0:
A[r+1][c] += q
A[r+1][c+1] += q
// в конце возвращаем меньшее из значений: 1 или количество по индексам нужного ряда и стакана
return min(1, A[query_row][query_glass])

228
Q
Linked List Cycle II
# linked lists
Given a linked list, return the node where the cycle begins. If there is no cycle, return null.

There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the next pointer. Internally, pos is used to denote the index of the node that tail’s next pointer is connected to. Note that pos is not passed as a parameter.

Notice that you should not modify the linked list.

Follow up:

Can you solve it using O(1) (i.e. constant) memory?

A
# Definition for singly-linked list.
# class ListNode:
#     def \_\_init\_\_(self, x):
#         self.val = x
#         self.next = None
// решение с двумя указателями
class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        slow = head
        fast = head
        isCycle = False
// в цикле двигаем быстрый и медленный указатели
        while slow and fast:
            slow = slow.next
// если у быстрого нет след.ноды, сразу возвращаем None
            if not fast.next:
                return None
            fast = fast.next.next
// если указатели встретились, значит в списке есть цикл, выходим
            if slow == fast:
                isCycle = True
                break
// если цикла не указалось, сразу возвращаем None
        if not isCycle:
            return None
// перемещаем медленный указатель на начало списка
        slow = head
// цикл, пока медленный и быстрый указатели не встретились: сдвигаем оба указателя на 1 ноду вперед
        while slow != fast:
            slow = slow.next
            fast = fast.next
// возвращаем медленный указатель
        return slow
229
Q
Summary Ranges
# numbers # arrays
You are given a sorted unique integer array nums.

Return the smallest sorted list of ranges that cover all the numbers in the array exactly. That is, each element of nums is covered by exactly one of the ranges, and there is no integer x such that x is in one of the ranges but not in nums.

Each range [a,b] in the list should be output as:

“a->b” if a != b
“a” if a == b

Example 1:

Input: nums = [0,1,2,4,5,7]
Output: ["0->2","4->5","7"]
Explanation: The ranges are:
[0,2] --> "0->2"
[4,5] --> "4->5"
[7,7] --> "7"
A

// проход за линейное время с двумя указателями, определяющими границы интервалов
def formatRange(self, nums: List[int], start: int, end: int) -> str:
if start == end - 1:
return str(nums[start])
else:
return str(nums[start])+’->’+str(nums[end-1])

def summaryRanges(self, nums: List[int]) -> List[str]:
    if not nums:
        return []
    ranges = []
    start = 0
    end = 1
    while end < len(nums):
        if nums[end] == nums[end-1] + 1:
            end += 1
        else:
            ranges.append(self.formatRange(nums, start, end))
            start = end
            end += 1
    ranges.append(self.formatRange(nums, start, end))
    return ranges
230
Q
Maximize Distance to Closest Person
# numbers # arrays
You are given an array representing a row of seats where seats[i] = 1 represents a person sitting in the ith seat, and seats[i] = 0 represents that the ith seat is empty (0-indexed).

There is at least one empty seat, and at least one person sitting.

Alex wants to sit in the seat such that the distance between him and the closest person to him is maximized.

Return that maximum distance to the closest person.

A

def maxDistToClosest(self, seats: List[int]) -> int:
# counting empty seats on the left
left_gap = 0
while seats[left_gap] != 1:
left_gap += 1
# counting empty seats in the middle and on the right
mid_gap = 0
cur_gap = 0
# start counting from the left gap, since we covered left seats before
for i in range(left_gap, len(seats)):
if seats[i] == 0:
cur_gap += 1
else:
mid_gap = max(mid_gap, cur_gap)
cur_gap = 0
# current gap becomes the right gap
right_gap = cur_gap
return max(left_gap, right_gap, (mid_gap+1)//2)

231
Q
Number of Longest Increasing Subsequence
# numbers # arrays
Given an integer array nums, return the number of longest increasing subsequences.

Example 1:

Input: nums = [1,3,5,4,7]
Output: 2
Explanation: The two longest increasing subsequences are [1, 3, 4, 7] and [1, 3, 5, 7].
Example 2:

Input: nums = [2,2,2,2,2]
Output: 5
Explanation: The length of longest continuous increasing subsequence is 1, and there are 5 subsequences’ length is 1, so output 5.

Constraints:

0 <= nums.length <= 2000
-106 <= nums[i] <= 106

A
// решение с динамическим программированием
def findNumberOfLIS(self, nums: List[int]) -> int:
        if not nums: return 0
        n = len(nums)
// составляем массивы подпоследовательностей разной длины и количество подпоследовательностей одной длины
        length = [1] * n
        count = [1] * n
// цикл по индексам массива
        for i in range(1, n):
            for j in range(i):
// если соседние числа возрастают, проверяем длины подпослед-й и кол-во подпослед-й по этим индексам
                if nums[i] > nums[j]:
                    if length[i] == length[j]:
                        length[i] = length[j]+1
                        count[i]  = count[j]
                    elif length[i] == length[j]+1:
                        count[i] += count[j]
// находим самую длинную подпослед-ть и считаем, сколько раз она встречается
        maxLength = max(length)
        return sum([count[i] for i in range(n) if length[i] == maxLength])
232
Q
Recover Binary Search Tree
# trees # graphs
You are given the root of a binary search tree (BST), where exactly two nodes of the tree were swapped by mistake. Recover the tree without changing its structure.

Follow up: A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?

A

// решение со стеком, куда записываются ноды в порядке инордер (возрастание) и указателями
def recoverTree(self, root: TreeNode) -> None:
// делаем стек, указатель текущей ноды, предыдущей ноды, левой и правой нод, которые нужно будет поменять местами
stack = []
trav = root
prev = None
left = None
right = None
// цикл, пока стек непустой или есть текущая нода
while stack or trav:
// если текущая нода есть, добавляем ее в стек, переходим на ее левую ноду
if trav:
stack.append(trav)
trav = trav.left
// иначе достаем последнюю ноду из стека, если есть предыдущая нода и ее значение больше последней, в левую ноду записываем предыдущую, в дополнительную - последнюю, иначе в правую ноду записываем последюю, в пред. ноду записываем последнюю, текущей нодой делаем правую ноду последней
else:
last = stack.pop()
if prev and prev.val > last.val:
if not left:
left = prev
curr = last
else:
right = last
prev = last
trav = last.right
// если есть правая нода, меняем ее значение с левой, иначе меняем значения с дополнительной (в случае если перепутанные ноды - соседи)
if right:
left.val, right.val = right.val, left.val
else:
left.val, curr.val = curr.val, left.val

233
Q

Convert Binary Number in a Linked List to Integer
# linked lists # bitwise
Given head which is a reference node to a singly-linked list. The value of each node in the linked list is either 0 or 1. The linked list holds the binary representation of a number.

Return the decimal value of the number in the linked list.

A
class Solution:
    def getDecimalValue(self, head: ListNode) -> int:
        num = 0
        cur = head
        while cur:
            num = (num << 1) + cur.val
            cur = cur.next
        return num
234
Q

Insertion Sort List
# linked lists
Sort a linked list using insertion sort.
Example 1:

Input: 4->2->1->3

A
// решение с помощью трех указателей: начала и конца отсортированной части и текущей ноды
def insertionSortList(self, head: ListNode) -> ListNode:
// если список пустой или только с одной ноды, сразу возвращаем
        if not head or not head.next:
            return head
 // делаем ноду-заглушку для начала отсортированной части       
        sort_start = ListNode(None)
        sort_start.next = head
// делаем голову концом отсортированной части, текущей - след.ноду
        sort_end = head
        cur = sort_end.next
// цикл, пока есть текущая нода: если текущая нода не меньше конца, то делаем ее концом, а текущей - след.ноду
        while cur:
            if cur.val >= sort_end.val:
                sort_end, cur = cur, cur.next
// иначе определяем место вставки циклом от начала отсортированной части
            else:
                insert_node = sort_start
                while insert_node.next.val < cur.val:
                    insert_node = insert_node.next
 // делаем след.указатель конца на след.ноду после текущей, след.указатель текущей на ноду после вставки, след.указатель вставки на текущую ноду, текущую ноду следующей после конца               
                sort_end.next = cur.next
                cur.next = insert_node.next
                insert_node.next = cur
                cur = sort_end.next
// в конце возвращаем начало списка        
        return sort_start.next
235
Q

Minimum Height Trees
# trees # graphs
A tree is an undirected graph in which any two vertices are connected by exactly one path. In other words, any connected graph without simple cycles is a tree.

Given a tree of n nodes labelled from 0 to n - 1, and an array of n - 1 edges where edges[i] = [ai, bi] indicates that there is an undirected edge between the two nodes ai and bi in the tree, you can choose any node of the tree as the root. When you select a node x as the root, the result tree has height h. Among all possible rooted trees, those with minimum height (i.e. min(h)) are called minimum height trees (MHTs).

Return a list of all MHTs’ root labels. You can return the answer in any order.

The height of a rooted tree is the number of edges on the longest downward path between the root and a leaf.

A

// деревьев с мин. путями может быть не больше 2
составляем словарь с путями, делаем сет из нод и последовательно удаляем пути, пока не останется 2 или меньше
def findMinHeightTrees(self, n: int, edges: List[List[int]]) -> List[int]:
d = collections.defaultdict(set)
for u, v in edges:
d[u].add(v)
d[v].add(u)
s = set(range(n))
while len(s) > 2:
leaves = set(i for i in s if len(d[i]) == 1)
s -= leaves
for i in leaves:
for j in d[i]:
d[j].remove(i)
return list(s)

236
Q

Minimum Cost to Move Chips to The Same Position
# numbers # arrays
We have n chips, where the position of the ith chip is position[i].

We need to move all the chips to the same position. In one step, we can change the position of the ith chip from position[i] to:

position[i] + 2 or position[i] - 2 with cost = 0.
position[i] + 1 or position[i] - 1 with cost = 1.
Return the minimum cost needed to move all the chips to the same position.
Input: position = [1,2,3]
Output: 1
Explanation: First step: Move the chip at position 3 to position 1 with cost = 0.
Second step: Move the chip at position 2 to position 1 with cost = 1.
Total cost is 1.

A
// подсчитываем количество фишек на четных и нечетных позициях и выбираем минимальное из них
def minCostToMoveChips(self, position: List[int]) -> int:
        evens = 0
        odds = 0
        for p in position:
            if p % 2 == 0:
                evens += 1
            else:
                odds += 1
        return min(evens, odds)
237
Q
Find the Smallest Divisor Given a Threshold
# numbers # arrays
Given an array of integers nums and an integer threshold, we will choose a positive integer divisor and divide all the array by it and sum the result of the division. Find the smallest divisor such that the result mentioned above is less than or equal to threshold.

Each result of division is rounded to the nearest integer greater than or equal to that element. (For example: 7/3 = 3 and 10/2 = 5).

It is guaranteed that there will be an answer.

Example 1:

Input: nums = [1,2,5,9], threshold = 6
Output: 5
Explanation: We can get a sum to 17 (1+2+5+9) if the divisor is 1.
If the divisor is 4 we can get a sum to 7 (1+1+2+3) and if the divisor is 5 the sum will be 5 (1+1+1+2).

A
// решение с бинарным поиском
class Solution:
    def smallestDivisor(self, nums: List[int], threshold: int) -> int:
// определяем нижнюю и верхнюю границы поиска (верхняя - самое большое число массива)
        low = 1
        high = max(nums)
// цикл, пока нижняя граница меньше верхней
        while low < high:
// определяем середину
            mid = (low + high) // 2
// если сумма частных каждого числа и середины больше порога, меняем нижнюю границу на середину + 1, иначе делаем середину верхней границей 
            if sum((i+mid-1)//mid for i in nums) > threshold:
                low = mid + 1
            else:
                high = mid
// в конце возвращаем нижнюю границу
        return low
238
Q
Add Two Numbers II
# numbers # linked lists
You are given two non-empty linked lists representing two non-negative integers. The most significant digit comes first and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.

You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Follow up:
What if you cannot modify the input lists? In other words, reversing the lists is not allowed.

Example:

Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7

A
// решение с помощью стека
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
// делаем из связных списков стеки, заводим переменную для суммы и ноду для ответа
        s1 = self.makeStack(l1)
        s2 = self.makeStack(l2)
        sum_val = 0
        ans = ListNode(0)
// цикл, пока стеки не пустые
        while s1 or s2:
// если первый стек не пустой, добавляем в сумму последнее число стека, так же добавляем последнее число из второго стека, если он не пустой
            if s1:
                sum_val += s1.pop()
            if s2:
                sum_val += s2.pop()
// в сумму записываем целую часть деления суммы на 10, в значение ответной ноды остаток от деления суммы на 10
            sum_val, ans.val = divmod(sum_val, 10)
// делаем головную ноду со значением суммы
            head = ListNode(sum_val)
// делаем указатель головы на ответную ноду, ответная нода становится головой
            head.next, ans = ans, head
// возвращаем ответную ноду, если у нее есть значение, иначе следующую после нее
        return ans if ans.val else ans.next
    def makeStack(self, node):
        s = []
        while node:
            s.append(node.val)
            node = node.next
        return s
239
Q
Binary Tree Tilt
# trees # graphs
Given the root of a binary tree, return the sum of every tree node's tilt.

The tilt of a tree node is the absolute difference between the sum of all left subtree node values and all right subtree node values. If a node does not have a left child, then the sum of the left subtree node values is treated as 0. The rule is similar if there the node does not have a right child.

A
// рекурсивное решение
class Solution:
// вспомогательная функция для подсчета сумм значений и тилтов за 1 проход 
    def sum_tilt(self, node: TreeNode) -> (int, int):
        if not node:
            return 0, 0
// рекурсивно вызываем функцию для левого и правого поддеревьев
        left_sum, left_tilt = self.sum_tilt(node.left)
        right_sum, right_tilt = self.sum_tilt(node.right)
// считаем общую сумму нод (текущая + левое поддерево + правое поддерево)
        total_sum = node.val + left_sum + right_sum
// считаем тилт текущей ноды, прибавляем к общей сумме тилтов вместе с суммами тилтов левого и правого поддеревьев
        tilt = abs(left_sum - right_sum)
        total_tilt = tilt + left_tilt + right_tilt
        return total_sum, total_tilt
    def findTilt(self, root: TreeNode) -> int:
        return self.sum_tilt(root)[1]
240
Q

Maximum Difference Between Node and Ancestor
# trees # graphs
Given the root of a binary tree, find the maximum value V for which there exist different nodes A and B where V = |A.val - B.val| and A is an ancestor of B.

A node A is an ancestor of B if either: any child of A is equal to B, or any child of A is an ancestor of B.

A
// подход сверху-вниз
// вспомогательная функция, возвращает минимальное значение, максимальное значение и макс. разницу
def maxV(self, node: TreeNode) -> (int, int, int):
// если ноды нет, возвращаем -1, иначе рекурсивно вызываем функцию для левого и правого поддерева
        if not node:
            return None, None, -1
        else:
            min_left, max_left, v_left = self.maxV(node.left)
            min_right, max_right, v_right = self.maxV(node.right)
// находим максимальную разницу слева и справа, наибольшее значение записываем в v
            l = max(abs(min_left - node.val), abs(max_left - node.val)) if min_left is not None else -1
            r = max(abs(min_right - node.val), abs(max_right - node.val)) if min_right is not None else -1
            v = max(l, r)
// переопределяем минимумы/максимумы слева и справа, если их нет
            min_left = min_left if min_left is not None else 10**5 + 1
            min_right = min_right if min_right is not None else 10**5 + 1
            max_left = max_left if max_left is not None else -1
            max_right = max_right if max_right is not None else -1
// находим минимум, максимум и v
            min_value = min(min_left, min_right, node.val)
            max_value = max(max_left, max_right, node.val)
            return min_value, max_value, max(v, v_left, v_right)
    def maxAncestorDiff(self, root: TreeNode) -> int:
        return self.maxV(root)[2]
// решение снизу-вверх (определяем минимум и максимум перед текущей нодой)
def maxAncestorDiff(self, root):
        self.Max = 0
// обход в глубину с определением мин-макс
        def dfs(node, low, high):    
            if not node: return
// определяем макс. разницу из текущего значения и разностей текущей ноды с мин-макс
            self.Max = max(self.Max, abs(node.val-low), abs(node.val-high))
// переопределяем мин и макс, рекурсивно выполняем обход левого и правого поддерева
            low1, high1 = min(low, node.val), max(high, node.val)
            dfs(node.left, low1, high1)
            dfs(node.right, low1, high1)
// выполняем обход дерева, начиная с корня, возвращаем макс. разницу                
        dfs(root, root.val, root.val)
        return self.Max
241
Q
Flipping an Image
# numbers # arrays # matrices
Given a binary matrix A, we want to flip the image horizontally, then invert it, and return the resulting image.

To flip an image horizontally means that each row of the image is reversed. For example, flipping [1, 1, 0] horizontally results in [0, 1, 1].

To invert an image means that each 0 is replaced by 1, and each 1 is replaced by 0. For example, inverting [0, 1, 1] results in [1, 0, 0].

Example 1:

Input: [[1,1,0],[1,0,1],[0,0,0]]
Output: [[1,0,0],[0,1,0],[1,1,1]]
Explanation: First reverse each row: [[0,1,1],[1,0,1],[0,0,0]].
Then, invert the image: [[1,0,0],[0,1,0],[1,1,1]]

A
// решение в одну строку
def flipAndInvertImage(self, A: List[List[int]]) -> List[List[int]]:
        return [[1-n for n in row[::-1]] for row in A]

// решение с перестановкой и инвертированием на месте
def flipAndInvertImage(self, A: List[List[int]]) -> List[List[int]]:
n = len(A[0])
for i in range(len(A)):
if n % 2 != 0:
A[i][n//2] = 1 - A[i][n//2]
for j in range(n//2):
A[i][j], A[i][n-1-j] = 1-A[i][n-1-j], 1-A[i][j]
return A

242
Q
Valid Square
# arrays # numbers # math
Given the coordinates of four points in 2D space, return whether the four points could construct a square.

The coordinate (x,y) of a point is represented by an integer array with two integers.

Example:

Input: p1 = [0,0], p2 = [1,1], p3 = [1,0], p4 = [0,1]
Output: True

Note:

All the input integers are in the range [-10000, 10000].
A valid square has four equal sides with positive length and four equal angles (90-degree angles).
Input points have no order.

A

// находим квадраты всех попарных расстояний, если среди них есть 4 равных и 2 вдвое больше остальных и равных между собой, значит это квадрат
def validSquare(self, p1: List[int], p2: List[int], p3: List[int], p4: List[int]) -> bool:
if p1 == p2 == p3 == p4:
return False
s1 = (p1[0] - p2[0])2 + (p1[1] - p2[1])2
s2 = (p1[0] - p3[0])2 + (p1[1] - p3[1])2
s3 = (p1[0] - p4[0])2 + (p1[1] - p4[1])2
s4 = (p2[0] - p3[0])2 + (p2[1] - p3[1])2
s5 = (p2[0] - p4[0])2 + (p2[1] - p4[1])2
s6 = (p3[0] - p4[0])2 + (p3[1] - p4[1])2
return (s1 == s3 == s4 == s6 and s2 == s5 == 2s1) or (s1 == s2 == s5 == s6 and s3 == s4 == 2s1) or (s2 == s3 == s4 == s5 and s1 == s6 == 2*s2)

243
Q
Permutations II
# numbers # arrays
Given a collection of numbers, nums, that might contain duplicates, return all possible unique permutations in any order.

Example 1:

Input: nums = [1,1,2]
Output:
[[1,1,2],
 [1,2,1],
 [2,1,1]]
Example 2:

Input: nums = [1,2,3]
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

Constraints:

1 <= nums.length <= 8
-10 <= nums[i] <= 10

A

// решение с бэктрекингом
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
res = []
// вспомогательная функция для бэктрекинга
def backtrack(comb, counter):
// если длина текущей перестановки равна длине исходного массива, добавляем ее в результат и выходим
if len(comb) == len(nums):
res.append(list(comb))
return
// цикл по словарю-счетчику
for num in counter:
// если число встретилось больше 0 раз, добавляем его в перестановку и уменьшаем счетчик
if counter[num] > 0:
comb.append(num)
counter[num] -= 1
// рекурсивно вызываем функцию, удаляем из комбинации последнее число и снова увеличиваем счетчик
backtrack(comb, counter)
comb.pop()
counter[num] += 1
// вызываем функцию для пустого массива и словаря-счетчика чисел, возвращаем результат
backtrack([], collections.Counter(nums))
return res

244
Q
Populating Next Right Pointers in Each Node
# trees # graphs
You are given a perfect binary tree where all leaves are on the same level, and every parent has two children. The binary tree has the following definition:
struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.

Initially, all next pointers are set to NULL.

Follow up:

You may only use constant extra space.
Recursive approach is fine, you may assume implicit stack space does not count as extra space for this problem.

Input: root = [1,2,3,4,5,6,7]
Output: [1,#,2,3,#,4,5,6,7,#]
Explanation: Given the above perfect binary tree (Figure A), your function should populate each next pointer to point to its next right node, just like in Figure B. The serialized output is in level order as connected by the next pointers, with ‘#’ signifying the end of each level.

A
// решение со вспомогательной функцией обхода
# Definition for a Node.
class Node:
    def \_\_init\_\_(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
"""
// обход дерева по уровням (передается текущий уровень, нужный уровень, текущая нода и предыдущая)
def traverse(cur_level, target_level, node, prev):
// если ноды нет, возвращаем None
    if not node:
        return None
// если спустились до нужного уровня, делаем след.указатель ноды на предыдущую, текущую ноду делаем предыдущей и возвращаем ее
    if cur_level == target_level:
        node.next = prev
        prev = node
        return node
// иначе рекурсивно обходим правое и левое поддерево, увеличивая текущий уровень, и возвращаем пред.ноду
    else:
        prev = traverse(cur_level + 1, target_level, node.right, prev)
        prev = traverse(cur_level + 1, target_level, node.left, prev)
        return prev
class Solution:            
    def connect(self, root: 'Node') -> 'Node':
        n = 0
// циклом обходим дерево, пока вернулась хоть одна нода
        while traverse(0, n, root, None):
            n += 1
        return root
// альтернативное решение
class Solution:
    def connect(self, root: 'Node') -> 'Node':
        if not root:
            return
// заводим предыдущую ноду и текущую
        prev = root
        cur = None
// пока есть левый ребенок пред.ноды
        while prev.left:
// делаем пред. ноду текущей
            cur = prev
// пока есть текущая нода
            while cur:
// делаем след. указатель левого ребенка текущей ноды на ее правого ребенка
                cur.left.next = cur.right
// если след. указатель текущей ноды не пустой, делаем след. указатель прав. ребенка текущей ноды на след. указатель левого ребенка текущей ноды
                if cur.next:
                    cur.right.next = cur.next.left
// делаем след. ноду текущей
                cur = cur.next
// делаем левого ребенка пред. ноды пред. нодой
            prev = prev.left
        return root
245
Q

Range Sum of BST
# trees # graphs
Given the root node of a binary search tree, return the sum of values of all nodes with a value in the range [low, high].
Input: root = [10,5,15,3,7,null,18], low = 7, high = 15
Output: 32

A
def rangeSumBST(self, root, L, R):
        """
        :type root: TreeNode
        :type L: int
        :type R: int
        :rtype: int
        """
        def dfs(root):
            if not root:
                return
            if L <= root.val <= R:
                self.res += root.val
            if L <= root.val:
                dfs(root.left)
            if R >= root.val:
                dfs(root.right)
        self.res = 0
        dfs(root)
        return self.res
246
Q
Merge Intervals
# arrays # numbers
Given an array of intervals where intervals[i] = [starti, endi], merge all overlapping intervals, and return an array of the non-overlapping intervals that cover all the intervals in the input.

Example 1:

Input: intervals = [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].

A
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        if not intervals:
            return []
    sortedIntervals = sorted(intervals)
    mergedIntervals = []

    currentStart, currentEnd = sortedIntervals[0]

    for start, end in sortedIntervals[1:]:
        if start > currentEnd:
            mergedIntervals.append([currentStart, currentEnd])
            currentStart, currentEnd = start, end
        else:
            currentEnd = max(end, currentEnd)

    mergedIntervals.append((currentStart, currentEnd))

    return mergedIntervals
247
Q
Decode String
# strings
Given an encoded string, return its decoded string.

The encoding rule is: k[encoded_string], where the encoded_string inside the square brackets is being repeated exactly k times. Note that k is guaranteed to be a positive integer.

You may assume that the input string is always valid; No extra white spaces, square brackets are well-formed, etc.

Furthermore, you may assume that the original data does not contain any digits and that digits are only for those repeat numbers, k. For example, there won’t be input like 3a or 2[4].

Example 1:

Input: s = “3[a]2[bc]”
Output: “aaabcbc”

A
// решение со стеком
class Solution:
    def decodeString(self, s: str) -> str:
        i = 0
        num = 0
        stack = ['']
        while i < len(s):
            if s[i].isdigit():
                num = num*10+int(s[i])
            elif s[i] == '[':
                stack.append(num)
                num = 0
                stack.append("")
            elif s[i] == ']':
                str1 = stack.pop()
                rep = stack.pop()
                str2 = stack.pop()
                stack.append(str2+rep*str1)
            else:
                stack[-1] += s[i]
            i += 1
        return ''.join(stack)
248
Q

Search in Rotated Sorted Array II
# numbers # arrays
Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., [0,0,1,2,2,5,6] might become [2,5,6,0,0,1,2]).

You are given a target value to search. If found in the array return true, otherwise return false.

Example 1:

Input: nums = [2,5,6,0,0,1,2], target = 0
Output: true
Example 2:

Input: nums = [2,5,6,0,0,1,2], target = 3
Output: false

A
def search(self, nums: List[int], target: int) -> bool:
        l, r = 0, len(nums) - 1
    while l <= r:
        mid = (l + r) // 2

        if nums[mid] == target or nums[l] == target:
            return True
        elif nums[mid] < target < nums[r]:
            l = mid + 1
        elif nums[l] < target < nums[mid]:
            r = mid - 1
        else: # binary search doesn't work
            l += 1

    return False
249
Q

Numbers At Most N Given Digit Set
# numbers # arrays
Given an array of digits, you can write numbers using each digits[i] as many times as we want. For example, if digits = [‘1’,’3’,’5’], we may write numbers such as ‘13’, ‘551’, and ‘1351315’.

Return the number of positive integers that can be generated that are less than or equal to a given integer n.

Example 1:

Input: digits = [“1”,”3”,”5”,”7”], n = 100
Output: 20
Explanation:
The 20 numbers that can be written are:
1, 3, 5, 7, 11, 13, 15, 17, 31, 33, 35, 37, 51, 53, 55, 57, 71, 73, 75, 77.

A

// решение с динамическим программированием и комбинаторикой
def atMostNGivenDigitSet(self, digits, n):
up, ans, T, str_n = [0]*10, 0, len(digits), str(n)
for i in range(10):
for dig in digits:
up[i] += (dig < str(i))

    k, d_set = len(str_n), set(digits)
    for i in range(k):
        if i > 0 and str_n[i-1] not in d_set: break
        ans += up[int(str_n[i])] * T**(k-i-1)

    addon = (T**k - 1)//(T-1) - 1 if T != 1 else k - 1
    return ans + addon + (not set(str_n) - set(digits))
250
Q
House Robber III
# trees # numbers # graphs
The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that "all houses in this place forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night.

Determine the maximum amount of money the thief can rob tonight without alerting the police.
Example 1:

Input: [3,2,3,null,3,null,1]

     3
    / \
   2   3
    \   \ 
     3   1

Output: 7
Explanation: Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.

A
# Definition for a binary tree node.
# class TreeNode:
#     def \_\_init\_\_(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
// решение с обходом в глубину
class Solution:
    def rob(self, root: TreeNode) -> int:
        def dfs(node):
            if not node: return [0, 0]
            L = dfs(node.left)
            R = dfs(node.right)
            return [node.val + L[1] + R[1], max(L) + max(R)]
    return max(dfs(root))
251
Q

Basic Calculator II
Implement a basic calculator to evaluate a simple expression string.

The expression string contains only non-negative integers, +, -, *, / operators and empty spaces . The integer division should truncate toward zero.

Example 1:

Input: “3+2*2”
Output: 7
Example 2:

Input: “ 3/2 “
Output: 1
Example 3:

Input: “ 3+5 / 2 “
Output: 5

A
// решение со стеком и словарем операций
class Solution:
    def calculate(self, s: str) -> int:
        num, op, stack = 0, '+', [0]
        ops = {
            '+':lambda x, y: y,
            '-':lambda x, y: -y,
            '*':lambda x, y: x*y,
            '/':lambda x, y: int(x/y)
        }
        for i, c in enumerate(s):
            if c.isdigit():
                num = num * 10 + int(c)
            if not c.isdigit() and c != ' ' or i == len(s)-1:
                prev = 0 if op in '+-' else stack.pop()
                stack.append(ops[op](prev, num))
                num, op = 0, c
        return sum(stack)
252
Q
Smallest Integer Divisible by K
# numbers # math
Given a positive integer K, you need to find the length of the smallest positive integer N such that N is divisible by K, and N only contains the digit 1.

Return the length of N. If there is no such N, return -1.

Note: N may not fit in a 64-bit signed integer.

Example 1:

Input: K = 1
Output: 1
Explanation: The smallest answer is N = 1, which has length 1.
Example 2:

Input: K = 2
Output: -1
Explanation: There is no such positive integer N divisible by 2.
Example 3:

Input: K = 3
Output: 3
Explanation: The smallest answer is N = 111, which has length 3.

A
def smallestRepunitDivByK(self, K: int) -> int:
// проверяем пограничные случаи, когда К четное или делится на 5
        if K % 2 == 0 or K % 5 == 0:
            return -1
// проверяем остаток от деления на К в цикле от 1 до К + 1, если остаток нулевой, сразу возвращаем количество цифр
        r = 0
        for n in range(1, K+1):
            r = (r * 10 + 1) % K
            if not r: return n
253
Q
Longest Substring with At Least K Repeating Characters
# strings
Given a string s and an integer k, return the length of the longest substring of s such that the frequency of each character in this substring is greater than or equal to k.

Example 1:

Input: s = “aaabb”, k = 3
Output: 3
Explanation: The longest substring is “aaa”, as ‘a’ is repeated 3 times.
Example 2:

Input: s = “ababbc”, k = 2
Output: 5
Explanation: The longest substring is “ababb”, as ‘a’ is repeated 2 times and ‘b’ is repeated 3 times.

Constraints:

1 <= s.length <= 104
s consists of only lowercase English letters.
1 <= k <= 105

A
def longestSubstring(self, s: str, k: int) -> int:
// делаем словарь частотности всех символов строки: если все символы встречаются не реже К раз, возвращаем длину всей строки
        counter = collections.Counter(s)
        if all(counter[i] >= k for i in counter):
            return len(s)
// заводим переменные для стартового индекса и длины подстроки
        start, longest = 0, 0
// цикл по индексам в пределах длины строки
        for i in range(len(s)):
// если частотность символа по текущему индексу меньше К, определяем длину как максимум из текущего значения/рекурсивного вызова для среза строки со стартового индекса/К, делаем стартовый индекс i+1
            if counter[s[i]] < k:
                longest = max(longest, self.longestSubstring(s[start:i], k))
                start = i + 1
определяем длину как максимум из текущего значения/рекурсивного вызова для среза строки со стартового индекса/К, возвращаем это значение        
        longest = max(longest, self.longestSubstring(s[start:], k))
        return longest
254
Q
Partition Equal Subset Sum
# numbers # arrays
Given a non-empty array nums containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.

Example 1:

Input: nums = [1,5,11,5]
Output: true
Explanation: The array can be partitioned as [1, 5, 5] and [11].
Example 2:

Input: nums = [1,2,3,5]
Output: false
Explanation: The array cannot be partitioned into equal sum subsets.

A
// решение с динамическим программированием
def canPartition(self, nums: List[int]) -> bool:
// если чисел меньше 2 или их сумма нечетная, сразу возвращаем False
        if len(nums) < 2 or sum(nums) % 2 != 0:
            return False
// определяем половину: делим сумму чисел на 2
        half = sum(nums) // 2
// делаем дп-массив из булевых переменных размера половины
        dp = [False for i in range(half+1)]
        dp[0] = True
// цикл по числам массива
        for num in nums:
// если число больше длины дп-массива-1, сразу возвращаем False
            if num > len(dp)-1:
                return False
// делаем массив индексов
            idxlist = []
// цикл от 1 до половины
            for i in range(1, half+1):
// если текущее число больше текущего индекса, идем дальше
                if num > i:
                    continue
// если в дп-массиве по индексу индекс-число истинное значение, в массив индексов добавляем текущий индекс
                if dp[i-num]:
                    idxlist += [i]
// в дп-массиве по индексу текущего числа ставим истину
            dp[num] = True
// проходимся по списку индексов, в дп-массив ставим истину по его индексам
            for idx in idxlist:
                dp[idx] = True
// возвращаем последнее значение дп-массива
        return dp[-1]
// решение с битовыми манипуляциями
def canPartition(self, A):
// получаем битовое представление всего массива: БП сдвигаем влево на число (умножаем на 2 в степени числа) и делаем лог. ИЛИ
        a = reduce(lambda a, num: a|(a<
255
Q
Sliding Window Maximum
# numbers # arrays
You are given an array of integers nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.

Return the max sliding window.

Example 1:

Input: nums = [1,3,-1,-3,5,3,6,7], k = 3
Output: [3,3,5,5,6,7]
Explanation: 
Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7
Example 2:

Input: nums = [1], k = 1
Output: [1]
Example 3:

Input: nums = [1,-1], k = 1
Output: [1,-1]
Example 4:

Input: nums = [9,11], k = 2
Output: [11]
Example 5:

Input: nums = [4,-2], k = 2
Output: [4]

Constraints:

1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length

A
// решение с очередью
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
        d = collections.deque()
        res = []
// проходимся по индексам массива
        for i in range(len(nums)):
            n = nums[i]
// если очередь непустая и ее первый элемент меньше i-k, удаляем его
            if d and d[0] <= i-k:
                d.popleft()
// пока очередь непустая и число по индексу последнего элемента очередь меньше-равно числа по текущему индексу, удаляем в очереди справа
            while d and nums[d[-1]]<=n:
                d.pop()
// добавляем в очередь индекс
            d.append(i)
// если индекс+1 больше-равно к, в результат добавляем число по индексу первого элемента очереди
            if i+1 >= k:
                res.append(nums[d[0]])
        return res
256
Q
Jump Game III
# arrays
Given an array of non-negative integers arr, you are initially positioned at start index of the array. When you are at index i, you can jump to i + arr[i] or i - arr[i], check if you can reach to any index with value 0.

Notice that you can not jump outside of the array at any time.

Example 1:

Input: arr = [4,2,3,0,3,1,2], start = 5
Output: true
Explanation:
All possible ways to reach at index 3 with value 0 are:
index 5 -> index 4 -> index 1 -> index 3
index 5 -> index 6 -> index 4 -> index 1 -> index 3
Example 2:

Input: arr = [4,2,3,0,3,1,2], start = 0
Output: true 
Explanation: 
One possible way to reach at index 3 with value 0 is: 
index 0 -> index 4 -> index 1 -> index 3
Example 3:

Input: arr = [3,0,2,1,2], start = 2
Output: false
Explanation: There is no way to reach at index 1 with value 0.

Constraints:

1 <= arr.length <= 5 * 10^4
0 <= arr[i] < arr.length
0 <= start < arr.length

A
// итеративный обход со стеком
def canReach(self, arr: List[int], start: int) -> bool:
// делаем стек с начальным индексом, сет посещенных индексов и переменную с длиной массива
        stack = [start]
        visited = set()
        n = len(arr)
// цикл, пока стек непустой
        while stack:
// достаем последний индекс из стека
            i = stack.pop()
// если число по нему - 0, сразу возвращаем true
            if arr[i] == 0:
                return True
// добавляем индекс в посещенные
            visited.add(i)
// определяем следующие два индекса, по которым можно перейти: если первый меньше длины массива и его нет в посещенных, добавляем в стек, если второй не меньше 0 и его нет в посещенных, добавляем в стек
            num1 = i + arr[i]
            num2 = i - arr[i]
            if num1 < n and num1 not in visited:
                stack.append(num1)
            if num2 >= 0 and num2 not in visited:
                stack.append(num2)
// в конце возвращаем False
        return False
257
Q
Maximum Depth of Binary Tree
# trees # graphs
Given the root of a binary tree, return its maximum depth.

A binary tree’s maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.

A
def maxDepth(self, root: TreeNode) -> int:
        if not root:
            return 0
        left = self.maxDepth(root.left)
        right = self.maxDepth(root.right)
        if left > right:
            return left + 1
        else:
            return right + 1
258
Q
Linked List Random Node
# linked lists # random
Given a singly linked list, return a random node's value from the linked list. Each node must have the same probability of being chosen.

Follow up:
What if the linked list is extremely large and its length is unknown to you? Could you solve this efficiently without using extra space?

Example:

// Init a singly linked list [1,2,3].
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
Solution solution = new Solution(head);
// getRandom() should return either 1, 2, or 3 randomly. Each element should have equal probability of returning.
solution.getRandom();
A

from random import random

class Solution:

    def \_\_init\_\_(self, head: ListNode):
        self.head = head
// метод резервуарной выборки
    def getRandom(self) -> int:
        cur_node = self.head
        counter = 1
        choice = -1
        while cur_node:
            if random() < 1/counter:
                choice = cur_node.val
            cur_node = cur_node.next
            counter += 1
        return choice
259
Q
Increasing Order Search Tree
# trees # graphs
Given the root of a binary search tree, rearrange the tree in in-order so that the leftmost node in the tree is now the root of the tree, and every node has no left child and only one right child.
A

// решение со стеком
def increasingBST(self, root: TreeNode) -> TreeNode:
self.nodes = []
def add_nodes(node):
if node:
self.nodes.append(TreeNode(node.val))
add_nodes(node.left)
add_nodes(node.right)
add_nodes(root)
self.nodes.sort(key=lambda i: i.val)
new_head = self.nodes[0]
cur_node = new_head
if len(self.nodes) > 1:
for i in range(len(self.nodes)):
cur_node.right = self.nodes[i]
cur_node = self.nodes[i]
return new_head

// обход инордер с генератором
def increasingBST(self, root: TreeNode) -> TreeNode:
        def inorder(node):
            if node:
                yield from inorder(node.left)
                yield node.val
                yield from inorder(node.right)
        res = cur = TreeNode(None)
        for v in inorder(root):
            cur.right = TreeNode(v)
            cur = cur.right
        return res.right
260
Q

Populating Next Right Pointers in Each Node II
# graphs # trees
Given a binary tree

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}
Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.

Initially, all next pointers are set to NULL.

Follow up:

You may only use constant extra space.
Recursive approach is fine, you may assume implicit stack space does not count as extra space for this problem.

A
// решение с обходом в ширину
class Solution:   
    def connect(self, root: 'Node') -> 'Node':
        tail = dummy = Node(0)
        cur = root
        while cur:
            tail.next = cur.left
            if tail.next:
                tail = tail.next
            tail.next = cur.right
            if tail.next:
                tail = tail.next
            cur = cur.next
            if not cur:
                tail = dummy
                cur = dummy.next
        return root
261
Q
Smallest Subtree with all the Deepest Nodes
# trees # graphs
Given the root of a binary tree, the depth of each node is the shortest distance to the root.

Return the smallest subtree such that it contains all the deepest nodes in the original tree.

A node is called the deepest if it has the largest depth possible among any node in the entire tree.

The subtree of a node is tree consisting of that node, plus the set of all descendants of that node.

A
// решение со вспомогательной рекурсивной функцией
def subtreeWithAllDeepest(self, root: TreeNode) -> TreeNode:
        self.lca = None
        self.deepest = 0
        def tree(node, depth):
// определяем максимальную глубину дерева
            self.deepest = max(self.deepest, depth)
            if not node:
                return depth
// определяем глубину левого и правого поддеревьев
            left = tree(node.left, depth + 1)
            right = tree(node.right, depth + 1)
// если глубины левого и правого поддерева равны максимальной, записываем текущую ноду как наименьшего общего предка
            if left == right == self.deepest:
                self.lca = node
// возвращаем максимум из левого/правого поддерева
            return max(left, right)
        tree(root, 0)
        return self.lca
262
Q
Swap Nodes in Pairs
# linked lists
Given a linked list, swap every two adjacent nodes and return its head.

You may not modify the values in the list’s nodes. Only nodes itself may be changed.

Input: head = [1,2,3,4]
Output: [2,1,4,3]

A
def swapPairs(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head
// создаем ноду-заглушку перед головой, делаем ее текущей
        dummy = ListNode(0, head)
        cur = dummy
// цикл, пока есть две след.ноды после текущей
        while cur.next and cur.next.next:
// первая нода - след. после текущей
            first = cur.next
// вторая нода - через текущую
            sec = cur.next.next
// делаем вторую ноду след.указателем текущей 
            cur.next = sec
// делаем след.указатель второй ноды след.указателем первой
            first.next = sec.next
// делаем первую ноду след.указателем второй
            sec.next = first
// сдвигаем текущую ноду через одну
            cur = cur.next.next
// возвращаем след.ноду после заглушки
        return dummy.next
263
Q
Decode Ways
# strings
A message containing letters from A-Z is being encoded to numbers using the following mapping:
'A' -> 1
'B' -> 2
...
'Z' -> 26
Given a non-empty string containing only digits, determine the total number of ways to decode it.

The answer is guaranteed to fit in a 32-bit integer.

Example 1:

Input: s = “12”
Output: 2
Explanation: It could be decoded as “AB” (1 2) or “L” (12).
Example 2:

Input: s = “226”
Output: 3
Explanation: It could be decoded as “BZ” (2 26), “VF” (22 6), or “BBF” (2 2 6).
Example 3:

Input: s = “0”
Output: 0
Explanation: There is no character that is mapped to a number starting with ‘0’. We cannot ignore a zero when we face it while decoding. So, each ‘0’ should be part of “10” –> ‘J’ or “20” –> ‘T’.
Example 4:

Input: s = “1”
Output: 1

A
def numDecodings(self, s: str) -> int:
// крайний случай, если строка пустая или начинается с 0
        if not s or s[0] == '0':
            return 0
// заводим переменные-счетчики
        w1 = 1
        w2 = 1
        curr = 0
// цикл по индексам от 1
        for i in range(1, len(s)):
// если текущий одиночный символ от 1 до 9, перезаписываем в текущий счетчик значение первого
            if '1'<= s[i] <= '9':
                curr = w1
// если пара символов образует число от 10 до 26, в текущий счетчик добавляем значение второго
            if '10' <= s[i-1:i+1] <= '26':
                curr += w2
// переопределяем счетчики: в первый записываем значение текущего, во второй значение первого, текущий обнуляем
            w1, w2, curr = curr, w1, 0
// возвращаем первый счетчик
        return w1
264
Q
Merge Sorted Array
# numbers # arrays
Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.

The number of elements initialized in nums1 and nums2 are m and n respectively. You may assume that nums1 has enough space (size that is equal to m + n) to hold additional elements from nums2.

Example 1:

Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]
Example 2:

Input: nums1 = [1], m = 1, nums2 = [], n = 0
Output: [1]

Constraints:

0 <= n, m <= 200
1 <= n + m <= 200
nums1.length == m + n
nums2.length == n
-109 <= nums1[i], nums2[i] <= 109
A

def merge(self, nums1, m, nums2, n):
// вставка с конца, аргументы-объемы массивов используем как индексы
// цикл, пока индексы положительные
while m > 0 and n > 0:
// если последнее ненулевое число первого массива не меньше последнего числа из второго, делаем его самым последним числом в первом массиве, уменьшаем первый индекс
if nums1[m-1] >= nums2[n-1]:
nums1[m+n-1] = nums1[m-1]
m -= 1
// иначе делаем последнее число из второго массива самым последним числом первого и уменьшаем второй индекс
else:
nums1[m+n-1] = nums2[n-1]
n -= 1
// если после цикла второй индекс все еще больше 0, записываем срез из второго массива в срез первого до этого индекса
if n > 0:
nums1[:n] = nums2[:n]

265
Q
Minimum Operations to Reduce X to Zero
# arrays # numbers
ou are given an integer array nums and an integer x. In one operation, you can either remove the leftmost or the rightmost element from the array nums and subtract its value from x. Note that this modifies the array for future operations.

Return the minimum number of operations to reduce x to exactly 0 if it’s possible, otherwise, return -1.

Example 1:

Input: nums = [1,1,4,2,3], x = 5
Output: 2
Explanation: The optimal solution is to remove the last two elements to reduce x to zero.
Example 2:

Input: nums = [5,6,7,8,9], x = 4
Output: -1
Example 3:

Input: nums = [3,2,20,1,1,3], x = 10
Output: 5
Explanation: The optimal solution is to remove the last three elements and the first two elements

A

// решение от обратного: ищем максимальную подпоследовательность, сумма которой равна разности суммы массива и исходного числа
def minOperations(self, nums: List[int], x: int) -> int:
target = sum(nums) - x
size = -1
win_sum = 0
n = len(nums)
end = -1
// цикл по индексам и числам в массиве
for start, num in enumerate(nums):
// в сумму скользящего окна прибавляем число
win_sum += num
// пока конечный индекс + 1 меньше длины массива и сумма окна больше таргета, увеличиваем конечный индекс и вычитаем из суммы окна число по конечному индексу
while end + 1 < n and win_sum > target:
end += 1
win_sum -= nums[end]
// если сумма окна равна таргету, определяем размер (максимум из текущего размера или разности начального и конечного индексов)
if win_sum == target:
size = max(size, start - end)
// возращаем -1, если размер меньше 0 иначе разности длины массива и размера подпоследовательности
return -1 if size < 0 else n - size

266
Q
Max Number of K-Sum Pairs
# numbers # arrays
You are given an integer array nums and an integer k.

In one operation, you can pick two numbers from the array whose sum equals k and remove them from the array.

Return the maximum number of operations you can perform on the array.

Example 1:

Input: nums = [1,2,3,4], k = 5
Output: 2
Explanation: Starting with nums = [1,2,3,4]:
- Remove numbers 1 and 4, then nums = [2,3]
- Remove numbers 2 and 3, then nums = []
There are no more pairs that sum up to 5, hence a total of 2 operations.
Example 2:

Input: nums = [3,1,3,4,3], k = 6
Output: 1
Explanation: Starting with nums = [3,1,3,4,3]:
- Remove the first two 3’s, then nums = [1,4,3]
There are no more pairs that sum up to 6, hence a total of 1 operation.

A
// решение с хеш-таблицей
def maxOperations(self, nums: List[int], k: int) -> int:
        if k == 1:
            return 0
// делаем словарь частотности чисел
        count = Counter(nums)
        res = 0
// цикл по ключам словаря
        for x in count:
// определяем второе число как разность К и ключа
            y = k - x
// если числа равны, то к результату прибавляем частотность ключа, деленную пополам
            if x == y:
                res += count[x]//2
            else:
// иначе если второе число есть в словаре, определяем минимальную частотность из двух чисел, прибавляем ее к результату и вычитаем из обоих чисел
                if y in count:
                    minval = min(count[x], count[y])
                    res += minval
                    count[x] -= minval
                    count[y] -= minval
        return res
267
Q
Longest Palindromic Substring
#strings
Given a string s, return the longest palindromic substring in s.

Example 1:

Input: s = “babad”
Output: “bab”
Note: “aba” is also a valid answer.
Example 2:

Input: s = “cbbd”
Output: “bb”
Example 3:

Input: s = “a”
Output: “a”
Example 4:

Input: s = “ac”
Output: “a”

Constraints:

1 <= s.length <= 1000
s consist of only digits and English letters (lower-case and/or upper-case),

A
// определяем центр палиндрома и пытаемся его увеличить в обе стороны
def longestPalindrome(self, s):
    lenS = len(s)
    if lenS <= 1: return s
// заводим переменные для минимального начального индекса, максимальной длины и текущего индекса
    minStart, maxLen, i = 0, 1, 0
// цикл, пока текущий индекс меньше длины строки
    while i < lenS:
// если разность длины строки и тек.индекса меньше-равна максимальной длине пополам, выходим из цикла
        if lenS - i <= maxLen // 2: break
// заводим еще два индекса, равные текущему
        j, k = i, i
// циклом увеличиваем индекс К, пока он меньше длины строки -1 и символ по этому индексу равен следующему
        while k < lenS - 1 and s[k] == s[k + 1]: k += 1
// текущий индекс делаем К+1
        i = k + 1
// циклом увеличиваем индекс К и уменьшаем индекс J, пока К меньше длины строки и J ненулевой, и символы по индексам К+1 и J-1 равны
        while k < lenS - 1 and j and s[k + 1] == s[j - 1]:  k, j = k + 1, j - 1
// если разность k-j+1 больше максимальной длины, мин.начальный индекс делаем J, в макс.длину записываем k-j+1
        if k - j + 1 > maxLen: minStart, maxLen = j, k - j + 1
// возвращаем срез от мин.начального индекса до мин.индекса+макс.длина
    return s[minStart: minStart + maxLen]
268
Q
Valid Parentheses
# strings
Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.

An input string is valid if:

Open brackets must be closed by the same type of brackets.
Open brackets must be closed in the correct order.

Example 1:

Input: s = “()”
Output: true
Example 2:

Input: s = “()[]{}”
Output: true
Example 3:

Input: s = “(]”
Output: false
Example 4:

Input: s = “([)]”
Output: false
Example 5:

Input: s = “{[]}”
Output: true

A
def isValid(self, s: str) -> bool:
        if len(s) == 1:
            return False
// составляем словарь соответствий скобок и заводим стек
        pairs = {')': '(', '}': '{', ']': '['}
        stack = []
// цикл по символам строки      
        for char in s:
// если символ - открывающая скобка, добавляем его в стек
            if char in "({[":
                stack.append(char)
// если символ - закрывающая скобка
            if char in ")}]":
// если стек пустой или последняя открывающая скобка не подходит, значит, строка не валидна
                if len(stack) == 0 or stack[-1] != pairs[char]:
                    return False
// удаляем последнюю скобку из стека
                stack.pop()
// если строка валидная, стек должен быть пустым
        return len(stack) == 0
269
Q
Find the Most Competitive Subsequence
# numbers # arrays
Given an integer array nums and a positive integer k, return the most competitive subsequence of nums of size k.

An array’s subsequence is a resulting sequence obtained by erasing some (possibly zero) elements from the array.

We define that a subsequence a is more competitive than a subsequence b (of the same length) if in the first position where a and b differ, subsequence a has a number less than the corresponding number in b. For example, [1,3,4] is more competitive than [1,3,5] because the first position they differ is at the final number, and 4 is less than 5.

Example 1:

Input: nums = [3,5,2,6], k = 2
Output: [2,6]
Explanation: Among the set of every possible subsequence: {[3,5], [3,2], [3,6], [5,2], [5,6], [2,6]}, [2,6] is the most competitive.
Example 2:

Input: nums = [2,4,3,3,5,4,9,6], k = 4
Output: [2,3,3,4]

Constraints:

1 <= nums.length <= 105
0 <= nums[i] <= 109
1 <= k <= nums.length

A
// решение с помощью стека
def mostCompetitive(self, nums: List[int], k: int) -> List[int]:
        N = len(nums)
        stack = []
// проходимся по индексам-числам массива
        for i, v in enumerate(nums):
// определяем, сколько осталось чисел (длина массива - текущий индекс)
            nums_left = N - i
// циклом удаляем из стека последнее число, пока он не пустой, последнее число больше текущего, а количество оставшихся чисел больше, чем К - длина стека
            while stack and stack[-1] > v and nums_left > k - len(stack):
                stack.pop()
// если стек меньше нужной длины, добавляем в него число
            if len(stack) < k:
                stack.append(v)
// в конце возвращаем стек
        return stack
270
Q

Merge k Sorted Lists
# lists # numbers
You are given an array of k linked-lists lists, each linked-list is sorted in ascending order.

Merge all the linked-lists into one sorted linked-list and return it.

Example 1:

Input: lists = [[1,4,5],[1,3,4],[2,6]]
Output: [1,1,2,3,4,4,5,6]
Explanation: The linked-lists are:
[
  1->4->5,
  1->3->4,
  2->6
]
merging them into one sorted list:
1->1->2->3->4->4->5->6
Example 2:

Input: lists = []
Output: []
Example 3:

Input: lists = [[]]
Output: []

Constraints:

k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] is sorted in ascending order.
The sum of lists[i].length won't exceed 10^4.
A
// решение "в лоб" - ноды всех списков добавляются в один большой массив, массив сортируется и из него делается связный список
def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        self.nodes = []
        head = point = ListNode(0)
        for l in lists:
            while l:
                self.nodes.append(l.val)
                l = l.next
        for x in sorted(self.nodes):
            point.next = ListNode(x)
            point = point.next
        return head.next
// использование очереди с приоритетом
from Queue import PriorityQueue
class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        head = point = ListNode(0)
        q = PriorityQueue()
        for l in lists:
            if l:
                q.put((l.val, l))
        while not q.empty():
            val, node = q.get()
            point.next = ListNode(val)
            point = point.next
            node = node.next
            if node:
                q.put((node.val, node))
        return head.next
// сливаем списки попарно, пока не получится один большой список
def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        amount = len(lists)
        interval = 1
        while interval < amount:
            for i in range(0, amount - interval, interval * 2):
                lists[i] = self.merge2Lists(lists[i], lists[i + interval])
            interval *= 2
        return lists[0] if amount > 0 else None
    def merge2Lists(self, l1, l2):
        head = point = ListNode(0)
        while l1 and l2:
            if l1.val <= l2.val:
                point.next = l1
                l1 = l1.next
            else:
                point.next = l2
                l2 = l1
                l1 = point.next.next
            point = point.next
        if not l1:
            point.next=l2
        else:
            point.next=l1
        return head.next
271
Q
Path With Minimum Effort
# matrices # numbers
You are a hiker preparing for an upcoming hike. You are given heights, a 2D array of size rows x columns, where heights[row][col] represents the height of cell (row, col). You are situated in the top-left cell, (0, 0), and you hope to travel to the bottom-right cell, (rows-1, columns-1) (i.e., 0-indexed). You can move up, down, left, or right, and you wish to find a route that requires the minimum effort.

A route’s effort is the maximum absolute difference in heights between two consecutive cells of the route.

Return the minimum effort required to travel from the top-left cell to the bottom-right cell.

A
def minimumEffortPath(self, heights: List[List[int]]) -> int:
        m = len(heights)
        n = len(heights[0])
        neibs = [[1,0], [0,1], [-1,0], [0,-1]]

// обход в глубину
def dfs(limit, x, y):
// в список посещенных добавляем текущие координаты
visited.add((x,y))
// проходимся по соседям
for dx, dy in neibs:
// если координаты в пределах размерности матрицы и точки нет в посещенных, проверяем, что абсолютная разница координат не превышает предел: тогда выполняем поиск в глубину по соседним точкам
if 0 <= dx+x < m and 0 <= dy + y < n and (dx+x, dy+y) not in visited:
if abs(heights[x][y]-heights[dx+x][dy+y]) <= limit:
dfs(limit, dx+x, dy+y)
// задаем начало и конец
beg = -1
end = max(max(heights, key = max))
// бинарный поиск для определения предела
while beg + 1 < end:
// определяем середину, заводим сет посещенных, выполняем поиск в глубину с начала, если крайняя правая точка в посещенных, делаем переопределяем конец, иначе переопределяем начало
mid = (beg+end)//2
visited = set()
dfs(mid, 0,0)
if (m-1, n-1) in visited:
end = mid
else:
beg = mid
return end

272
Q
Concatenation of Consecutive Binary Numbers
# numbers # binary
Given an integer n, return the decimal value of the binary string formed by concatenating the binary representations of 1 to n in order, modulo 109 + 7.

Example 1:

Input: n = 1
Output: 1
Explanation: “1” in binary corresponds to the decimal value 1.
Example 2:

Input: n = 3
Output: 27
Explanation: In binary, 1, 2, and 3 corresponds to “1”, “10”, and “11”.
After concatenating them, we have “11011”, which corresponds to the decimal value 27.
Example 3:

Input: n = 12
Output: 505379714
Explanation: The concatenation results in “1101110010111011110001001101010111100”.
The decimal value of that is 118505380540.
After modulo 109 + 7, the result is 505379714.

Constraints:

1 <= n <= 105

A
// решение с битовой манипуляцией
def concatenatedBinary(self, n: int) -> int:
        res = 0
        l = 0
        mod = 10**9+7
        for x in range(1, n+1):
            if x & (-x) == x:
                l += 1
            res = (res * (1 << l) + x) % mod
        return res
273
Q
Trim a Binary Search Tree
# trees # graphs
Given the root of a binary search tree and the lowest and highest boundaries as low and high, trim the tree so that all its elements lies in [low, high]. Trimming the tree should not change the relative structure of the elements that will remain in the tree (i.e., any node's descendant should remain a descendant). It can be proven that there is a unique answer.

Return the root of the trimmed binary search tree. Note that the root may change depending on the given bounds.

A
// рекурсивное решение
def trimBST(self, root: TreeNode, low: int, high: int) -> TreeNode:
// если нет ноды, возвращаем null
        if not root:
            return None
// если значение ноды больше верхнего порога, рекурсивно обходим левое поддерево и возвращаем его
        elif root.val > high:
            return self.trimBST(root.left, low, high)
// если значение ноды меньше нижнего порога, рекурсивно обходим правое поддерево и возвращаем его
        elif root.val < low:
            return self.trimBST(root.right, low, high)
// иначе рекурсивно обходим левое и правое поддеревья и возвращаем вершину
        else:
            root.left = self.trimBST(root.left, low, high)
            root.right = self.trimBST(root.right, low, high)
            return root
274
Q
Copy List with Random Pointer
# linked lists
A linked list of length n is given such that each node contains an additional random pointer, which could point to any node in the list, or null.

Construct a deep copy of the list. The deep copy should consist of exactly n brand new nodes, where each new node has its value set to the value of its corresponding original node. Both the next and random pointer of the new nodes should point to new nodes in the copied list such that the pointers in the original list and copied list represent the same list state. None of the pointers in the new list should point to nodes in the original list.

For example, if there are two nodes X and Y in the original list, where X.random –> Y, then for the corresponding two nodes x and y in the copied list, x.random –> y.

Return the head of the copied linked list.

The linked list is represented in the input/output as a list of n nodes. Each node is represented as a pair of [val, random_index] where:

val: an integer representing Node.val
random_index: the index of the node (range from 0 to n-1) that the random pointer points to, or null if it does not point to any node.
Your code will only be given the head of the original linked list.

A
class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        if not head:
            return
        // добавляем доп. ноды в исходный список
        curr = head 
        while curr != None: 
            new = Node(curr.val) 
            new.next = curr.next
            curr.next = new 
            curr = curr.next.next
        // добавляем случайные указатели к новым нодам
        curr = head 
        while curr != None:
            if curr.random:
                curr.next.random = curr.random.next
            curr = curr.next.next
        // отделяем клон списка от оригинала
        curr = head
        new_head = head.next
        while curr.next != None: 
            tmp = curr.next
            curr.next = curr.next.next
            curr = tmp 
        return new_head
275
Q
Search a 2D Matrix II
# matrices
Write an efficient algorithm that searches for a target value in an m x n integer matrix. The matrix has the following properties:

Integers in each row are sorted in ascending from left to right.
Integers in each column are sorted in ascending from top to bottom.

A
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        if not matrix:
            return False
        m = len(matrix)
        n = len(matrix[0])
        y = m-1
        x = 0
        while x < n and y >= 0:
            if matrix[y][x] == target:
                return True
            elif matrix[y][x] < target:
                x += 1
            else:
                y -= 1
        return False
276
Q
Validate Stack Sequences
# arrays
Given two sequences pushed and popped with distinct values, return true if and only if this could have been the result of a sequence of push and pop operations on an initially empty stack.

Example 1:

Input: pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
Output: true
Explanation: We might do the following sequence:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1

A
def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool:
        i = j = 0
        for x in pushed:
            pushed[i] = x
            while i >= 0 and pushed[i] == popped[j]:
                i, j = i - 1, j + 1
            i += 1
        return i == 0
277
Q
Intersection of Two Linked Lists
# linked lists
Write a program to find the node at which the intersection of two singly linked lists begins.
A
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        curA = headA
        curB = headB
        while curA != curB:
            curA = headB if not curA else curA.next
            curB = headA if not curB else curB.next
        return curA