en
Feedback
Python | LeetCode

Python | LeetCode

Open in Telegram

Сайт: https://easyoffer.ru/ Все каналы: t.me/+xGeAw6ckJ4liYzQy Контакт для рекламы: @easyoffer_adv

Show more
9 118
Subscribers
-124 hours
-297 days
-9330 days
Posts Archive
Задача: 24. Swap Nodes in Pairs #medium Условие:
Учитывая связанный список, поменяйте местами каждые два соседних узла и верните его голову. Вы должны решить проблему, не изменяя значения в узлах списка (т. е. изменять можно только сами узлы).
Решение:
 def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]: 
        if  not (head and head.next): 
            return head 
        head, head.next, head.next.next = head.next, head, self.swapPairs(head.next.next) 
        return head
Пояснение:
1. Функция swapPairs принимает на вход головной узел связного списка head и возвращает новую голову списка после перестановки пар узлов. 2. Сначала проверяется, есть ли головной узел head и есть ли следующий за ним узел head.next. Если нет, то возвращается исходный head, так как нечего менять. 3. Если есть как минимум два узла, то происходит перестановка: - Временная переменная temp сохраняет второй узел head.next. - Головной узел head становится третьим узлом, а его следующий узел head.next становится первым узлом. - Следующий за вторым узлом указатель head.next.next обновляется рекурсивным вызовом self.swapPairs(head.next.next), чтобы перестроить оставшуюся часть списка. - Головной узел head возвращается в качестве новой головы списка. 4. Рекурсивный вызов self.swapPairs(head.next.next) будет происходить, пока не останется меньше двух узлов в списке. Это обеспечивает перестановку всех пар узлов.

📌 Составили список лучших каналов от действующих разработчиков: Python Developer — советы и практики от действующего Senior-
📌 Составили список лучших каналов от действующих разработчиков: Python Developer — советы и практики от действующего Senior-разработчика Java Developer — секреты и тонкости программирования на Java Frontend Developer — готовый код и полезные ресурсы для любого фронтендера

😮 Добавлена новая база слитых курсов на 800ГБ: Python: https://t.me/+-3O1svHQCGUxNWYy Программирование: https://t.me/+1VPcMAgJ7oliYmQy Frontend и Web: https://t.me/+viU1cwWNrNE2YWIy Графика и дизайн: https://t.me/+28fE7chaCHRhZTYy

Задача: 23. Merge k Sorted Lists #medium Условие:
Вам дан массив из k списков связанных списков, каждый связанный список отсортирован в порядке возрастания.Объедините все связанные списки в один отсортированный связанный список и верните его.
Решение:
class ListNode: 
    def init(self, val=0, next=None): 
        self.val = val 
        self.next = next 
class Solution: 
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: 
        n = len(lists) 
 
        newList = ListNode() 
        new = newList 
 
        while n: 
            # Find list with smallest value: 
            smallestNode = ListNode(float('inf')) 
            smallestIndex = -1 
            for i in range(n): 
                listNode = lists[i] 
                if listNode and listNode.val < smallestNode.val: 
                    smallestNode = listNode 
                    smallestIndex = i 
             
            if smallestIndex == -1: 
                break 
             
            new.next = ListNode(smallestNode.val) 
            new = new.next 
 
            if smallestNode.next: 
                lists[smallestIndex] = smallestNode.next 
            else: 
                lists.pop(smallestIndex) 
                n-=1 
                 
        return newList.next 
Пояснение:
1. Определяется класс ListNode, который представляет узел связного списка. У него есть два атрибута: val (значение узла) и next (ссылка на следующий узел). 2. Определяется класс Solution, который содержит метод mergeKLists. 3. Метод mergeKLists принимает на вход список lists, который является списком связных списков. Каждый список в lists является необязательным (Optional[ListNode]). 4. Вначале определяется длина списка lists и сохраняется в переменной n. 5. Создается новый связный список newList и переменная new, которая будет указывать на последний добавленный узел в newList. 6. Запускается цикл, который продолжается, пока n (количество списков в lists) не станет равным 0. 7. Внутри цикла производится поиск списка с наименьшим значением в первом узле. Для этого: - Создается переменная smallestNode со значением бесконечности. - Создается переменная smallestIndex со значением -1. - Перебираются все списки в lists. - Если текущий список не пуст и значение в его первом узле меньше, чем в smallestNode, то smallestNode и smallestIndex обновляются. 8. Если smallestIndex равен -1, это означает, что все списки в lists пусты, поэтому цикл завершается. 9. Иначе создается новый узел с значением, взятым из smallestNode, и добавляется в конец newList. 10. Если у smallestNode есть следующий узел, то соответствующий список в lists обновляется, чтобы указывать на этот следующий узел. Если у smallestNode нет следующего узла, то этот список удаляется из lists, и n уменьшается на 1. 11. После завершения цикла возвращается newList.next, так как первый узел newList был пустым вспомогательным узлом.

Задача: 22. Generate Parentheses #medium Условие:
Учитывая n пар круглых скобок, напишите функцию, которая генерирует все комбинации правильных круглых скобок.
Решение:
def generateParenthesis(self, n: int) -> List[str]: 
  def dfs(left, right, s): 
    if len(s) == n * 2: 
      res.append(s) 
      return  
 
    if left < n: 
      dfs(left + 1, right, s + '(') 
 
    if right < left: 
      dfs(left, right + 1, s + ')') 
 
  res = [] 
  dfs(0, 0, '') 
  return res
Пояснение:
1. Функция generateParenthesis принимает на вход целое число n, которое представляет количество пар скобок, которые нужно сгенерировать. 2. Внутри функции есть вспомогательная функция, называемая dfs (Depth-First Search). Эта функция выполняет фактическую генерацию скобок. 3. Функция dfs принимает три параметра: - left: количество открывающих скобок в текущей строке. - right: количество закрывающих скобок в текущей строке. - s: текущая строка скобок. 4. Базовый случай рекурсии - когда длина строки s равна n * 2, что означает, что мы сгенерировали полную строку скобок. В этом случае мы добавляем текущую строку s в список res и выходим из функции. 5. Первый рекурсивный случай - когда left меньше n. Это значит, что мы можем добавить открывающую скобку к строке. Поэтому мы вызываем dfs с left + 1, right без изменений и s + '('. 6. Второй рекурсивный случай - когда right меньше left. Это означает, что мы можем добавить закрывающую скобку к строке, так как количество закрывающих скобок меньше количества открывающих. Поэтому мы вызываем dfs с left без изменений, right + 1 и s + ')'. 7. Функция dfs первоначально вызывается с left = 0, right = 0 и пустой строкой ''. 8. Рекурсивные вызовы продолжаются, пока не будет достигнут базовый случай, и все допустимые сочетания скобок будут добавлены в список res. 9. Наконец, функция generateParenthesis возвращает список res, содержащий все допустимые строки скобок длины n * 2.

Задача: №21. Merge Two Sorted Lists #easy Условие:
Вам даны заголовки двух отсортированных связанных списков list1 и list2. Объедините два списка в один отсортированный список. Список должен быть составлен путем сращивания узлов первых двух списков. Возвращает заголовок объединенного связанного списка.
Решение:
class Solution(object):
    def mergeTwoLists(self, l1, l2):
        dummy = ListNode(0)  
        cur = dummy  
        while l1 and l2:  
            if l1.val <= l2.val:  
                cur.next = l1  
                l1 = l1.next  
            else:  
                cur.next = l2  
                l2 = l2.next  
            cur = cur.next  
        cur.next = l1 or l2  
  
        return dummy.next  
Пояснение: Создание фиктивного узла: Создается фиктивный узел dummy для упрощения операции добавления узлов к результатирующему списку. Этот узел будет служить началом итогового списка. Указатель cur инициализируется на dummy и будет использоваться для построения итогового списка. Слияние списков: Цикл выполняется до тех пор, пока не достигнут конец одного из списков (l1 или l2). Внутри цикла происходит сравнение значений текущих узлов двух списков: Если значение узла из списка l1 меньше или равно значению узла из списка l2, то узел из списка l1 присоединяется к итоговому списку. Иначе, узел из списка l2 присоединяется к итоговому списку. Перемещение указателя cur вперед для добавления следующего узла. Добавление оставшихся узлов: После завершения цикла один из списков может быть непустым. В этом случае остается добавить оставшиеся узлы этого списка к итоговому списку. Это делается с помощью cur.next = l1 or l2, что означает, что если l1 не пуст, то добавляются узлы из l1, иначе добавляются узлы из l2. Возвращение результата: Возвращается следующий узел от фиктивного узла, что представляет собой начальный узел итогового списка, который содержит все элементы из обоих списков в отсортированном порядке. Временная и пространственная сложность: Временная сложность: O(n + m), где n и m — количество узлов в l1 и l2 соответственно. Этот алгоритм проходит через каждый узел списков один раз. Пространственная сложность: O(1) для дополнительных данных, так как используется только фиксированное количество переменных для указателей и временных операций.

Задача: 44. Wildcard Matching #Hard Условие:
При наличии входных строк и шаблона (p) реализуйте сопоставление шаблонов с подстановочными знаками с поддержкой "?" и "*", где: "?" Соответствует любому отдельному символу."*" Соответствует любой последовательности символов (включая пустую последовательность). Соответствие должно охватывать всю входную строку (не частичное).
Решение:
class Solution: 
    def isMatch(self, s: str, p: str) -> bool: 
        memo = [[None] * (len(p) + 1) for _ in range(len(s) + 1)] 
        return self.f(s, 0, p, 0, memo) 
     
    def f(self, s, i, p, j, memo): 
        if i == len(s) and j == len(p): //both strings end : match successfull 
            return True 
 
        //Pattern is over but string is left: match unsuccessful. 
        //Point to note : if String is over and pattern is left, 
        //it 'might' still be possible to match the string. 
        //Take for eg. s = "" and p = "*******".  
        if j == len(p):  
            return False 
         
        if memo[i][j] is None:  //subproblem not solved earlier. 
            flag = False 
 
            //match single character, but string s should be left, 
            //else we get IndexError 
            if i < len(s) and (s[i] == p[j] or p[j] == '?'):  
                flag = self.f(s, i + 1, p, j + 1, memo) 
 
            elif p[j] == '*':   // can match variable no. of characters, so loop over them and see when it matches. 
                for t in range(i, len(s) + 1): 
                    if self.f(s, t, p, j + 1, memo): 
                        flag = True 
                        break 
            //if it doesn't ever match, the flag will be False by default. 
            memo[i][j] = flag 
 
        return memo[i][j] 
        
Пояснение: 1. Динамическое программирование: Используем двумерный массив memo для хранения промежуточных результатов. 2. Рекурсивная функция f: Определяем рекурсивную функцию f(s, i, p, j, memo), которая принимает следующие параметры: - s: Исходная строка. - i: Индекс текущего символа в s. - p: Шаблон. - j: Индекс текущего символа в p. - memo: Массив для хранения промежуточных результатов. 3. Рекурсивная логика: - Базовый случай: Если i и j достигли концов s и p соответственно, то строка соответствует шаблону. - Если j достиг конца p, но i не достиг конца s, то строка не соответствует шаблону. - Если memo[i][j] не равно None, то мы уже рассчитали результат для этих индексов и можем вернуть его. - Проверяем совпадение символов: - Если символы на индексах i в s и j в p совпадают или символ в p является подстановочным знаком ?, то мы двигаемся дальше. - Если символ в p является звездочкой *, то мы можем пропустить произвольное количество символов в s, поэтому перебираем все возможные варианты пропуска и проверяем соответствие. 4. Заполнение memo: Сохраняем результат для данного вызова f в массиве memo для использования в будущих вызовах.

Задача: 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), так как мы используем только несколько дополнительных переменных, и не используем дополнительную память, зависящую от размера входных данных.