手撕代码高频考题代码详解

手撕代码高频考题代码详解

1. 快速排序

# Python最简版
from random import randint


def quick_sort(arr):
    if len(arr) <= 1:
        return arr
    p = arr[randint(0, len(arr) - 1)]
    left = [x for x in arr if x < p]
    mid = [x for x in arr if x == p]
    right = [x for x in arr if x > p]

    return quick_sort(left) + mid + quick_sort(right)


a = [randint(0, 100000) for x in range(100000)]
print(quick_sort(a))

2. 堆排序

class Solution(object):
    def __init__(self, nums):
        self.nums = nums

    def heap_sort(self):
        i, length = 0, len(self.nums)
        # 构造大顶堆,从非叶子节点开始倒序遍历,因此是length // 2 - 1 就是最后一个非叶子节点
        for i in range(length // 2 - 1, -1, -1):
            self.build_heap(i, length - 1)
        # 上面的循环完成了大顶堆的构造,那么就开始把根节点跟末尾节点交换,然后重新调整大顶堆
        for j in range(length - 1, -1, -1):
            self.nums[0], self.nums[j] = self.nums[j], self.nums[0]  # 交换
            self.build_heap(0, j - 1)  # 从堆顶开始调整
        return self.nums

    def build_heap(self, i, length):
        """构建大顶堆"""
        left, right = 2 * i + 1, 2 * i + 2  # 左右子节点的下标
        large_index = i
        if left <= length and self.nums[i] < self.nums[left]:
            large_index = left
        if right <= length and self.nums[large_index] < self.nums[right]:
            large_index = right
        if large_index != i:
            self.nums[large_index], self.nums[i] = self.nums[i], self.nums[large_index]
            self.build_heap(large_index, length)

solution = Solution([2, 3, 5, 4, 7, 6, 8])
print(solution.heap_sort())
# 小顶堆的话只需要把<改成>号即可

3. 寻找数组中出现一次的数,其他出现3次及以上

"""
出现三次或者三次以上去找那个单独的值的时候该怎么办呢?好像不能用异或了,但是考虑到输入是int型数组,所以可以用32位来表达输入数组的元素。
假设输入中没有single number,那么输入中的每个数字都重复出现了数字,也就是说,对这32位中的每一位i而言,所有的输入加起来之后,第i位一定是3的倍数。
现在增加了single number,那么对这32位中的每一位做相同的处理,也就是说,逐位把所有的输入加起来,并且看看第i位的和除以3的余数,这个余数就是single numer在第i位的取值。
这样就得到了single number在第i位的取值。这等价于一个模拟的二进制,接着只需要把这个模拟的二进制转化为十进制输出即可。
"""
nums = [1, 2, 2, 2, 3, 3, 3]
dp = [0] * 32
for i in nums:
    for j in range(32):
        dp[j] = dp[j] + ((i >> j) & 1)  # 首先把输入数字的第i位加起来,这里和1去与,取到的就是一位

res = 0
for i in range(32):
    if dp[i] % 3 != 0:
        res = res | (1 << i)
print(res)

4. 寻找数组中两个出现一次的数,其他数出现2次

# 假设这两个不同的数分别为a,b,根据异或运算最后得到a^b,因为a和b不同,所以a^b必定存在某个二进制位置k,a为0,b为1,或者相反。找到第一个不同的位置即可,将a和b分开。
nums = [5, 2, 3, 3]
res = 0
for i in nums:
    res ^= i

k = 0
while (res >> k) & 1 == 0:
    k = k + 1

res1 = 0
res2 = 0
for i in nums:
    if (i >> k) & 1:
        res1 ^= i
    else:
        res2 ^= i
print(res1, res2)

5. 划分瓶子

import numpy as np

dp = np.zeros(10)
a = np.array([1, 2, 3, 5])
b = sum(a)

for i in range(len(a)):
    for j in range(b // 2, a[i] - 1, -1):
        dp[j] = max(dp[j], dp[j - a[i]] + a[i])

if int(b - 2 * dp[b // 2]) == 0:
    print("1")
else:
    print("0")

6. 两座岛相连起来的桥的最短长度

# 题目意思:
"""
二维数组,0表示海洋,1表示岛屿,存在两座岛,问使得两座岛相连起来的桥的最短长度,如果两座岛相连,则输出0
"""
def shortestBridge(A):
    row, col = len(A), len(A[0])
    visited = [[0] * col for _ in range(row)]  # 负责记录其中的一个岛
    q = []
    start = []  # 保存其中一个岛的所有位置
    found = False
    for i in range(row):  # 先找到一个岛中其中一个位置
        for j in range(col):
            if A[i][j] == 1:
                found = True
                q.append((i, j))
                visited[i][j] = 1
                break
        if found:
            break

    while q:  # 以其中一个岛的位置为基础,使用广度优先搜索方法,继续找到这个岛的其他位置
        tmp = []
        for a in q:
            x, y = a[0], a[1]
            start.append(a)  # 把岛的位置放到 start 队列里面
            if (x - 1 >= 0) and (visited[x - 1][y] == 0) and (A[x - 1][y] == 1):
                tmp.append((x - 1, y))
                visited[x - 1][y] = 1
            if (x + 1 < col) and (visited[x + 1][y] == 0) and (A[x + 1][y] == 1):
                tmp.append((x + 1, y))
                visited[x + 1][y] = 1
            if (y - 1 >= 0) and (visited[x][y - 1] == 0) and (A[x][y - 1] == 1):
                tmp.append((x, y - 1))
                visited[x][y - 1] = 1
            if (y + 1 < row) and (visited[x][y + 1] == 0) and (A[x][y + 1] == 1):
                tmp.append((x, y + 1))
                visited[x][y + 1] = 1
        q = tmp

    ans = 0
    while start:  # 从一个岛出发,去找探索另外一个岛
        tmp = []
        for a in start:  # 广度优先算法,一层一层的探查 是否 到达另外一个岛
            x, y = a[0], a[1]
            if (x - 1 >= 0) and (visited[x - 1][y] == 0):
                if A[x - 1][y] == 1:
                    return ans
                else:
                    tmp.append((x - 1, y))
                    visited[x - 1][y] = 1
            if (x + 1 < col) and (visited[x + 1][y] == 0):
                if A[x + 1][y] == 1:
                    return ans
                else:
                    tmp.append((x + 1, y))
                    visited[x + 1][y] = 1
            if (y - 1 >= 0) and (visited[x][y - 1] == 0):
                if A[x][y - 1] == 1:
                    return ans
                else:
                    tmp.append((x, y - 1))
                    visited[x][y - 1] = 1
            if (y + 1 < row) and (visited[x][y + 1] == 0):
                if A[x][y + 1] == 1:
                    return ans
                else:
                    tmp.append((x, y + 1))
                    visited[x][y + 1] = 1

        start = tmp  # 探索了一层之后,没有发现另外一个岛,则更新最外层边界以及路径长度
        ans += 1

    return ans


if __name__ == '__main__':
    A = [[1, 1, 1, 1, 1],
         [1, 0, 0, 0, 1],
         [1, 0, 1, 0, 1],
         [1, 0, 0, 0, 1],
         [1, 1, 1, 1, 1]]
    print(shortestBridge(A))

7. 链表相交

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        cur1 = headA
        cur2 = headB
        # 链表不相交的情况,两个NULL指针相等跳出循环
        while cur1 != cur2:
            cur1 = cur1.next if cur1 else headB
            cur2 = cur2.next if cur2 else headA
        return cur1

8. 求数组中第K个最大的元素

import random


def partition(arr, low, high):
    """
    将小于中轴元素的一次排在前面,从0开始
    :param arr:
    :param low:
    :param high:
    :return:
    """
    x = arr[high]
    i = low - 1
    for j in range(low, high):
        if arr[j] <= x:
            i += 1
            arr[i], arr[j] = arr[j], arr[i]
    arr[i + 1], arr[high] = arr[high], arr[i + 1]  # 将中轴元素调回,使得中轴元素左边小于中轴,右边大于中轴
    return i + 1


def randomPartition(arr, low, high):
    """
    将中轴元素放置在最后面
    :param arr:
    :param low:
    :param high:
    :return:
    """
    rand_num = random.randint(low, high)
    arr[rand_num], arr[high] = arr[high], arr[rand_num]
    return partition(arr, low, high)


def quick_sort(arr, low, high, k=None):
    # par_num = randomPartition(arr, low, high)
    # if par_num == k:
    #     return arr[k]
    # elif par_num > k:
    #     return quick_sort(arr, low, par_num - 1, k)
    # else:
    #     return quick_sort(arr, par_num + 1, high, k)
    if low < high:
        par_num = randomPartition(arr, low, high)
        quick_sort(arr, low, par_num - 1)
        quick_sort(arr, par_num + 1, high)


arr = [2, 5, 5, 3]
n = len(arr)
k = 3
quick_sort(arr, 0, n - 1)
print(arr)

9. 旋转数组搜索问题

# 适用于重复和非重复的找目标值的两种情况
class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        left = 0
        right = len(nums) - 1
        while left <= right:
            mid  = (left + right) >> 1
            if nums[mid] == target:
                return mid
            
            if nums[mid] > nums[right]: # mid左边单调递增
                if nums[left] <= target < nums[mid]:
                    right = mid -1
                else:
                    left = mid + 1

            elif nums[mid] < nums[right]:
                if nums[mid] < target <= nums[right]:
                    left = mid + 1
                else:
                    right = mid - 1
            else:
                right = right - 1

        return -1

# 旋转多次数组求目标值的最小索引        
class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        left = 0
        right = len(nums) - 1
        while left < right:
            mid = (left + right) >> 1
            if nums[mid] > nums[left]:  # 左区间单调递增
                if nums[left] <= target <= nums[mid]:
                    right = mid
                else:
                    left = mid + 1

            elif nums[mid] < nums[left]:  # 右区间单调递增
                if target <= nums[mid] or target >= nums[left]:
                    right = mid
                else:
                    left = mid + 1
            else:
                if nums[left] != target:
                    left += 1
                else:
                    right = left
        return left if nums[left] == target else -1

# 旋转多次数组求目标值的最大索引
class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        left = 0
        right = len(nums) - 1
        while left < right:
            mid = (left + right) // 2
            if nums[mid] < nums[right]:  # 右区间单调递增
                if nums[mid] <= target <= nums[right]:
                    if mid == left:
                        if nums[mid] == target:
                            return mid

                        if nums[right] == target:
                            return right
                    else:
                        left = mid
                else:
                    right = mid - 1

            elif nums[mid] > nums[right]:  # 左区间单调递增
                if target <= nums[right] or target >= nums[mid]:
                    left = mid
                else:
                    right = mid - 1

            else:
                if nums[mid] != target:
                    right -= 1
                else:
                    break
        return right if nums[right] == target else -1


print(Solution().search([15, 16, 19, 20, 25, 1, 3, 4, 5, 5, 7, 10, 14], 5))


# 找最小值
class Solution(object):
    def minArray(self, numbers):
        """
        :type numbers: List[int]
        :rtype: int
        """
        left = 0
        right = len(numbers) - 1
        while left < right:
            mid = (left + right) >> 1    
            if numbers[mid] > numbers[right]: # 最小值在[mid+1,right]中间
                left = mid + 1
            elif numbers[mid] < numbers[right]: # 最小值在[left,mid]中间
                right = mid
            elif numbers[mid] == numbers[right]: # 无法判断在左边还是右边,那最小值可以用mid代替,right舍弃即可
                right -= 1
        return numbers[left]

# 找最大值
class Solution(object):
    def minArray(self, numbers):
        """
        :type numbers: List[int]
        :rtype: int
        """
        left = 0
        right = len(numbers) - 1
        while left < right:
            mid = (left + right) >> 1    
            if numbers[mid] > numbers[right]: # 最小值在[mid,right]中间
                left = mid
            elif numbers[mid] < numbers[right]: # 最小值在[left,mid]中间
                right = mid - 1
            elif numbers[mid] == numbers[right]: # 无法判断在左边还是右边
                right -= 1
        return numbers[left]

10. 最大岛屿数目

class Solution:
    def dfs(self, grid, r, c):
        grid[r][c] = 0
        nr, nc = len(grid), len(grid[0])
        for x, y in [(r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1)]:
            if 0 <= x < nr and 0 <= y < nc and grid[x][y] == "1":
                self.dfs(grid, x, y)

    def numIslands(self, grid: List[List[str]]) -> int:
        nr = len(grid)
        if nr == 0:
            return 0
        nc = len(grid[0])

        num_islands = 0
        for r in range(nr):
            for c in range(nc):
                if grid[r][c] == "1":
                    num_islands += 1
                    self.dfs(grid, r, c)
        
        return num_islands

11. 二叉树序列化和反序列化

class Codec:

    def serialize(self, root):
        """Encodes a tree to a single string.
        
        :type root: TreeNode
        :rtype: str
        """
        if not root: return '[]'
        queue = collections.deque()
        queue.append(root)
        res = []
        while queue:
            node = queue.popleft()
            res.append(str(node.val) if node else '#')
            if node:
                queue.extend([node.left, node.right])
        # print(res)
        return '[' + ','.join(res) + ']'
        
    def deserialize(self, data):
        """Decodes your encoded data to tree.
        
        :type data: str
        :rtype: TreeNode
        """
        nodes = [TreeNode(int(v)) if v != '#' else None for v in data[1:-1].split(',')]
        # print(nodes)
        i,j = 0,1
        while i < len(nodes):
            if nodes[i] is not None:
                nodes[i].left = nodes[j]
                j += 1
                nodes[i].right = nodes[j]
                j += 1
            i += 1
        return nodes[0]

12. 最长不重复子串

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        # 哈希集合,记录每个字符是否出现过
        occ = set()
        n = len(s)
        # 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        rk, ans = -1, 0
        for i in range(n):
            if i != 0:
                # 左指针向右移动一格,移除一个字符
                occ.remove(s[i - 1])
            while rk + 1 < n and s[rk + 1] not in occ:
                # 不断地移动右指针
                occ.add(s[rk + 1])
                rk += 1
            # 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = max(ans, rk - i + 1)
       return ans

13. 硬币问题(最少硬币个数)

class Solution(object):
    def coinChange(self, coins, amount):
        """
        :type coins: List[int]
        :type amount: int
        :rtype: int
        """
        dp = [1e9] * (amount + 1)
        dp[0] = 0
        for i in coins:
           for j in range(i, amount + 1):
               dp[j] = min(dp[j], dp[j-i] + 1)
        return dp[amount] if dp[amount] != 1e9 else -1

14. 硬币问题(组合方式总数)

n = 7
mod = 10**7 + 7
nums = [1, 2, 3, 4, 5, 6]
dp = [0] * (n + 1)
dp[0] = 1
for i in nums:
    for j in range(n, i - 1, -1): # 只能取一个;如果是能取多个的话,调换循环顺序
        dp[j] = (dp[j] + dp[j - i]) % mod
print(dp[n])

15. 背包问题

# 01 背包
N, V = map(int, input().split())

v = [0] * N
w = [0] * N

for i in range(N):
    v[i], w[i] = map(int, input().split())

dp = [0] * (V + 1)  # 初始化全0

for i in range(N):
    for j in range(V, v[i] - 1, -1):
        dp[j] = max(dp[j], dp[j - v[i]] + w[i])

print(dp[V])
# 完全背包
"""
换句话说,这正是为了保证每件物品只选一次,保证在考虑“选入第 i 件物品”这件策略时,依据的是一个绝无已经选入第 i 件物品的子结果 F[i − 1, v − Ci]。
而现在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第 i 种物品”这种策略时,却正需要一个可能已选入第 i 种物品的子结果 F[i, v − Ci],
所以就可以并且必须采用 v递增的顺序循环。
"""
N, V = map(int, input().split())

v = [0] * N
w = [0] * N

for i in range(N):
    v[i], w[i] = map(int, input().split())

dp = [0] * (V + 1)  # 初始化全0

for i in range(N):
    for j in range(v[i], V + 1):
        dp[j] = max(dp[j], dp[j - v[i]] + w[i])

print(dp[V])
# 多重背包
N, V = map(int, input().split())
v = [0] * N  # 体积
w = [0] * N  # 价值
s = [0] * N  # 个数
dp = [0] * (V + 1)
for i in range(N):
    v[i], w[i], s[i] = map(int, input().split())
for i in range(N):
    for j in range(V, v[i] - 1, -1):
        for k in range(1, min(s[i], j // v[i]) + 1):
            dp[j] = max(dp[j], dp[j - k * v[i]] + k * w[i])

print(dp[V])     

16. 链表反转

def reverse(head):
    pre = None
    cur = head
    while cur:
        t = cur.next
        cur.next = pre
        pre = cur
        cur = t
    return pre

17. 最小编辑距离

有两个字符串,str1,str2,可以通过以下操作将str1变成str2. 分别是字符串替换/删除/插入操作
问最少需要多少种操作使得,str1变成str2?

# 动态规划思路
设m,n分别为str1和str2的长度
dp[m][n] 表示长度分别为m,n时的最小编辑距离,也就是最少操作次数
if str1[m] == str2[n]:
    dp[m][n] = dp[m-1][n-1]
else:
   if str1 删除  ----> 将str1[m]删除
       dp[m][n] = dp[m-1][n] + 1
   if str1 替换  ----> 将str1[m]替换成str2[n]
       dp[m][n] = dp[m-1][n-1] + 1
   if str1 插入  ----> 在str1[m+1]处插入一个字符
      dp[m][n] = dp[m][n-1] + 1

状态转移方程:dp[m][n] = min(dp[m-1][n] + 1, dp[m-1][n-1] + 1, dp[m][n-1] + 1)
# 完整代码如下:
class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        import numpy as np
        m = len(word1)
        n = len(word2)
        dp = np.zeros((m+1,n+1),int)
        """ dp[i][j] 表示长度为i和j的字符串str1和str2之间的最小编辑距离,解题思路如下
        if str1[m] == str2[n]:
            dp[m][n] = dp[m-1][n-1]
        else:
            if str1 删除  ----> 将str1[m]删除
                dp[m][n] = dp[m-1][n] + 1
            if str1 替换  ----> 将str1[m]替换成str2[n]
                dp[m][n] = dp[m-1][n-1] + 1
            if str1 插入  ----> 在str1[m+1]处插入一个字符
                dp[m][n] = dp[m][n-1] + 1
        """
        dp[0] = range(n + 1) # 表示str1为空字符串,最小编辑距离就等于str2的长度
        dp[:,0] = range(m + 1) # 表示str2为空字符串,最小编辑距离就等于str1的长度
        for i in range(1,m+1):
            for j in range(1,n+1):
                if word1[i-1] == word2[j-1]: # 第i个位置和第j个位置相同的话,则等于长度为i-1到长度为j-1的两个字符串的最小编辑距离
                    dp[i][j] = dp[i-1][j-1]
                else:# 三种状态下取最小值
                    dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
        return dp[m][n]

18. 归并排序

def mergesort(seq):
    if len(seq) <= 1:
        return seq
    mid = len(seq) // 2
    left = mergesort(seq[:mid])
    right = mergesort(seq[mid:])
    return merge(left, right)

def merge(left, right):
    result = []
    i, j = 0, 0
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            result.append(left[i])
            i += 1
        else:
            result.append(right[j])
            j += 1
    result += left[i:]
    result += right[j:]
    return result

if __name__ == '__main__':
    seq = [4, 5, 7, 9, 7, 5, 1, 0, 7, -2, 3, -99, 6]
print(mergesort(seq))

19. 循环链表及其头结点

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if head is None:
            return None
        faster, slower = head, head
        flag = False
        while faster.next is not None and faster.next.next is not None:
            faster = faster.next.next
            slower = slower.next
            if slower == faster:
                flag = True
                break
        if flag:
            slower = head
            while slower != faster:
                slower = slower.next
                faster = faster.next
            return slower
        else:
            return None

20. 最长连续上升子序列

class Solution(object):
    def findLengthOfLCIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        if len(nums) == 1:
            return 1
        res = 1
        anchor = 1
        for i in range(1,len(nums)):
            if nums[i] > nums[i-1]:
                anchor = anchor + 1
            else:
                anchor = 1
            res = max(res, anchor)
        return res

21. 最长上升子序列 (非连续)

def fun(nums):
    """
    最长递增子序列
    状态方程:dp[i]代表以第i个位置元素结尾的最长上升子序列,判断第i个位置时,需要比较前面的所有元素,若小于的话,则该元素可以作为一个中转点,把第i个位置拼接上去,长度加1
    """
    dp = [1] * (len(nums) + 1)

    for i in range(len(nums)):
        for j in range(i):
            if nums[j] < nums[i]:
                dp[i] = max(dp[i], dp[j] + 1)

    return max(dp)

print(fun([10, 9, 2, 5, 3, 7, 101, 18]))

22. 最长公共子序列

def longestCommonString(str1, str2):
    if len(str1) == 0 or len(str2) == 0:
        return 0

    m = len(str1)
    n = len(str2)

    dp = np.zeros((m + 1, n + 1))

    for i in range(1, m + 1):
        for j in range(1, n + 1):
            if str1[i - 1] == str2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
            else:
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1])
    return dp[-1][-1]

23. 最长上升子序列的个数

class Solution(object):
    def findNumberOfLIS(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        dp = [1] * len(nums)
        count = [1] * len(nums)
        for i in range(len(nums)):
            for j in range(i):
                if nums[j] < nums[i]:
                    if dp[j] + 1 > dp[i]:
                        dp[i] = max(dp[i], dp[j] + 1)
                        count[i] = count[j]
                    elif dp[j] + 1 == dp[i]:
                        count[i] += count[j]
        ans = 0
        for i in range(len(dp)-1,-1,-1):
            if dp[i] == max(dp):
                ans += count[i]
        return ans

24. 最长连续序列

class Solution(object):
    def longestConsecutive(self, nums):
        """
        用哈希表存储每个端点值对应连续区间的长度
          若数已在哈希表中:跳过不做处理
          若是新数加入:
            取出其左右相邻数已有的连续区间长度 left 和 right
            计算当前数的区间长度为:cur_length = left + right + 1
            根据 cur_length 更新最大长度 max_length 的值
            更新区间两端点的长度值
        """
        hash_dict = dict()

        max_length = 0
        for num in nums:
            if num not in hash_dict:
                left = hash_dict.get(num - 1, 0)
                right = hash_dict.get(num + 1, 0)
                print(left, right)

                cur_length = 1 + left + right
                if cur_length > max_length:
                    max_length = cur_length

                hash_dict[num] = cur_length
                hash_dict[num - left] = cur_length
                hash_dict[num + right] = cur_length

        return max_length


solution = Solution()
print(solution.longestConsecutive([100, 4, 200, 1, 3, 2]))

25. 戳气球

class Solution:
    def maxCoins(self, nums: List[int]) -> int:
        n = len(nums)
        val = [1] + nums + [1]

        @lru_cache(None)
        def getCoins(left, right):
            if left >= right - 1:
                return 0
            best = 0
            for mid in range(left + 1, right):
                total = val[left] * val[mid] * val[right]
                total += getCoins(left,mid) + getCoins(mid,right)
                best = max(best, total)
            return best

        return getCoins(0,n+1)

26. 二叉树遍历

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
class Solution:
    # 先序打印二叉树(递归)
    def preOrderTraverse(node):
        if node is None:
            return None
        print(node.val)
        preOrderTraverse(node.left)
        preOrderTraverse(node.right)
        
    # 先序打印二叉树(非递归)
    def preOrderTravese(node):
        stack = [node]
        while len(stack) > 0:
            print(node.val)
            if node.right is not None:
                stack.append(node.right)
            if node.left is not None:
                stack.append(node.left)
            node = stack.pop()
            
    # 中序打印二叉树(递归)
    def inOrderTraverse(node):
        if node is None:
            return None
        inOrderTraverse(node.left)
        print(node.val)
        inOrderTraverse(node.right)
        
    # 中序打印二叉树(非递归)
    def inOrderTraverse(node):
        stack = []
        pos = node
        while pos is not None or len(stack) > 0:
            if pos is not None:
                stack.append(pos)
                pos = pos.left
            else:
                pos = stack.pop()
                print(pos.val)
                pos = pos.right    
        
    
    # 后序打印二叉树(递归)
    def postOrderTraverse(node):
        if node is None:
            return None
        postOrderTraverse(node.left)
        postOrderTraverse(node.right)
        print(node.val)
        
    # 后序打印二叉树(非递归)
    # 使用两个栈结构
    # 第一个栈进栈顺序:左节点->右节点->跟节点
    # 第一个栈弹出顺序: 跟节点->右节点->左节点(先序遍历栈弹出顺序:跟->左->右)
    # 第二个栈存储为第一个栈的每个弹出依次进栈
    # 最后第二个栈依次出栈
    def postOrderTraverse(node):
        stack = [node]
        stack2 = []
        while len(stack) > 0:
            node = stack.pop()
            stack2.append(node)
            if node.left is not None:
                stack.append(node.left)
            if node.right is not None:
                stack.append(node.right)
        while len(stack2) > 0:
            print(stack2.pop().val)

27. 二叉树的层序遍历

# BFS版本
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        if not root:
            return []
        res = []
        queue = collections.deque()
        queue.append(root)
        while len(queue) > 0:
            length = len(queue)
            layer = []
            for _ in range(length):
                cur = queue.popleft()
                layer.append(cur.val)
                if cur.left is not None:
                    queue.append(cur.left)
                if cur.right is not None:
                    queue.append(cur.right)
            res.append(layer)
        return res

# DFS版本
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def levelOrder(self, root):
        """
        :type root: TreeNode
        :rtype: List[List[int]]
        """
        res = []
        self.level(root, 0, res)
        return res

    def level(self, root, level, res):
        if not root: return
        if len(res) == level: res.append([])
        res[level].append(root.val)
        if root.left: self.level(root.left, level + 1, res)
        if root.right: self.level(root.right, level + 1, res)

28. 不含连续1的非负整数

# dp[i]表示第i位满足要求的数目
# 以7为例,dp[7] = dp[6] + '0' + dp[5] + '01'; 考虑第七位为0,问题转化为dp[6]的子问题,考虑第7位为1,第六位只能为0,则问题转化为求解dp[5]
def solve(num):
    dp = [0] * 30
    dp[0] = 1
    dp[1] = 2
    for i in range(2, 30):
        dp[i] = dp[i - 1] + dp[i - 2]

    i = 30
    pre = 0
    res = 0

    while i >= 0:
        if num & (1 << i):  # 从左往右第一个为1的高位,相当于把改为置为0, 考虑后面所有的情况,也就是dp[i]
            res += dp[i]
            if pre == 1:  # 如果出现相邻两个1的话,则将第二位1置为0,考虑后面的所有情况,也就是dp[i]
                res -= 1  # 这里减一主要是为了和保持格式统一,因为这里面已经包含了num在内了,所以后面先减1在最后加1保持不变,这种情况直接结束
                break
            pre = 1
        else:
            pre = 0
        i -= 1
    return res + 1


print(solve(7))

29. 构造二叉树

已知二叉树前序遍历和中序遍历,求后序遍历

class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


class Solution:
    def reConstructBinaryTree(self, pre, tin):
        """
        返回构造的TreeNode根节点
        :param pre: 
        :param tin: 
        :return: 
        """
        if not pre and not tin:
            return None
        root = TreeNode(pre[0])
        tin_index = tin.index(pre[0])  # 查找性能优化,可以采用dict
        root.left = self.reConstructBinaryTree(pre[1:tin_index + 1], tin[0:tin_index])
        root.right = self.reConstructBinaryTree(pre[tin_index + 1:], tin[tin_index + 1:])
        return root

    def PostTraversal(self, root):
        """
        后序遍历
        :param root: 
        :return: 
        """
        if root is not None:
            self.PostTraversal(root.left)
            self.PostTraversal(root.right)
            print(root.val)


pre = [1, 2, 4, 7, 3, 5, 6, 8]
tin = [4, 7, 2, 1, 5, 3, 8, 6]
S = Solution()
root = S.reConstructBinaryTree(pre, tin)
S.PostTraversal(root)

# 加速版本
class Solution:
    def buildTree(self, preorder, inorder):
        self.dic, self.po = {}, preorder
        for i in range(len(inorder)):
            self.dic[inorder[i]] = i
        return self.recur(0, 0, len(inorder) - 1)

    def recur(self, pre_root, in_left, in_right):
        if in_left > in_right: return # 终止条件:中序遍历为空
        root = TreeNode(self.po[pre_root]) # 建立当前子树的根节点
        i = self.dic[self.po[pre_root]]    # 搜索根节点在中序遍历中的索引,从而可对根节点、左子树、右子树完成划分。
        root.left = self.recur(pre_root + 1, in_left, i - 1) # 开启左子树的下层递归
        root.right = self.recur(i - in_left + pre_root + 1, i + 1, in_right) # 开启右子树的下层递归
        return root # 返回根节点,作为上层递归的左(右)子节点
        

从中序与后序遍历序列构造二叉树

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
 
class Solution(object):
    def buildTree(self, inorder, postorder):
        """
        :type inorder: List[int]
        :type postorder: List[int]
        :rtype: TreeNode
        """
        if not postorder:
            return None
        root = TreeNode(postorder[-1])
        n = inorder.index(root.val)
        root.left = self.buildTree(inorder[:n],postorder[:n])
        root.right = self.buildTree(inorder[n+1:],postorder[n:-1])
        return root

根据前序和后序遍历构造二叉树
class Solution(object):
    def constructFromPrePost(self, pre, post):
        if not pre: return None
        root = TreeNode(pre[0])
        if len(pre) == 1: return root

        L = post.index(pre[1]) + 1
        root.left = self.constructFromPrePost(pre[1:L+1], post[:L])
        root.right = self.constructFromPrePost(pre[L+1:], post[L:-1])
        return root
        
class Solution(object):
    def constructFromPrePost(self, pre, post):
        def make(i0, i1, N):
            if N == 0: return None
            root = TreeNode(pre[i0])
            if N == 1: return root

            for L in xrange(N):
                if post[i1 + L - 1] == pre[i0 + 1]:
                    break

            root.left = make(i0 + 1, i1, L)
            root.right = make(i0 + L + 1, i1 + L, N - 1 - L)
            return root

        return make(0, 0, len(pre))     

30. 合并两个有序数组

class Solution(object):
    def merge(self, nums1, m, nums2, n):
        # 从后往前考虑
        length = m + n - 1
        m -= 1
        n -= 1
        while m >= 0 and n >= 0:
            if nums2[n] > nums1[m]:
                nums1[length] = nums2[n]
                n -= 1
            else:
                nums1[length] = nums1[m]
                m -= 1
            length -= 1
        if n >= 0:  
            nums1[:n+1] = nums2[:n+1]

31. 奇偶链表

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution(object):
    def oddEvenList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        if not head:
            return head
        odd_head = odd = head
        even_head = even = head.next
        while odd.next and even.next:
            # print(odd,even)
            odd.next, even.next = odd.next.next, even.next.next
            odd, even = odd.next, even.next
        odd.next = even_head
        return odd_head

32. 冒泡排序优化版

def BubbleSort(numList):
    if not len(numList):
        return
    for i in range(len(numList)):
        isSwap = False
        j = len(numList) - 1
        while j > i:  # 初级优化,可以考虑从尾部开始,这样可以将以排好序的部分不再检查
            if numList[j] < numList[j - 1]:
                numList[j], numList[j - 1] = numList[j - 1], numList[j]
                isSwap = True
            j -= 1
        if not isSwap:  # 通过设置boolean变量来判断某次循环是否没有出现交换,说明排序已完成
            return numList
    return numList


print(BubbleSort([2, 3, 5, 4, 2, 1, 7, 3]))

33. 最长回文子串

def palindrome(s, i, j):
    while i >= 0 and j < len(s) and s[i] == s[j]:
        i -= 1
        j += 1
    return s[i + 1:j]


def solve(s):
    """
    返回最长回文子串的其中之一,最大长度,所有结果,字典序最小
    :param s:
    :return:
    """
    res = ""
    resList = []
    max_length = 1
    for i in range(len(s)):
        s1 = palindrome(s, i, i)
        s2 = palindrome(s, i, i + 1)
        t = []
        if len(s1) > len(s2):
            t.append(s1)
            mt = s1
        elif len(s1) == len(s2):
            t.extend([s1, s2])
            mt = s1
        else:
            t.append(s2)
            mt = s2

        if len(res) <= len(mt):
            resList.extend(t)
            res = mt
        max_length = max(max_length, len(res))
        resList = [i for i in resList if len(i) == max_length]  # 移除长度更短的结果
    resList = sorted([i for i in resList if len(i) == max_length])  # 返回字典序最小的那个
    return res, resList, max_length, resList[0]


print(solve("bbbaaacccddd"))

34. 回文链表

def isPalindrome(self, head):
    vals = []
    current_node = head
    while current_node is not None:
        vals.append(current_node.val)
        current_node = current_node.next
    return vals == vals[::-1]

35. 高楼扔鸡蛋

# 解法一:
def superEggDrop(self, K: int, N: int) -> int:
        
    memo = dict()
    def dp(K, N):
        if K == 1: return N
        if N == 0: return 0
        if (K, N) in memo:
            return memo[(K, N)]
                            
        # for 1 <= i <= N:
        #     res = min(res, 
        #             max( 
        #                 dp(K - 1, i - 1), 
        #                 dp(K, N - i)      
        #                 ) + 1 
        #             )

        res = float('INF')
        # 用二分搜索代替线性搜索
        lo, hi = 1, N
        while lo <= hi:
            mid = (lo + hi) // 2
            broken = dp(K - 1, mid - 1) # 碎
            not_broken = dp(K, N - mid) # 没碎
            # res = min(max(碎,没碎) + 1)
            if broken > not_broken:
                hi = mid - 1
                res = min(res, broken + 1)
            else:
                lo = mid + 1
                res = min(res, not_broken + 1)

        memo[(K, N)] = res
        return res
    
    return dp(K, N)
   
# 解法二
class Solution(object):
    def superEggDrop(self, K, N):
        """
        f(T,K)代表有T次试验,K个鸡蛋最高能达到的楼层高度N
        状态方程:f(T,K) = f(T-1,K) + f(T-1,K-1) + 1
        - 如果鸡蛋没有碎,则说明这层上面还可以有f(T-1,K)层
        - 如果鸡蛋碎了,则说明这层下面还可以有f(T-1,K-1)层
        """
        if N == 1:
            return 1
        f = [[0] * (K + 1) for _ in range(N + 1)]
        for i in range(1, K + 1):
            f[1][i] = 1
        ans = -1
        for i in range(2, N + 1):
            for j in range(1, K + 1):
                f[i][j] = 1 + f[i - 1][j - 1] + f[i - 1][j]
            if f[i][K] >= N:
                ans = i
                break
        return ans
        
# 解法三:最快的代码
def superEggDrop(K, N):
    """
    K个鸡蛋,尝试一次能到达的楼层数N,类似于压缩二维的DP数组
    dp[k] += dp[k - 1] + 1  
    """
    dp = [0] * (K + 1)
    res = 0
    while dp[K] < N:
        for k in range(K, 0, -1):
            dp[k] += dp[k - 1] + 1
        res += 1

    return res


superEggDrop(3, 10)

36. 最长上升子序列(字典序最小)

import bisect

n = int(input())
nums = list(map(int, input().split()))
dp, helper, length = [1] * n, [nums[0]], 1
# helper 长度为i的LIS末尾的数
# dp 存放以i结尾的序列长度

for i in range(1, n):
    if nums[i] > helper[-1]:
        length += 1
        dp[i] = length
        helper.append(nums[i])
    else:
        # 查找helper数组中第一个大于等于nums[i]的数并替换它
        pos = bisect.bisect(helper, nums[i])
        dp[i] = pos + 1
        helper[pos] = nums[i]

end, length = helper[-1], max(dp)
index = nums.index(end)
res = []

# 回退查找字典序最小的
while index >= 0:
    if not res or (nums[index] < res[-1] and dp[index] == length):
        res.append(nums[index])
        length -= 1
    if not length:
        break
    index -= 1
print(' '.join(map(str, res[::-1])))

37. 最长上升子序列(所有序列)

from copy import deepcopy

nums = [10, 9, 2, 5, 3, 7, 101, 18]

length = len(nums)

dp = [1] * length

max_length = 1
allSeqList = []
for i in range(length):
    local = []
    index = -1
    for j in range(i):
        if nums[i] > nums[j]:
            if dp[j] + 1 > dp[i]:
                local.clear()
                index = j
                local.extend(deepcopy(allSeqList[j]))
                for item in local:
                    item.append(nums[i])
                dp[i] = dp[j] + 1
            elif dp[j] + 1 == dp[i]:
                more = deepcopy(allSeqList[j])
                for item in more:
                    item.append(nums[i])
                local.extend(more)

    if index == -1:
        tmp = [nums[i]]
        local.append(tmp)

    allSeqList.append(deepcopy(local))
    max_length = max(dp[i], max_length)

res = []
for i in range(length):
    if dp[i] == max_length:
        res.extend(allSeqList[i])
print(res)

38. 所有的递增子序列

def findSubsequences(nums):
    if not nums:
        return []
    pres = {(nums[0],)}
    for j in pres:
        print(j[-1])
    for i in nums[1:]:
        print({j + (i,) for j in pres if j[-1] <= i})
        pres.update({j + (i,) for j in pres if j[-1] <= i})
       pres.add((i,))
    return [list(i) for i in pres if len(i) > 1]


print(findSubsequences([4, 6, 7, 7]))

39. 连续子数组和为K的个数

from collections import defaultdict

def subArraySum(nums, k):
    n = len(nums)
    dict_nums = defaultdict(int)
    dict_nums[0] = 1
    ans = 0
    sum_i = 0
    for i in range(n):
        sum_i += nums[i]
        sum_j = sum_i - k
        if dict_nums[sum_j]:
            ans += dict_nums[sum_j]
        dict_nums[sum_i] += 1

    return ans


print(subArraySum([1, 1, 1], 2))

40. 全排列

from copy import deepcopy


class Combination(object):
    def __init__(self, nums, track):
        self.res = []
        self.nums = nums
        self.n = len(nums)
        self.track = track

    def backTrace(self):
        if self.n == len(self.track):
            self.res.append(deepcopy(self.track))
            return
        for i in range(self.n):
            if self.nums[i] in self.track:
                continue
            self.track.append(self.nums[i])
            self.backTrace()
            self.track.remove(self.nums[i])


combination = Combination([1, 2, 3], [])
combination.backTrace()
print(combination.res)

41. 区间交集

class Solution(object):
    def intervalIntersection(self, A, B):
        """
        :type A: List[List[int]]
        :type B: List[List[int]]
        :rtype: List[List[int]]
        """
        n = len(A)
        m = len(B)
        i, j = 0, 0
        res = []
        while i < n and j < m:
            a1, a2 = A[i][0], A[i][1]
            b1, b2 = B[j][0], B[j][1]
            # 区间有交集
            if b2 >= a1 and b1 <= a2:
                res.append([max(a1,b1),min(a2,b2)])
            # 指针移动
            if a2 >= b2:
                j += 1
            else:
                i += 1
        return res

42. 洗牌算法

from random import randint


def shuffle(arr):
    n = len(arr)
    for i in range(n):
        rand = randint(i, n - 1)
        arr[i], arr[rand] = arr[rand], arr[i]
    return arr

43. 滑动谜题

from collections import defaultdict, deque


class Solution(object):
    def slidingPuzzle(self, board):
        start = ''.join(map(str, board[0])) + ''.join(map(str, board[1]))
        target = "123450"
        queue = deque([start])
        visited = defaultdict(int)
        neighbor = [[1, 3], [0, 4, 2], [1, 5], [0, 4], [3, 1, 5], [4, 2]]
        visited[start] = 1
        step = 0
        while queue:
            for i in range(len(queue)):
                cur = queue.popleft()
                if target == cur:
                    return step
                idx = cur.index('0')
                for adj in neighbor[idx]:
                    new_board = [i for i in cur]
                    new_board[adj], new_board[idx] = new_board[idx], new_board[adj]
                    new_board = ''.join(new_board)
                    if not visited[new_board]:
                        queue.append(new_board)
                        visited[new_board] = 1
            step += 1
        return -1

44. 高效素数计算

import math


def SieveOfEratosthenes(n):
    is_prime = [True for _ in range(n)]
    for i in range(2, int(math.sqrt(n)) + 1):
        if is_prime[i]:
            for j in range(i ** 2, n, i):
                is_prime[j] = False
    cnt = 0
    for i in range(2, n):
        if is_prime[i]:
            cnt += 1
            print(i)
    return cnt


n = 30
print(SieveOfEratosthenes(n))

45. 接雨水问题

class Solution(object):
    def trap(self, height):
        """
        :type height: List[int]
        :rtype: int
        """
        if not height:
            return 0
        n = len(height)
        l_max = height[0]
        r_max = height[-1]
        left = 0
        right = n - 1
        ans = 0
        # ans = min(l_max, r_max) + height[i]
        while left <= right:
            l_max = max(l_max, height[left])
            r_max = max(r_max, height[right])
            if l_max < r_max:
                ans += l_max - height[left]
                left += 1
            else:
                ans += r_max - height[right]
                right -= 1
        return ans

46. 最长回文子序列的长度

def solve(s):
    """
    dp[i][j] = s[i....j]最长回文子序列的长度
    :param s:
    :return:
    """
    n = len(s)
    dp = [[0] * n for _ in range(n)]
    for i in range(n):
        dp[i][i] = 1
    # 先从底向上推,再从左向右推
    for i in range(n - 1, -1, -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]


print(solve("bbbab"))

47. 跳跃游戏

def jump(nums):
    n = len(nums)
    end = 0
    farthest = 0
    jumps = 0
    for i in range(n - 1):
        farthest = max(nums[i] + i, farthest)
        if end == i:
            end = farthest
            jumps += 1
    return jumps


print(jump([2, 3, 1, 1, 4]))

48. k个一组反转链表

class Solution(object):
    def reverseKGroup(self, head, k):
        """
        k个一组反转链表
        """
        if not head:
            return None
        a, b = head, head
        for i in range(k):
            if not b:
                return head
            b = b.next
        newHead = self.reverse(a, b)
        a.next = self.reverseKGroup(b, k)
        return newHead

    def reverse(self, a, b):
        """
        反转节点a到节点b之间的节点
        :param a:
        :param b:
        :return:
        """
        pre = None
        cur = a
        while cur != b:
            t = cur.next
            cur.next = pre
            pre = cur
            cur = t
        return pre

49. 判断括号的合法性

def isValid(s):
    left = []
    for i in s:
        if i in ['(', '{', '[']:
            left.append(i)
        else:
            if left and leftOf(i) == left[-1]:
                left.pop(-1)
            else:
                return False

    return True if not left else False


def leftOf(c):
    if c == '}':
        return '{'
    elif c == ')':
        return '('
    else:
        return '['


print(isValid("()[]{}"))

50. 寻找缺失和重复的元素

def findErrorNums(nums):
    n = len(nums)
    dup = -1
    for i in range(n):
        index = abs(nums[i]) - 1
        if nums[index] < 0:
            dup = abs(nums[i])
        else:
            nums[index] *= -1
    missing = -1
    for i in range(n):
        if nums[i] > 0:
            missing = i + 1

    return dup, missing


print(findErrorNums([0, 4, 1, 4, 2]))

51. 无限序列中随机抽取元素

import random


def solve(head, k):
    """
    无限序列中随机抽取元素
    :param head:
    :param k:
    :return:
    """
    res = []
    p = head
    for i in range(k):
        if not p:
            break
        res[i] = p.val
        p = p.next

    i = k
    while p:
        i += 1
        j = random.randint(0, i)
        if j < k:
            res[j] = p.val
        p = p.next
    return res

52. 高效判定子序列

import bisect
from collections import defaultdict


def isSubsequence(s, t):
    m = len(s)
    n = len(t)
    index = defaultdict(list)
    for i in range(n):
        index[t[i]].append(i)
    j = 0
    for i in range(m):
        if not index[s[i]]:
            return False
        pos = bisect.bisect_left(index[s[i]], j)
        if pos == len(index[s[i]]):
            return False
        j += index[s[i]][pos] + 1
    return True

print(isSubsequence("abc", "ahbgdc"))

53. 并查集

class UF(object):
    """
    并查集算法
    """

    def __init__(self, n):
        self.count = n
        self.parent = [i for i in range(n)]
        self.size = [1] * n

    def union(self, p, q):
        rootP = self.find(p)
        rootQ = self.find(q)

        if rootP == rootQ:
            return

        # 优化做法把小树接到大树下面
        if self.size[rootP] > self.size[rootQ]:
            self.parent[rootQ] = rootP
            self.size[rootP] += self.size[rootQ]
        else:
            self.parent[rootP] = rootQ
            self.size[rootQ] += self.size[rootP]

        self.count -= 1

    def find(self, x):
        while self.parent[x] != x:
            # 路径压缩
            self.parent[x] = self.parent[self.parent[x]]
            x = self.parent[x]
        return x

    def connected(self, p, q):
        rootP = self.find(p)
        rootQ = self.find(q)
        return rootP == rootQ

    def count(self):
        return self.count


class Solution(object):
    def solve(self, board):
        if not board:
            return
        m = len(board)
        n = len(board[0])
        uf = UF(m * n + 1)
        dummy = m * n
        for i in range(m):
            if board[i][0] == 'O':
                uf.union(i * n, dummy)
            if board[i][n - 1] == 'O':
                uf.union(i * n + n - 1, dummy)

        for i in range(n):
            if board[0][i] == 'O':
                uf.union(i, dummy)
            if board[m - 1][i] == 'O':
                uf.union(n * (m - 1) + i, dummy)

        direction = [[1, 0], [-1, 0], [0, 1], [0, -1]]
        for i in range(1, m - 1):
            for j in range(n - 1):
                if board[i][j] == 'O':
                    for k in range(4):
                        x = i + direction[k][0]
                        y = j + direction[k][1]
                        if board[x][y] == 'O':
                            uf.union(x * n + y, i * n + j)

        for i in range(1, m - 1):
            for j in range(1, n - 1):
                if not uf.connected(dummy, i * n + j):
                    board[i][j] = 'X'

        return board

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值