coding_v2

动态规划

题目list【力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台】

coding_v2_第1张图片

  1. LC300:最长上升子序列【【LeetCode】最长上升子序列 python ★★★★★★_yingzoe的博客-CSDN博客_最长上升子序列python】


def solve(nums):
    if not nums:
        return -1
    l = len(nums)
    dp = [1] * l
    max_len = 1 # 长度至少也是1
    for i in range(1, l):
        for j in range(i):
            if nums[j] < nums[i]:
                dp[i] = max(dp[j]+1, dp[i])
                if dp[i] > max_len:
                    max_len = dp[i]
    return max_len
  1. 合唱团【合唱团(牛客) - 代码先锋网】


def solve(nums):
    num1 = kernel(nums)
    print(num1)
    num2 = kernel(nums[::-1])
    print(num2)
    res = []
    ans = -1
    for i in range(len(num1)):
        cur = num1[i] + num2[i] - 1
        res.append(cur)
        ans = max(ans, res[i])
    return len(nums) - ans
def kernel(nums):
    n = len(nums)
    dp = [1] * n
    res = 1
    for i in range(1, n):
        for j in range(i):
            if nums[i] > nums[j]:
                dp[i] = max(dp[j]+1, dp[i])
                res = max(res, dp[i])
    return dp
  1. LC674:最长连续递增序列【力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台】


def solve(nums):
    if not nums:
        return -1
    ans = 1
    l = len(nums)
    start = 0
    for i in range(l):
        if i > 0 and nums[i] <= nums[i-1]:
            start = i
        ans = max(ans, i - start + 1)
    return ans
  1. LC718:最长重复子数组


def solve(nums1, nums2):
    m ,n = len(nums1), len(nums2)
    dp = [[0] * (n + 1) for i in range(m+1)]
    ans = 0
    for i in range(m-1, -1, -1):
        for j in range(n-1, -1, -1):
            if nums1[i] == nums2[j]:
                dp[i][j] = dp[i+1][j+1] + 1
            else:
                dp[i][j] = 0
            ans = max(ans, dp[i][j])
    return ans
    
  1. LC1143:最长公共子序列


def solve(text1, text2):
    m, n = len(text1), len(text2)
    dp = [[0] * (n + 1) for i in range(m + 1)]
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if text1[i-1] == text2[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
    return dp[m][n]
  1. LC1035:不相交的线【本质为最长公共子序列】


def solve(nums1, nums2):
    m, n = len(nums1), len(nums2)
    dp = [[0] * (n + 1) for i in range(m + 1)]
    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if nums1[i-1] == nums2[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
    return dp[m][n]
  1. LC53:最大子序和【连续】


def solve(nums):
    pre = 0
    max_sum = nums[0]
    for each in nums:
        pre = max(pre + each, each) # 当前数字大,还是加上当前数字之前的一段大
        max_sum = max(pre, max_sum)
    return max_sum

def solve(nums):
    if not nums:
        return -1
    n = len(nums)
    dp = [0] * n
    dp[0] = nums[0]
    res = nums[0]
    for i in range(1, n):
        if dp[i-1] >= 0:
            dp[i] = dp[i-1] + nums[i]
        else:
            dp[i] = nums[i]
        res = max(res, dp[i])
    return res
  1. LC392:判断子序列


def solve(s, t):
    m, n = len(s), len(t)
    i = 0
    j = 0
    while i < m and j < n:
        if s[i] == t[j]:
            i += 1
        j += 1
    return i == m

# 动态规划(最长公共子序列,判断最长子序列长度是否等于m)
def solve(s, t):
    m, n = len(s), len(t)
    dp = [[0] * (n+1) for i in range(m+1)]
    max_len = 0
    for i in range(1, m+1):
        for j in range(1, n+1):
            if s[i-1] == t[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i-1][j], dp[i][j-1])
            max_len = max(max_len, dp[i][j])
    return max_len == m
  1. LC673:最长递增子序列个数


def solve(nums):
    n = len(nums)
    max_len = 0 # 最长长度
    ans = 0
    dp = [1] * n
    cnt = [1] * n
    for i in range(n):
        for j in range(i):
            if nums[i] > nums[j]:
                if dp[j] + 1 > dp[i]:
                    dp[i] = dp[j] + 1
                    cnt[i] = cnt[j]
                elif dp[j] + 1 == dp[i]:
                    cnt[i] += cnt[j]
        if dp[i] > max_len:
            max_len = dp[i]
            ans = cnt[i]
        elif dp[i] == max_len:
            ans += cnt[i]
    return ans
  1. LC72:编辑距离


def solve(word1, word2):
    m, n = len(word1), len(word2)
    dp = [[0] * (n + 1) for i in range(m + 1)]
    for i in range(1, m+1):
        dp[i][0] = dp[i-1][0] + 1
    for j in range(1, n + 1):
        dp[0][j] = dp[0][j-1] + 1
    for i in range(1, m+1):
        for j in range(1, n+1):
            if word1[i-1] == word2[j-1]:
                dp[i][j] = dp[i-1][j-1]
            else:
                dp[i][j] = min(dp[i-1][j-1] + 1, dp[i][j-1] + 1, dp[i-1][j] + 1)
    return dp[m][n]
  1. LC582:两个字符串的删除操作


# 方法1:dp
def solve(word1, word2):
    m, n = len(word1), len(word2)
    dp = [[0] * (n+1) for i in range(m+1)]
    for i in range(1, m+1):
        dp[i][0] = dp[i-1][0] + 1
    for j in range(1, n+1):
        dp[0][j] = dp[0][j-1] + 1
    for i in range(1, m+1):
        for j in range(1, n+1):
            if word1[i-1] == word2[j-1]:
                dp[i][j] = dp[i-1][j-1]
            else:
                dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1)
    return dp[m][n]

# 方法2:最长公共子序列
def solve(word1, word2):
    m, n = len(word1), len(word2)
    dp = [[0] * (n+1) for i in range(m+1)]
    for i in range(1, m+1):
        for j in range(1, n+1):
            if word1[i-1] == word2[j-1]:
                dp[i][j] = dp[i-1][j-1] + 1
            else:
                dp[i][j] = max(dp[i][j-1], dp[i-1][j])
    max_len = dp[m][n]
    res = m - max_len + n - max_len
    return res
  1. LC115:不同子序列的个数


# 不同子序列的个数(t是s的子序列)
def solve(s, t):
    m, n = len(s), len(t)
    if m < n:
        return 0
    dp = [[0] * (n+1) for i in range(m+1)] # dp[i][j]表示s[i:]在t[j:]中不同子序列的个数
    for i in range(m+1):
        dp[i][n] = 1
    for i in range(m-1, -1, -1):
        for j in range(n-1, -1, -1):
            if s[i] == t[j]:
                dp[i][j] = dp[i+1][j+1] + dp[i+1][j]
            else:
                dp[i][j] = dp[i+1][j]
    return dp[0][0]
  1. LC516:最长回文子序列


def solve(s):
    n = len(s)
    dp = [[0] * n for i in range(n)] # dp[i][j]表示s中i和j之间的字符串的最长回文子序列长度
    for i in range(n-1, -1, -1):
        dp[i][i] = 1
        for j in range(i+1, n):
            if s[i] == s[j]:
                dp[i][j] = dp[i+1][j-1] + 2
            else:
                dp[i][j] = max(dp[i+1][j], dp[i][j-1])
    return dp[0][n-1]
  1. LC5:最长回文子串


def solve(s):
    nums = s
    n = len(nums)
    if n < 2:
        return nums
    dp = [[0] * n for i in range(n)]
    max_len = 1
    begin = 0
    for i in range(n):
        dp[i][i] = 1
    for L in range(2, n+1):
        for i in range(n):
            j = i + L - 1
            if j >= n:
                break
            if nums[i] != nums[j]:
                dp[i][j] = 0
            else:
                if j - i < 3:
                    dp[i][j] = 1
                else:
                    dp[i][j] = dp[i+1][j-1]
            if dp[i][j] and L > max_len:
                max_len = L
                begin = i
    return nums[begin:begin+max_len]
  1. LC70:爬楼梯


def solve(n):
    if n < 3:
        return n
    f0 = 1
    f1 = 2
    for i in range(3, n+1):
        fn = f0 + f1
        f0 = f1
        f1 = fn
    return fn
  1. LC746:使用最小花费爬楼梯


def solve(cost):
    n = len(cost)
    dp = [0] * (n+1)
    for i in range(2, n+1):
        dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
    return dp[n]
  1. LC121:买卖股票最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。


def solve(prices):
    minPrice = 1e20
    maxProfit = -1
    for i in range(len(prices)):
        if prices[i] < minPrice:
            minPrice = prices[i]
        maxProfit = max(maxProfit, prices[i]-minPrice)
    return maxProfit
  1. LC122:买卖股票最佳时机2

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。


def solve(prices):
    n = len(prices)
    dp = [[0] * 2 for i in range(n)]
    dp[0][0] = 0
    dp[0][1] = -prices[0]
    for i in range(1, n):
        dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
        dp[i][1] = max(dp[i-1][0] - prices[i], dp[i-1][1])
    return dp[n-1][0]
  1. LC309:买卖股票最佳时机【含冷冻期】


'''
dp[i][0]:持有股票
dp[i][1]:不持有股票(不在冷冻期)
dp[i][2]:不持有股票(在冷冻期)
'''
def solve(prices):
    n = len(prices)
    dp = [[0] * 3 for i in range(n)]
    dp[0][0] = -prices[0]
    dp[0][1] = 0
    dp[0][2] = 0
    for i in range(1, n):
        dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])
        dp[i][1] = max(dp[i-1][1], dp[i-1][2])
        dp[i][2] = dp[i-1][0] + prices[i]
    return max(dp[n-1][1], dp[n-1][2])
  1. LC714:买卖股票最佳时机【含手续费】


'''
dp[i][0]:有股票
dp[i][1]:没有股票
'''
def solve(prices, fee):
    n = len(prices)
    dp = [[0] * 2 for i in range(n)]
    dp[0][0] = -prices[0]
    dp[0][1] = 0
    for i in range(1, n):
        dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])
        dp[i][1] = max(dp[i-1][0] + prices[i] - fee, dp[i-1][1])
    return dp[n-1][1]
  1. LC198:打家劫舍


def solve(nums):
    if not nums:
        return 0
    n = len(nums)
    if n == 1:
        return nums[0]
    dp = [0] * n
    dp[0] = nums[0]
    dp[1] = max(nums[0]. nums[1])
    for i in range(2, n):
        dp[i] = max(dp[i-1], dp[i-2]+nums[i])
    return dp[-1]
  1. LC983:最低票价


def solve(days, costs):
    maxDays = days[-1]
    dp = [0] * (maxDays + 31) #防止越界
    for d in range(maxDays, -1, -1):
        if d in days:
            dp[d] = min(dp[d+1] + costs[0], dp[d+7]+costs[1], dp[d+30]+costs[2])
        else:
            dp[d] = dp[d+1]
    return dp[0]

位运算、数组

  1. LC136:只出现一次的数字(只有一个数字出现一次,其他均出现两次)


def solve(nums):
    res = nums[0]
    n = len(nums)
    for i in range(1, n):
        res = res ^ nums[i]
    return res
  1. LC268:丢失的数字(给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。)


def solve(nums):
    ans = 0
    for i in range(len(nums)):
        ans = ans ^ nums[i]
    for i in range(len(nums)+1):
        ans = ans ^ i
#         print(i, nums[i])
#         print(ans)
    return ans
  1. LC141:环形链表


# 哈希
def solve(head):
    seen = set()
    while head:
        if head in seen:
            return True
        else:
            seen.add(head)
            head = head.next
    return False

# 快慢指针
def solve(head):
    if not head or not head.next:
        return False
    slow = head
    fast = head.next
    while slow != fast:
        if not fast or not fast.next:
            return False
        slow = slow.next
        fast = fast.next.next
    return True
  1. LC142:环形链表2【若有环,寻找环的入口】


def solve(head):
    fast, slow = head, head
    while True:
        if not fast or not fast.next:
            return None
        fast = fast.next.next
        slow = slow.next
        if fast == slow:
            break
    fast = head
    while fast != slow:
        fast = fast.next
        slow = slow.next
    return fast

数组、二分、双指针

  1. LC26:原地删除有序数组重复值


def solve(nums):
    n = len(nums)
    slow, fast = 1, 1
    while fast < n:
        if nums[fast] != nums[fast-1]:
            nums[slow] = nums[fast]
            slow += 1
        fast += 1
    return slow
  1. 剑指11:旋转数组最小值


def solve(numbers):
    low, high = 0, len(numbers) - 1
    while low <= high:
        if numbers[low] < numbers[high]:
            return numbers[low] # 如果是有序数组 直接返回numbers[low]
        mid = (low + high) // 2
        if numbers[mid] > numbers[low]:
            low = mid + 1
        elif numbers[mid] < numbers[low]:
            high = mid
        else:
            low += 1
    return numbers[mid]
  1. LC33:搜索排序旋转数组【无重复值】


# 先寻找有序的一部分
def solve(nums, target):
    low, high = 0, len(nums) - 1
    while low <= high:
        mid = (low + high) // 2
        if nums[mid] == target:
            return mid
        if nums[mid] >= nums[low]: # 注意等号
            if target < nums[mid] and target >= nums[low]:
                high = mid - 1
            else:
                low = mid + 1
        else:
            if target > nums[mid] and target <= nums[len(nums)-1]:
                low = mid + 1
            else:
                high = mid - 1
    return -1
  1. LC81:搜索排序旋转数组【有重复值】


# 先寻找有序的一部分
def solve(nums, target):
    low, high = 0, len(nums) - 1
    while low <= high:
        mid = (low + high) // 2
        if nums[mid] == target:
            return True
        if nums[low] == nums[mid] and nums[mid] == nums[high]:
            low += 1
            high -= 1
        elif nums[mid] >= nums[low]: # 注意等号
            if target < nums[mid] and target >= nums[low]:
                high = mid - 1
            else:
                low = mid + 1
        else:
            if target > nums[mid] and target <= nums[len(nums)-1]:
                low = mid + 1
            else:
                high = mid - 1
    return False
  1. LC240:搜索二维矩阵2(行升序、列升序)


# z型搜索
def solve(matrix, target):
    row, col = len(matrix), len(matrix[0])
    x, y = 0, col-1
    while x < row and y >= 0:
        if matrix[x][y] == target:
            return True
        elif matrix[x][y] > target:
            y -= 1
        else:
            x += 1
    return False
  1. LC88:合并两个有序数组(非递减顺序)


# 双指针
def solve(nums1, m, nums2, n):
    res = []
    p1, p2 = 0, 0
    while p1 < m or p2 < n:
        if p1 == m:
            res.append(nums2[p2])
            p2 += 1
        elif p2 == n:
            res.append(nums1[p1])
            p1 += 1
        elif nums1[p1] < nums2[p2]:
            res.append(nums1[p1])
            p1 += 1
        else:
            res.append(nums2[p2])
            p2 += 1
    nums1[:] = res

链表

  1. LC21:合并两个有序链表


# 递归
def solve(list1, list2):
    if list1 is None:
        return list2
    elif list2 is None:
        return list1
    elif list1.val < list2.val:
        list1.next = solve(list1.next, list2)
        return list1
    else:
        list2.next = solve(list1, list2.next)
        return list2

# 迭代
def solve(list1, list2):
    prehead = ListNode(-1)
    prev = prehead
    while list1 and list2:
        if list1.val < list2.val:
            prev.next = list1
            list1 = list1.next
        else:
            prev.next = list2
            list2 = list2.next
        prev = prev.next
    if not list1:
        prev.next = list2
    else:
        prev.next = list1
    return prehead.next
  1. LC148:排序链表


# 归并法 递归
def solve(head):
    def sortKernel(head, tail):
        if not head:
            return head
        if head.next == tail:
            head.next = None
            return head
        slow = fast = head # 寻找中点
        while fast != tail:
            slow = slow.next
            fast = fast.next
            if fast != tail:
                fast = fast.next
        mid = slow
        return merge(sortKernel(head, mid), sortKernel(mid, tail))
    def merge(list1, list2):
        prehead = ListNode(-1)
        prev = prehead
        while list1 and list2:
            if list1.val <= list2.val:
                prev.next = list1
                list1 = list1.next
            else:
                prev.next = list2
                list2 = list2.next
            prev = prev.next
        if not list1:
            prev.next = list2
        if not list2:
            prev.next = list1
        return prehead.next
    return sortKernel(head, None)
  1. LC23:合并k个有序链表


# 暴力 顺序合并 时间复杂度O(K^2*n)
def solve(lists):
    ans = None
    for i in range(len(lists)):
        ans = kernel(ans, lists[i])
    return ans
def kernel(list1, list2):
    if list1 is None:
        return list2
    if list2 is None:
        return list1
    prehead = ListNode(-1)
    prev = prehead
    while list1 and list2:
        if list1.val < list2.val:
            prev.next = list1
            list1 = list1.next
        else:
            prev.next = list2
            list2 = list2.next
        prev = prev.next
    if not list1:
        prev.next = list2
    else:
        prev.next = list1
    return prehead.next

# 分治合并
def solve(lists):
    return merge(lists, 0, len(lists)-1)

def merge(lists, left, right):
    if left == right:
        return lists[left]
    if left > right:
        return None
    mid = (left + right) // 2
    return kernel(merge(lists, left, mid), merge(lists, mid+1, right))
def kernel(list1, list2):
    if list1 is None:
        return list2
    if list2 is None:
        return list1
    prehead = ListNode(-1)
    prev = prehead
    while list1 and list2:
        if list1.val < list2.val:
            prev.next = list1
            list1 = list1.next
        else:
            prev.next = list2
            list2 = list2.next
        prev = prev.next
    if not list1:
        prev.next = list2
    else:
        prev.next = list1
    return prehead.next
        
  1. LC160:相交链表


#空间复杂度o(m),m为headA长度
def solve(headA, headB):
    seen = set()
    while headA:
        seen.add(headA)
        headA = headA.next
    while headB:
        if headB in seen:
            return headB
        headB = headB.next
    return None

# 空间复杂度o(1)
def solve(headA, headB):
    if headA is None or headB is None:
        return None
    pa, pb = headA, headB
    while pa != pb:
        if pa is not None:
            pa = pa.next
        else:
            pa = headB
        if pb is not None:
            pb = pb.next
        else:
            pb = headA
    return pa

深度优先、广度优先、并查集

  1. LC200:岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围。


# 深度优先
def solve(grid):
    row = len(grid)
    col = len(grid[0])
    res = 0
    for x in range(row):
        for y in range(col):
            if grid[x][y] == '1':
                res += 1
                dfs(grid, x, y)
    return res

def dfs(grid, x, y):
    grid[x][y] = 0
    row = len(grid)
    col = len(grid[0])
    for i, j in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
#         print(i, j)
        if i >= 0  and i < row and j >= 0 and j < col and grid[i][j] == '1': # 注意grid[i][j] == '1'的判断要放到最后, 否则数组越界
            dfs(grid, i, j)

# 广度优先
import collections
def solve(grid):
    row = len(grid)
    col = len(grid[0])
    res = 0
    for x in range(row):
        for y in range(col):
            if grid[x][y] == '1':
                res += 1
                grid[x][y] = '0'
                neighbours = collections.deque([(x, y)])
                while neighbours:
                    r, c = neighbours.popleft()
                    for i, j in ([r-1, c], [r+1, c], [r, c-1], [r, c+1]):
                        if i >= 0 and i < row and j >= 0 and j < col and grid[i][j] == '1':
                            grid[i][j] = '0'
                            neighbours.append([i, j])
    return res
  1. LC130:被围绕的区域


# 深度优先
def solve(board):
    row = len(board)
    col = len(board[0])
    def dfs(x, y):
        if not (x >= 0 and x < row) or not(y >= 0 and y < col) or board[x][y] != 'O':
            return
        board[x][y] = 'A'
        dfs(x-1, y)
        dfs(x+1, y)
        dfs(x, y-1)
        dfs(x, y+1)
    for i in range(row):
        dfs(i, 0)
        dfs(i, col-1)
    for i in range(col-1):
        dfs(0, i)
        dfs(row-1, i)
    for i in range(row):
        for j in range(col):
            if board[i][j] == 'A':
                board[i][j] = 'O'
            elif board[i][j] == 'O':
                board[i][j] = 'X'
                

# 广度优先
def solve(board):
    row, col = len(board), len(board[0])
    quene = collections.deque()
    for i in range(row):
        if board[i][0] == 'O':
            board[i][0] = 'A'
            quene.append((i, 0))
        if board[i][col-1] == 'O':
            board[i][col-1] = 'A'
            quene.append((i, col-1))
    for i in range(col):
        if board[0][i] == 'O':
            board[0][i] = 'A'
            quene.append((0, i))
        if board[row-1][i] == 'O':
            board[row-1][i] = 'A'
            quene.append((row-1, i))
    while quene:
        x, y = quene.popleft()
        for i, j in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
            if i >= 0 and i < row and j >= 0 and j < col and board[i][j] == 'O':
                board[i][j] = 'A'
                quene.append((i, j))
    for i in range(row):
        for j in range(col):
            if board[i][j] == 'A':
                board[i][j] = 'O'
            elif board[i][j] == 'O':
                board[i][j] = 'X'
  1. LC695:岛屿最大面积


# 深度优先
def solve(grid):
    row = len(grid)
    col = len(grid[0])
    ans = 0
    for i in range(row):
        for j in range(col):
            ans = max(dfs(grid, i, j), ans)
    return ans
def dfs(grid, x, y):
    row, col = len(grid), len(grid[0])
    if x < 0 or y < 0 or x == row or y == col or grid[x][y] != 1:
        return 0
    grid[x][y] = 0
    ans = 1
    for i, j in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
        ans += dfs(grid, i, j)
    return ans

# 广度优先
# 广度优先
def solve(grid):
    row, col = len(grid), len(grid[0])
    ans = 0
    for i in range(row):
        for j in range(col):
            cur = 0
            quene = collections.deque([(i, j)])
            while quene:
                x, y = quene.popleft()
                if x < 0 or x == row or y < 0 or y == col or grid[x][y] != 1:
                    continue
                grid[x][y] = 0
                cur += 1
                for tmp_x, tmp_y in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
                    quene.append([tmp_x, tmp_y])
            ans = max(ans, cur)
    return ans
  1. LC463:岛屿的周长(只有一个岛屿)


# 深度优先
def solve(grid):
    row, col = len(grid), len(grid[0])
    ans = 0
    for i in range(row):
        for j in range(col):
            if grid[i][j] == 1:
                ans += dfs(i, j, grid)
    return ans
def dfs(i, j, grid):
    row, col = len(grid), len(grid[0])
    if i < 0 or i == row or j < 0 or j == col or grid[i][j] == 0:
        return 1
    if grid[i][j] == 2:
        return 0
    grid[i][j] = 2
    ans = 0
    for x, y in [(i-1, j),(i+1, j), (i, j-1), (i, j+1)]:
        ans += dfs(x, y, grid)
    return ans

# 广度优先
def solve(grid):
    row, col = len(grid), len(grid[0])
    ans = 0
    for i in range(row):
        for j in range(col):
            if grid[i][j] == 1:
                cur = 0
                quene = collections.deque([(i, j)])
                while quene:
                    x, y = quene.popleft()
                    grid[x][y] = 2
                    for tmp_x, tmp_y in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
                        if tmp_x < 0 or tmp_x == row or tmp_y < 0 or tmp_y == col or grid[tmp_x][tmp_y] == 0:
                            cur += 1
                        elif grid[tmp_x][tmp_y] == 1:
                            grid[tmp_x][tmp_y] = 2
                            quene.append([tmp_x, tmp_y])
                ans += cur
                return ans
  1. LC102:二叉树的层序遍历


# bfs
def solve(root):
    if not root:
        return []
    res = []
    quene = [root]
    while quene:
        size = len(quene)
        tmp = []
        for i in range(size):
            r = quene.pop(0)
            tmp.append(r.val)
            if r.left:
                quene.append(r.left)
            if r.right:
                quene.append(r.right)
        res.append(tmp)
    return res

# dfs
def solve(root):
    if not root:
        return []
    res = []
    def dfs(index, r):
        if len(res) < index:
            res.append([])
        res[index-1].append(r.val)
        if r.left:
            dfs(index+1, r.left)
        if r.right:
            dfs(index+1, r.right)
    dfs(1, root)
    return res
  1. LC103:二叉树锯齿形遍历


# bfs
def solve(root):
    if not root:
        return []
    res = []
    quene = [root]
    flag = 1
    while quene:
        size = len(quene)
        tmp = []
        for i in range(size):
            r = quene.pop(0)
            tmp.append(r.val)
            if r.left:
                quene.append(r.left)
            if r.right:
                quene.append(r.right)
        if flag:
            res.append(tmp)
            flag = 0
        else:
            res.append(tmp[::-1])
            flag = 1
    return res
  1. LC297:二叉树序列化反序列化


# bfs
class Solve:
    def serialize(self, root):
        if not root:
            return ''
        quene = [root]
        res = []
        while quene:
            node = quene.pop(0)
            if node:
                res.append(str(node.val))
                quene.append(node.left)
                quene.append(node.right)
            else:
                res.append('null')
        return '[' + ','.join(res) + ']'
    def deserialize(self, data):
        if not data:
            return []
        lst = data[1:-1].strip().split(',')
        root = TreeNode(int(lst[0]))
        quene = [root]
        i = 1
        while quene:
            node = quene.pop(0)
            if lst[i] != 'null':
                node.left = TreeNode(int(lst[i]))
                quene.append(node.left)
            i += 1
            if lst[i] != 'null':
                node.right = TreeNode(int(lst[i]))
                quene.append(node.right)
            i += 1
        return root

# dfs
class Solve:
    def serialize(self, root):
        if not root:
            return 'null'
        return str(root.val) + ',' + str(self.serialize(root.left)) + ',' + str(self.serialize(root.right))
    def deserialize(self, data):
        def dfs(lst):
            val = lst.pop(0)
            if val == 'null':
                return None
            root = TreeNode(int(val))
            root.left = dfs(lst)
            root.right = dfs(lst)
            return root
        lst = data.strip().split(',')
        return dfs(lst)

排序

  1. 山峰数组最大值索引


def solve(nums):
    low, high = 0, len(nums)-1
    ans = 0
    while low <= high:
        mid = (low + high) // 2
        if nums[mid] > nums[mid+1]:
            high = mid - 1
            ans = mid
        else:
            low = mid + 1
    return nums[ans]
  1. LC215:数组中第k大元素


# 快排 (时间复杂度期望为o(n))
def solve(nums, k):
    k = len(nums) - k
    start = 0
    end = len(nums) - 1
    while True:
        loc = quickKernel(nums, start, end)
        if loc == k:
            return nums[loc]
        elif loc < k:
            start = loc + 1
        else:
            end = loc - 1
def quickKernel(nums, start, end):
    low = start
    high = end
    base = nums[start]
    while low < high:
        while low < high and nums[high] >= base:
            high -= 1
        nums[low] = nums[high]
        while low < high and nums[low] < base:
            low += 1
        nums[high] = nums[low]
    nums[low] = base
    return low
    

# 堆排(时间复杂度nlogn)
def heapify(arr, n, i):
    """
    arr:数组
    n:数组的长度
    i: 当前节点的索引
    """
    r = 2*i + 1
    l = 2*i
    # 判断左子节点是否大于当前节点
    largest = i
    if l < n and arr[l] > arr[i]:  #降序改为arr[l] < arr[i]
        largest = l
    #     else:
    #         largest = i
    # 判断右子节点是否大于当前节点 
    if r < n and arr[r] > arr[largest]: #降序改为arr[r] < arr[largest]
        largest = r
    # 不满足特性,交换节点位置,交换后再次进行heapify
    if largest != i:
        arr[i], arr[largest] = arr[largest], arr[i]
        heapify(arr, n, largest)

def build_max_heaps(arr, n):
    i = n//2
    #     count = 0
    while i >= 0:
        heapify(arr, n, i)
        i -= 1
def heapSort(nums, k):
    n = len(nums)
    build_max_heaps(nums, n)
    for k in range(n-1, n-k-1, -1):
        nums[k], nums[0] = nums[0], nums[k]
        heapify(nums, k, 0)
    return nums[k]
 
  1. 快排


def quickSort(nums, low, high):
    if low >= high:
        return nums
    loc = kernel(nums, low, high)
    quickSort(nums, low, loc-1)
    quickSort(nums, loc+1, high)
def kernel(nums, start, end):
    low = start
    high = end
    base = nums[start]
    while low < high:
        while low < high and nums[high] >= base:
            high -= 1
        nums[low] = nums[high]
        while low < high and nums[low] <= base:
            low += 1
        nums[high] = nums[low]
    nums[low] = base
    return low
  1. 剑指offer40:最小的k个数


# 快排 (时间复杂度期望为o(n))
def quickSort_kernel(arr, start, end):
#     if start > end:
#         return
    base = arr[start]
    low = start
    high = end
    while low < high:
        while low < high and arr[high] >= base: # 若是最大的改这里
            high -= 1
        arr[low] = arr[high]
        while low < high and arr[low] <= base: # 若是最大的改这里
            low += 1
        arr[high] = arr[low]
    arr[low] = base
    return low
def solve(arr, k):
    if k > len(arr) or k <= 0:
        return []
    start = 0
    end = len(arr) - 1
    loc = quickSort_kernel(arr, start, end)
    while loc != k-1:
#         loc = quickSort_kernel(arr, start, end)
        if loc > k - 1:
            end = loc - 1
        else:
            start = loc + 1
        loc = quickSort_kernel(arr, start, end)
    return arr[:k]

# 堆排序
def getLeastNumbers(arr,k):
    if k == 0 or k > len(arr) or k < 0:
        return []
    data = arr[:k]
    build_heap(data,len(data))  ##实现
    for each in arr[k:]:
        if data[0] > each:
            data[0] = each
            heapify(data,len(data),0)
    return data
def build_heap(arr,n):
    i = n // 2
    while i >= 0:
        heapify(arr,n,i)
        i -= 1
def heapify(arr,n,i):
    left = 2 * i
    right = 2 * i + 1
    largest = i
    if left < n and arr[left] > arr[i]:
        largest = left
    if right < n and arr[right] > arr[largest]:
        largest = right
    if largest != i:
        arr[i],arr[largest] = arr[largest],arr[i]
        heapify(arr,n,largest)
  1. LC703:数据流中第k大元素


class Heap:
    def __init__(self,desc=False):
        """
        初始化,默认创建一个小顶堆
        """
        self.heap = []
        self.desc = desc
    
    @property
    def size(self):
        return len(self.heap)
    
    def top(self):
        if self.size:
            return self.heap[0]
        return None
    
    def push(self,item):
        """
        添加元素
        第一步,把元素加入到数组末尾
        第二步,把末尾元素向上调整
        """
        self.heap.append(item)
        self._sift_up(self.size-1)
    
    def pop(self):
        """
        弹出堆顶
        第一步,记录堆顶元素的值
        第二步,交换堆顶元素与末尾元素
        第三步,删除数组末尾元素
        第四步,新的堆顶元素向下调整
        第五步,返回答案
        """
        item = self.heap[0]
        self._swap(0,self.size-1)
        self.heap.pop()
        self._sift_down(0)
        return item
    
    def _smaller(self,lhs,rhs):
        return lhs > rhs if self.desc else lhs < rhs
    
    def _sift_up(self,index):
        """
        向上调整
        如果父节点和当前节点满足交换的关系
        (对于小顶堆是父节点元素更大,对于大顶堆是父节点更小),
        则持续将当前节点向上调整
        """
        while index:
            parent = (index-1) // 2
            
            if self._smaller(self.heap[parent],self.heap[index]):
                break
                
            self._swap(parent,index)
            index = parent
    
    def _sift_down(self,index):
        """
        向下调整
        如果子节点和当前节点满足交换的关系
        (对于小顶堆是子节点元素更小,对于大顶堆是子节点更大),
        则持续将当前节点向下调整
        """
        # 若存在子节点
        while index*2+1 < self.size:
            smallest = index
            left = index*2+1
            right = index*2+2
            
            if self._smaller(self.heap[left],self.heap[smallest]):
                smallest = left
                
            if right < self.size and self._smaller(self.heap[right],self.heap[smallest]):
                smallest = right
                
            if smallest == index:
                break
            
            self._swap(index,smallest)
            index = smallest
    
    def _swap(self,i,j):
        self.heap[i],self.heap[j] = self.heap[j],self.heap[i]

class KthLargest:

    def __init__(self, k: int, nums: List[int]):
        self.heap = Heap()
        self.k = k
        for num in nums:
            self.heap.push(num)
            if self.heap.size > k:
                self.heap.pop()


    def add(self, val: int) -> int:
        self.heap.push(val)
        if self.heap.size > self.k:
            self.heap.pop()
        return self.heap.top()
  1. LC414:第三大的数


# a最大 b次大 c第三大
def solve(nums):
    a, b, c = float('-inf'), float('-inf'), float('-inf')
    for each in nums:
        if each > a:
            a, b, c = each, a, b
        elif each > b and each < a:
            b, c = each, b
        elif each > c and each < b:
            c = each
    if c == float('-inf'):
        return a
    else:
        return c
  1. LC4:两个正序数组的中位数


def solve(nums1, nums2):
    def kernel(k):
        index1, index2 = 0, 0
        while True:
            if index1 == m:
                return nums2[index2+k-1]
            if index2 == n:
                return nums1[index1+k-1]
            if k == 1:
                return min(nums1[index1], nums2[index2])
            
            newIndex1 = min(index1 + k//2 -1, m-1)
            newIndex2 = min(index2 + k//2 -1, n-1)
            pivot1, pivot2 = nums1[newIndex1], nums2[newIndex2]
            if pivot1 <= pivot2:
                k = k - (newIndex1 - index1 + 1)
                index1 = newIndex1 + 1
            else:
                k = k- (newIndex2 - index2 + 1)
                index2 = newIndex2 + 1
    m, n = len(nums1), len(nums2)
    totalLength = m + n
    if totalLength % 2 == 1:
        return kernel((totalLength+1)//2)
    else:
        return (kernel(totalLength//2) + kernel(totalLength//2+1)) / 2

回溯

  1. LC46:全排列【不包含重复数字】


# 回溯
def solve(nums):
    n = len(nums)
    res = []
    def back(first):
        if first == n:
            res.append(nums[:])
        for i in range(first, n):
            nums[i], nums[first] = nums[first], nums[i]
            back(first+1)
            nums[i], nums[first] = nums[first], nums[i]
    back(0)
    return res
  1. LC47:全排列2【包含重复数字】


# 回溯2【含重复数字】
def solve(nums):
    res = []
    n = len(nums)
    used = [0] * n
    def back(nums, used, path):
        if len(path) == n:
            res.append(path[:])
#             return
        for i in range(n):
            if not used[i]:
                if i > 0 and nums[i] == nums[i-1] and not used[i-1]:
                    continue
                used[i] = 1
                path.append(nums[i])
                back(nums, used, path)
                used[i] = 0
                path.pop()
    back(sorted(nums), used, [])
    return res
  1. LC77:组合

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台


def solve(n, k):
    res = []
    path = []
    def back(i):
        d = k - len(path)
        if d == 0:
            res.append(path[:])
            return
        for j in range(i, d-1, -1):
            path.append(j)
            back(j-1)
            path.pop()
    back(n)
    return res
  1. LC39:组合总和


def solve(candidates, target):
    res = []
    n = len(candidates)
    path = []
    def back(begin, target):
        if target < 0:
            return
        if target == 0:
            res.append(path[:])
            return
        for i in range(begin, n):
            target -= candidates[i]
            path.append(candidates[i])
            back(i, target)
            target += candidates[i]
            path.pop()
    back(0, target)
    return res

def solve(candidates, target):
    res, path = [], []
    dfs(candidates, target, 0, res, path)
    return res
def dfs(nums, target, index, res, path):
    if target < 0:
        return
    if target == 0:
        res.append(path[:])
        return
    for i in range(index, len(nums)):
        dfs(nums, target-nums[i], i, res, path+[nums[i]])
  1. LC90:子集2【可能含有重复值】

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台


def solve(nums, target):
    res, path = [], []
    nums.sort() # 不sort的话会有重复值
    dfs(nums, 0, res, path, target)
    return res
def dfs(nums, index, res, path, target):
    if sum(path[:]) == target:
        res.append(path[:])
    for i in range(index, len(nums)):
        if i > index and nums[i] == nums[i-1]:
            continue
        path.append(nums[i])
        dfs(nums, i+1, res, path, target)
        path.pop()
        
  1. LC:112路径总和


# 递归
def solve(root, target):
    if not root:
        return False
    if not root.left and not root.right:
        return root.val == target
    return solve(root.left, target-root.val) or solve(root.right, target-root.val)

# 回溯
def solve(root, target):
    if not root:
        return False
    res = []
    return dfs(root, target, res, [root.val])
def dfs(root, target, res, path):
    if not root:
        return False
    if sum(path) == target and not root.left and not root.right:
        return True
    left_flag, right_flag = False, False
    if root.left:
        left_flag = dfs(root.left, target, res, path+[root.left.val])
    if root.right:
        right_flag = dfs(root.right, target, res, path+[root.right.val])
    return left_flag or right_flag
  1. LC113:路径总和2


def solve(root, target):
    res = []
    path = []
    dfs(root, target, res, path)
    return res
def dfs(root, target, res, path):
    if not root:
        return
    path.append(root.val)
    target = target - root.val
    if not root.left and not root.right and target == 0:
        res.append(path[:])
    dfs(root.left, target, res, path)
    dfs(root.right, target, res, path)
    path.pop()

二叉树

  1. LC236:二叉树的最近公共祖先


def solve(root, p, q):
    if not root or root == p or root == q:
        return root
    left = solve(root.left, p, q)
    right = solve(root.right, p, q)
    if not left:
        return right
    if not right:
        return left
    return root
  1. LC235:二叉搜索树的最近公共祖先


def solve(root, p, q):
    res = root
    while True:
        if p.val < res.val and q.val < res.val:
            res = res.left
        elif p.val > res.val and q.val > res.val:
            res = res.right
        else:
            break
    return res
  1. LC94:二叉树的中序遍历


# 递归
def solve(root):
    res = []
    def dfs(root):
        if not root:
            return None
        dfs(root.left)
        res.append(root.val)
        dfs(root.right)
    dfs(root)
    return res

# 迭代
def solve(root):
    res = []
    quene = []
    while quene or root:
        while root:
            quene.append(root)
            root = root.left
        root = quene.pop()
        res.append(root.val)
        root = root.right
    return res
        

  1. LC797:所有可能路径


def solve(graph):
    path = []
    res = []
    def back(x):
        if x == len(graph) - 1:
            res.append(path[:])
        for y in graph[x]:
            path.append(y)
            back(y)
            path.pop()
    path.append(0)
    back(0)
    return res
  1. LC210、LC207 课程表


def solve(num, condition):
    edges = collections.defaultdict(list)
    visited = [0] * num
    valid = True
    result = []
    for info in condition:
        edges[info[1]].append(info[0])
    def dfs(u):
        nonlocal valid
        visited[u] = 1
        for v in edges[u]:
            if visited[v] == 0:
                dfs(v)
                if not valid:
                    return
            elif visited[v] == 1:
                valid = False
                return
        visited[u] = 2
        result.append(u)
    for i in range(num):
        if valid and not visited[i]:
            dfs(i)
    if not valid:
        res = []
    else:
        res = result[::-1]
    return res, valid
  1. LC1514:概率最大的路径【无向加权图】


def solve(n, edges, succProb, start, end):
    graph = collections.defaultdict(list)
    for i, (x, y) in enumerate(edges):
        graph[x].append((succProb[i], y))
        graph[y].append((succProb[i], x))
    quene = [(-1.0, start)]
    prob = [0.0] * n
    prob[start] = 1.0
    while quene:
        p, node = quene.pop(0)
        p = -p
        if p < prob[node]:
            continue
        for p_next, node_next in graph[node]:
            if prob[node_next] < prob[node] * p_next:
                prob[node_next] = prob[node] * p_next
                quene.append((-prob[node_next], node_next))
    return prob[end]
  1. LC1971:寻找图中是否存在路径


def solve(n, edges, source, destination):
    graph = [[] * n for i in range(n)]
    for edge in edges:
        x, y = edge[0], edge[1]
        graph[x].append(y)
        graph[y].append(x)
    visited = [0] * n
    quene = [source]
    visited[source] = 1
    while quene:
        node = quene.pop(0)
        if node == destination:
            break
        for each in graph[node]:
            if not visited[each]:
                quene.append(each)
                visited[each] = 1
    if visited[destination] == 1:
            res = True
        else:
            res = False
    return res
    

你可能感兴趣的:(code,Python,leetcode,算法,职场和发展)