ar
Feedback
Python | LeetCode

Python | LeetCode

الذهاب إلى القناة على Telegram
9 395
المشتركون
-124 ساعات
-187 أيام
-5630 أيام
أرشيف المشاركات
Задача: 45. Jump Game II #Medium Условие:
Вам предоставляется массив целых чисел nums с индексом 0 и длиной n. Изначально вы располагаетесь в nums[0]. Каждый элемент nums[i] представляет максимальную длину прямого перехода от индекса i. Другими словами, если вы находитесь в nums[i], вы можете перейти к любому nums[i + j], где: 0 <= j <= nums[i] иi + j < n Возвращает минимальное количество переходов для достижения nums[n - 1]. Тестовые примеры генерируются таким образом, чтобы вы могли достичь nums[n - 1].
Решение:
class Solution: 
  def jump(self, nums: List[int]) -> int: 
    ans = 0 
    end = 0 
    farthest = 0 
 
    # Implicit BFS 
    for i in range(len(nums) - 1): 
      farthest = max(farthest, i + nums[i]) 
      if farthest >= len(nums) - 1: 
        ans += 1 
        break 
      if i == end:      # Visited all the items on the current level 
        ans += 1        # Increment the level 
        end = farthest  # Make the queue size for the next level 
 
    return ans
Пояснение: 1. Инициализируем ans как 0, который будет хранить количество прыжков. 2. Инициализируем end как 0, который будет хранить границу текущего уровня прыжков. 3. Инициализируем farthest как 0, который будет хранить самую дальнюю позицию, достижимую с текущего уровня прыжков. 4. Перебираем элементы массива nums до предпоследнего элемента: - Обновляем farthest как максимум из текущего farthest и текущей позиции i плюс значение nums[i]. - Если farthest больше или равен длине массива минус 1 (последний индекс), значит, мы достигли конца, и увеличиваем ans на 1. - Если i равно end, значит, мы завершили текущий уровень прыжков, и увеличиваем ans на 1. Также обновляем end до farthest, чтобы обозначить границу следующего уровня. 5. Возвращаем ans.

Задача: 46. Permutations #Medium Условие:
Учитывая массив nums, состоящий из различных целых чисел, верните все возможные перестановки. Вы можете вернуть ответ в любом порядке.
Решение:
class Solution: 
    def permute(self, nums: List[int]) -> List[List[int]]: 
        result = [] 
 
        def permute_rec(nums, current_index, result): 
            if current_index == len(nums) - 1: 
                result.append(nums.copy()) 
                return 
 
            for index in range(current_index, len(nums)): 
                nums[current_index], nums[index] = nums[index], nums[current_index] 
                permute_rec(nums, current_index + 1, result) 
                nums[current_index], nums[index] = nums[index], nums[current_index] 
 
        permute_rec(nums, 0, result) 
        return result
Пояснение: 1. Инициализируем список result для хранения результирующих перестановок. 2. Определяем рекурсивную функцию permute_rec(nums, current_index, result): - Базовый случай: Если current_index достигает последнего индекса массива, значит мы нашли перестановку, и добавляем копию текущего массива nums в result. - В цикле перебираем все элементы массива, начиная с current_index. Для каждого элемента: - Меняем местами текущий элемент и элемент на индексе index. - Вызываем permute_rec с обновленным массивом и увеличенным current_index. - Меняем местами элементы обратно. 3. Вызываем permute_rec(nums, 0, result) для запуска рекурсии с начальным индексом 0. 4. Возвращаем result, содержащий все перестановки массива.

Задача: №20. Valid Parentheses #easy Условие:
Учитывая строку s, содержащую только символы '(', ')', '{', '}', '[' и ']', определите, является ли входная строка допустимой. Входная строка действительна, если: Открытые скобки должны закрываться скобками того же типа. Открытые скобки должны закрываться в правильном порядке. Каждой закрывающей скобке соответствует открытая скобка того же типа.
Решение:
  def isValid(self, s: str) -> bool:
        dic = {'(':1 , ')':2 , '[':3 , ']':6 , '{':5 , '}':10}
        res = []
        for one in s:
            temp = dic[one]
            if(temp %2 ):
                res.append(temp)
            else:
                if(len(res) and res[-1]==temp//2):
                    del res[-1]
                else:
                    return False
        return res==[]
Пояснение: Определение маппинга: Словарь dic используется для сопоставления каждой скобке их числового представления. Открывающие скобки ('(', '[', '{') получают нечётные значения, а закрывающие скобки (')', ']', '}') — соответствующие четные значения, вдвое большие их. Обработка строки: Перебираем каждый символ в строке s. Для каждого символа получаем его числовое значение из словаря dic. Проверка на открывающую скобку: Если значение символа нечётное, это открывающая скобка. Мы добавляем это значение в список res. Проверка на закрывающую скобку: Если значение символа четное, это закрывающая скобка. Мы проверяем: Если список res не пуст и последний элемент в списке равен половине текущего значения (что означает, что открывающая скобка соответствует закрывающей скобке), удаляем последний элемент из списка res. Если это не так, возвращаем False, так как закрывающая скобка не соответствует последней открывающей скобке. Завершение: Если после обработки всей строки список res пуст, это значит, что все скобки корректно закрыты, и возвращаем True. Если список res не пуст, это означает, что остались незакрытые открывающие скобки, и возвращаем False. Временная и пространственная сложность: Временная сложность: O(n), где n — длина строки. Мы проходим по строке один раз. Пространственная сложность: O(n), где n — количество открывающих скобок, так как в худшем случае все они могут оказаться в списке res.

Задача: №19. Remove Nth Node From End of List #medium Условие:
Учитывая заголовок связанного списка, удалите n-й узел из конца списка и верните его заголовок.
Решение:
# class ListNode:
#     def init(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        if head.next == None:
            return None
        tmp = head
        size = 0
        
        # find the size of the linked list
        while tmp:
            size += 1
            tmp = tmp.next
        tmp = head
        
        #if we have to remove the first node:
        if n == size: 
            return head.next
        
        for i in range(size-n-1):
            tmp = tmp.next
        tmp.next = tmp.next.next
        return head
Пояснение: Определение размера списка: Сначала мы проходимся по всему списку, чтобы найти его размер. Это необходимо, чтобы определить, какой узел нужно удалить. Переменная size отслеживает количество узлов в списке. Удаление первого узла: Если n равно размеру списка, это означает, что нужно удалить первый узел. В этом случае возвращаем следующий узел от головы списка. Поиск узла перед нужным для удаления: Если n не равен размеру списка, нам нужно найти узел, который идет перед n-м узлом с конца. Мы делаем это, перемещаясь на size-n-1 узлов вперед в списке. Удаление узла: Устанавливаем следующий узел для найденного узла так, чтобы он указывал на следующий за следующим узел, effectively bypassing the node to be deleted. Возвращение нового заголовка: Возвращаем голову списка. Если был удален первый узел, новый заголовок будет начальным узлом списка после удаления. Временная и пространственная сложность: Временная сложность: O(L), где L — длина списка. Мы проходим по списку дважды: один раз для подсчета узлов и второй раз для удаления узла. Пространственная сложность: O(1), поскольку мы используем константное количество дополнительного пространства, не зависящего от размера входных данных.

Задача: №18. 4Sum #medium Условие:
Учитывая массив nums из n целых чисел, верните массив всех уникальных четверок [nums[a], nums[b], nums[c], nums[d]] таких, что: 0 <= a, b, c, d < n a, b, c и d различны. nums[a] + nums[b] + nums[c] + nums[d] == цель Вы можете вернуть ответ в любом порядке.
Решение:
```def fourSum(self, nums, target):
    nums.sort()
    results = []
    self.findNsum(nums, target, 4, [], results)
    return results

def findNsum(self, nums, target, N, result, results):
    if len(nums) < N or N < 2: return

    # solve 2-sum
    if N == 2:
        l,r = 0,len(nums)-1
        while l < r:
            if nums[l] + nums[r] == target:
                results.append(result + [nums[l], nums[r]])
                l += 1
                r -= 1
                while l < r and nums[l] == nums[l - 1]:
                    l += 1
                while r > l and nums[r] == nums[r + 1]:
                    r -= 1
            elif nums[l] + nums[r] < target:
                l += 1
            else:
                r -= 1
    else:
        for i in range(0, len(nums)-N+1):   # careful about range
            if target < nums[i]*N or target > nums[-1]*N:  # take advantages of sorted list
                break
            if i == 0 or i > 0 and nums[i-1] != nums[i]:  # recursively reduce N
                self.findNsum(nums[i+1:], target-nums[i], N-1, result+[nums[i]], results)
    return
```

Пояснение: Сортировка: Сначала массив nums сортируется. Сортировка упрощает обработку дубликатов и ускоряет выполнение с помощью двоичного поиска. Рекурсивная функция findNsum: Функция findNsum рекурсивно находит комбинации, сумма которых равна заданному target. В зависимости от значения N, она обрабатывает различные случаи: Для N = 2: Это подзадача "Two Sum". Мы используем два указателя (l и r), чтобы найти пары чисел в массиве, которые суммируются до target. Если текущая пара чисел nums[l] и nums[r] суммируется до target, добавляем эту пару к результатам. Двигаем указатели влево и вправо, пропуская дубликаты, чтобы избежать повторных комбинаций. Для N > 2: Функция рекурсивно вызывает себя, уменьшая N на 1 и продолжая искать комбинации среди оставшихся элементов массива. Мы также проверяем, находятся ли текущий элемент и его комбинации в допустимом диапазоне (для оптимизации). Условия выхода из рекурсии: Если длина массива меньше N или N меньше 2, функция завершает выполнение, так как это не имеет смысла для дальнейшего поиска комбинаций. Мы используем условия, чтобы прекратить выполнение, если текущий элемент слишком велик или слишком мал для достижения целевого значения при данном числе элементов (N). Уникальные комбинации: Чтобы избежать дубликатов, проверяем, является ли текущий элемент уникальным по сравнению с предыдущими. Сбор результатов: Результаты для каждого вызова функции findNsum добавляются в общий список results.

Задача: №17. Letter Combinations of a Phone Number #medium Условие:
Учитывая строку, содержащую цифры от 2 до 9 включительно, верните все возможные комбинации букв, которые может представлять число. Верните ответ в любом порядке. Соответствие цифр буквам (как на кнопках телефона) приведено ниже. Обратите внимание, что 1 не соответствует никаким буквам.
Решение:
class Solution(object):
    def subsetsWithDup(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        res = []
        nums.sort()
        self.dfs(nums, [], res)
        return res
    
    def dfs(self, nums, path, res):
        res.append(path)
        for i in range(len(nums)):
            if i > 0 and nums[i] == nums[i-1]:
                continue
            self.dfs(nums[i+1:], path + [nums[i]], res)
Пояснение: Сортировка: Сначала мы сортируем массив nums. Сортировка помогает легко обрабатывать дубликаты, так как одинаковые элементы будут расположены рядом. Рекурсивный метод dfs: Метод dfs используется для рекурсивного построения всех возможных подмножеств. В dfs, path представляет текущее подмножество, а res — список всех подмножеств. Добавление подмножества в результат: На каждом уровне рекурсии мы добавляем текущее подмножество path в результат res. Обработка дубликатов: Перед продолжением рекурсии проверяем, является ли текущий элемент nums[i] дубликатом предыдущего элемента. Если это так, пропускаем его, чтобы избежать повторного добавления одинаковых подмножеств в res. Рекурсивное построение подмножеств: Для каждого элемента в nums, начиная с текущего индекса, мы вызываем dfs для следующих элементов массива (nums[i+1:]). Это означает, что мы рассматриваем подмножества, включающие текущий элемент, и продолжаем строить подмножества без текущего элемента. Путь (path) и отсек (nums): Каждый раз при вызове dfs создается новое подмножество, добавляя текущий элемент к path. Затем этот новый список передается в следующий уровень рекурсии, что позволяет построить все возможные подмножества. Временная и пространственная сложность: Временная сложность: O(2^n), где n — количество элементов в nums. Это связано с тем, что существует 2^n подмножеств для массива из n элементов. Пространственная сложность: O(2^n * n), так как для каждой из 2^n возможных подмножеств может потребоваться до n элементов для хранения.

Задача: №16. 3Sum Closest #medium Условие:
Учитывая целочисленный массив nums длины n и целочисленную цель, найдите три целых числа в nums, сумма которых наиболее близка к цели. Возвращает сумму трех целых чисел. Вы можете предположить, что каждый вход будет иметь ровно одно решение.
Решение:
```class Solution:
    def threeSumClosest(self, num, target):
        num.sort()
        result = num[0] + num[1] + num[2]
        for i in range(len(num) - 2):
            j, k = i+1, len(num) - 1
            while j < k:
                sum = num[i] + num[j] + num[k]
                if sum == target:
                    return sum
                
                if abs(sum - target) < abs(result - target):
                    result = sum
                
                if sum < target:
                    j += 1
                elif sum > target:
                    k -= 1
                else:
                    return result
            
        return result
```

Пояснение: Сортировка массива: Сначала мы сортируем массив num. Это позволит нам использовать два указателя для нахождения наиболее близкой суммы. Инициализация результата: Инициализируем переменную result суммой первых трех элементов отсортированного массива. Это будет нашей начальной ближайшей суммой. Проход по массиву: Используем цикл for, чтобы пройти по массиву. Для каждого элемента используем два указателя j и k: j начинается сразу после текущего элемента i. k начинается с конца массива. Два указателя: Внутри цикла while, пока j меньше k, вычисляем сумму sum элементов num[i], num[j] и num[k]. Если сумма sum равна target, то возвращаем sum, так как мы нашли точное соответствие. Обновление результата: Если текущая сумма sum ближе к target, чем предыдущая ближайшая сумма result, обновляем result. Сдвиг указателей: Если sum меньше target, сдвигаем указатель j вправо, чтобы увеличить сумму. Если sum больше target, сдвигаем указатель k влево, чтобы уменьшить сумму. Возврат результата: После завершения всех итераций возвращаем result, которая будет содержать сумму трех чисел, ближайшую к target. Временная и пространственная сложность: Временная сложность: O(n^2), где n — длина массива. Сортировка занимает O(n log n), и основной алгоритм с двумя указателями выполняется за O(n^2). Пространственная сложность: O(1), так как мы используем только несколько дополнительных переменных, и не используем дополнительную память, зависящую от размера входных данных.