剑指offer分类代码总结

目录

Day1 栈与队列(简单)

09 两个栈实现队列

栈只能在栈顶添加或删除元素(对应list中的append和pop都是在列表的尾部进行操作的),而将栈A中的元素转移到栈B可对A中的元素进行倒序。B为空时才将A压入B顺序才不会乱。

class CQueue:

    def __init__(self):
        self.A = []
        self.B = []

    def appendTail(self, value: int) -> None:
        self.A.append(value)

    def deleteHead(self) -> int:
        if self.B: return self.B.pop()
        while self.A:
            self.B.append(self.A.pop())
        return self.B.pop() if self.B else -1
30 包含min函数的栈

#辅助栈的长度可以变得更短,只有该值比辅助栈中所有的值都小才压入辅助栈
#只有push和pop改变栈的元素,push的时候只有B为空或者该值小于B顶元素才压入B(因为只要最小的,前面有比该元素小就不会返回该值);
#pop的时候,B顶元素只有等于要被pop的值才会弹出B,不然当前最小值还是B顶元素

class MinStack:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.A = []
        self.B = []

    def push(self, x: int) -> None:
        self.A.append(x)
        if (self.B and self.B[-1] >= self.A[-1]) or not self.B:
            self.B.append(x)


    def pop(self) -> None:
        if self.A[-1] == self.B[-1]: self.B.pop()
        return self.A.pop()

    def top(self) -> int:
        return self.A[-1]

    def min(self) -> int:
        return self.B[-1]

Day2 链表(简单)

06 从尾到头打印链表

方法一:遍历,在列表头用list.insert(index, obj)插入

​ 或用append在尾部插入,然后res.reverse()、res[::-1]

class Solution:
    def reversePrint(self, head: ListNode) -> List[int]:
        res = []
        while head:
            res.append(head.val)
            head = head.next
        return res[::-1]

方法二:递归

def reversePrint(self, head: ListNode) -> List[int]:
        if not head: return []
        return self.reversePrint(head.next) + [head.val]
24 反转链表

方法一:双指针。用cur指向pre,然后pre指向新的链表头(cur),cur指向cur.next

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre = None
        cur = head
        while cur:
            tmp = cur.next
            cur.next = pre
            pre = cur
            cur = tmp
        return pre

方法二:递归

#递归,知道遇到None才返回,返回时修改指针指向
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        def recur(cur, pre):           #*
            if not cur: return pre          # 终止条件
            res = recur(cur.next, cur) #**  # 递归后继节点
            cur.next = pre                  # 修改节点引用指向,这里的cur是*中的cur,不是**中的cur
            return res                      # 返回反转链表的头节点
        
        return recur(head, None)            # 调用递归并返回
        #注意递归函数不是循环,在**中返回后,会不断执行cur.next = pre(和return res,返回的res始终是5)
35 复杂链表的复制

方法一:哈希表。遍历原链表,复制其节点的val生成新的节点,保存在哈希表。然后再根据原链表的顺序,修改新节点next和random的指向

方法二:复制每一个节点,将其插到对应节点的下一个。以便random找得到,最后再拆分

每个操作基本都涉及链表的遍历

class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        if not head: return
        dic = {}
        cur = head
        while cur:
            dic[cur] = Node(cur.val) #字典的键是原节点,字典的值是新节点
            cur = cur.next
        
        cur = head
        while cur:
            dic[cur].next = dic.get(cur.next) #字典的键是原节点,字典的值是新节点 #dic.get()返回指定键的值
            dic[cur].random = dic.get(cur.random)
            cur = cur.next
        return dic[head]

#方法二:复制每一个节点,并连接到对应节点的下一个。以便random找得到,最后再拆分
class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        if not head: return
        cur = head
        # 1. 复制各节点,并构建拼接链表
        while cur:
            tmp = Node(cur.val)
            tmp.next = cur.next
            cur.next = tmp
            cur = tmp.next   #或者cur.next.next 注意不是cur.next

        # 2. 连接random
        cur = head
        while cur:
            if cur.random:
                cur.next.random = cur.random.next  #cur.next.random = cur.random是错的,cur.random是原来的,下一个才是新建复制的节点
            cur = cur.next.next
        
        # 3. 拆分链表,提取出结果
        res = cur= head.next
        while cur.next:
            cur.next = cur.next.next
            cur = cur.next
               
        return res

Day3 字符串(简单)

05 替换空格

方法一:遍历,替换

方法二:使用str.split()函数。python的split()方法通过指定的分隔符对字符串进行分割,并将分割后的元素保存在一个列表中

"%20".join(s.split(' '))
58-II 旋转字符串

方法一:切片

return s[n:len(s)+1] + s[0:n] # 或s[n:] + s[:n]

方法二:列表遍历(若不能用切片)

class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        lst = []
        for i in range(n,len(s)):
            lst.append(s[i])
        for i in range(n):
            lst.append(s[i])
        return ''.join(lst)

方法三:字符串遍历拼接。

字符串是 “不可变对象” 。因此,每轮遍历拼接字符时,都需要新建一个字符串;因此,系统 需申请 N*N* 次内存 ,数据量较大时效率低下

class Solution:
    def reverseLeftWords(self, s: str, n: int) -> str:
        st = str()
        for i in range(n,len(s)):
            st += s[i]
        for i in range(n):
            st += s[i]
        return st

Day4 查找算法(简单)

03 数组中重复的数字

方法一:利用set()。设置一个set(),一个个加入,遇到相同的则返回

方法二:排序后比较相同的两个数

方法三:将索引与数值对应

class Solution:
    def findRepeatNumber(self, nums: List[int]) -> int:
        i = 0
        while i < len(nums):
            if nums[i] == i: 
                i += 1
                continue   #目的就是让索引等于num[i]
            if nums[i] == nums[nums[i]] :return nums[i]    #当前值,等于另一个以当前值为索引的值,即冲突了
            tmp = nums[nums[i]]
            nums[nums[i]] = nums[i]
            nums[i] = tmp
            # i += 1   #这里不能加一,要交换到当前值等于索引才能加一
        return -1
@二分查找
53-I 在排序数组中查找数字 I

统计一个数字在排序数组中出现的次数。

方法一:二分法

基础二分查找:

def binary_search(nums, target):
    i, j = 0, len(nums) - 1
    while i <= j:  #没数了才停,有一个数都还要处理
        m = (i+j) // 2
        if nums[m] == target: return m
        elif nums[m] < target: i = m + 1
        else: j = m - 1
    return None
my_nums = [1,3,5,7,12]
print(binary_search(my_nums,12))
#i=0,j=4,m=2;5<12,执行i=3
#i=3,j=4,m=3;7<12,执行i=4
#i=4,j=4,m=4;12==12,返回4  ,循环条件要有等于号才会执行到这一步

本题用两次二分法找到左右边界

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        i, j = 0, len(nums) - 1
        while i <= j:
            m = (i + j) // 2
            if nums[m] <= target: i = m + 1
            #这里是“小于等于”,目的是为了确定右边界,就是说当mid等于target时,因为不确定后面还有没有target,所以同样需要左边收缩范围
            else: j = m -1
        right = i
        i = 0   #注意这里i要重新等于0
        while i <= j:
            m = (i + j) // 2
            if nums[m] >= target: j = m - 1
            else: i = m + 1
        left = j

        return right - left -1
#先找左边界也一样

34 在排序数组中查找元素的第一个和最后一个位置

同样的做法!

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        if not nums: return [-1, -1]
        i, j = 0, len(nums) -1
        while i <= j:  #找左边界
            m = (i+j) // 2
            if nums[m] >= target: j = m - 1 #等于的时候还要继续减
            else:i = m + 1
        left = j + 1

        j = len(nums) -1
        while i <= j:  #找右边界
            m = (i+j) // 2
            if nums[m] <= target: i = m + 1
            else: j = m - 1
        right = i - 1

        return [-1, -1] if left >=len(nums) or nums[left] != target else [left, right]
53-II 0~n-1中缺失的数字

方法一:二分法。递增排序数组,想到用二分法

[0,1,2,3,4,5,6,7,910] 右子数组910的首位元素9的索引就是结果
class Solution:
    def missingNumber(self, nums: List[int]) -> int:
        i, j = 0, len(nums) - 1
        while i <= j:
            m = (i + j) // 2
            if nums[m] == m: i = m + 1 
            else: j = m - 1  
        return i #或者return j + 1

Day5 查找算法(中等)

04 二维数组中的查找
class Solution:
    def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
        i, j = len(matrix) - 1, 0
        while i >= 0 and j < len(matrix[0]): #注意这里i是逐渐减小的,所以边界是>=0
            if matrix[i][j] == target: return True
            elif matrix[i][j] < target: j += 1
            else: i -= 1
        return False
*11 旋转数组中的最小数字

方法一:遍历比较相邻的两个数

方法二:二分法。也是有序的数组

注意这里不用number[m] 与左边比较

#二分法。排序数组用二分查找!
class Solution:
    def minArray(self, numbers: List[int]) -> int:
        i, j = 0, len(numbers)-1
        while i< j:  #没有等号
            m = (i + j) // 2
            #注意都是和numbers[j]比较!
            if numbers[m] > numbers[j]: i = m + 1  #此时m一定在左排序数组中,即旋转点x一定在[m+1,j]闭区间内
            #注意不是m+1
            elif numbers[m] < numbers[j]: j = m     #此时m一定在右排序数组中,即旋转点x一定在[i,m]闭区间内
            else: j -= 1  #numbers[m]==numbers[j]时,去掉j对结果没影响
        return numbers[i]
50 第一个只出现一次的字符

方法一:用字典标记键是否在字典里面

class Solution:
    def firstUniqChar(self, s: str) -> str:
        dic = {}
        for c in s:
            dic[c] = not c in dic
        for k, v in dic.items():
            if v: return k
        return ' '

Day6 搜索与回溯算法(简单)

@层序遍历
32-I 从上到下打印二叉树I

方法一:层序遍历(广度优先搜索)

借助队列先入先出的特性来实现

class Solution:
    def levelOrder(self, root: TreeNode) -> List[int]:
        if not root: return []
        res, queue = [], [root]
        while queue:
            node = queue.pop(0)
            res.append(node.val)
            if node.left: queue.append(node.left)
            if node.right: queue.append(node.right)
        return res
32-II 从上到下打印二叉树II

方法一:层序遍历(广度优先搜索)

区别是,再设置一层循环来处理同一层的节点

#要动手逐步写才能想到细节是怎样的
#凭空很难把整个过程都想出来,大脑没能模拟出完整的层先过程,不代表这个方法不行,动手做才知道
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root: return []
        queue, res = [root], []
        while queue:
            tmp = []
            num = []
            for node in queue:
                num.append(node.val)
                if node.left: tmp.append(node.left)
                if node.right: tmp.append(node.right)
            queue = tmp
            res.append(num)
        return res

#写法二:
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root: return []
        res, queue = [], [root]
        while queue:
            tmp = []
            for _ in range(len(queue)): #一开始就得到当前层的长度,即使下面再添加节点也不影响
                node = queue.pop(0)
                tmp.append(node.val)
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
            res.append(tmp)
        return res
32-III 从上到下打印二叉树III

方法一:层序遍历

用flag标记层数,偶数层翻转在append到结果

方法二:层序遍历

奇数层在尾部插入,偶数层在头部插入

#添加tmp的元素时,奇数层添加到尾部,偶数层添加到头部
#1.双端队列tmp = collections.deque(), tmp.appendleft(val), tmp.append(val)
#2.列表也可以,tmp = [], tmp.insert(0,val)
#勿臆断:偶数层不一定要从右到左遍历节点,从左到右遍历,记录数据时放头或放尾部就有不一样的顺序
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root: return []
        res, queue = [], collections.deque() #queue=[]也可
        queue.append(root)
        while queue:
            # tmp = collections.deque()
            tmp = []
            for _ in range(len(queue)):
                node = queue.popleft()
                if len(res) & 1:
                    # tmp.appendleft(node.val)
                    tmp.insert(0,node.val)
                else:
                    tmp.append(node.val)
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
            # res.append(list(tmp))  #注意这里要将队列转化为list
            res.append(tmp)
        return res

Day7 搜索与回溯算法

26 树的子结构

判断B是不是A的子结构

方法一:递归

class Solution:
    def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
        #recur函数是确定起点为A,B后开始比
        #最后递归调用self.isSubStructure(A.left, B) or self.isSubStructure(A.right, B),是为了遍历不同的节点作为比较起点
        def recur(A, B):  #判断如果A、B根节点相同,B是不是A的子结构
            if not B: return True
            if not A or A.val != B.val: return False
            return recur(A.left, B.left) and recur(A.right, B.right)
        
        #根节点相同直接进入比较,根节点不同,看B是不是A的左、右子树的子结构
        return bool(A and B) and (recur(A, B) or self.isSubStructure(A.left, B) or self.isSubStructure(A.right, B))
        #bool(A and B),A为空或B为则直接返回False
        #B为空直接返回False因为空树不为子结构,注意后面的几个or条件要用括号括起来

        #满足以下条件之一即可
        #1.recur(A, B):根节点相同的话直接进入比较,从A、B开始有子结构
        #2.isSubStructure(A.left, B):A左子树的根与B的根相同,从A.left、B开始有子结构
        #3.isSubStructure(A.right, B): A右子树的根与B的根相同,从A.left、B开始有子结构
27 二叉树的镜像

输入一个二叉树,输出一个它的的镜像

方法一:递归

class Solution:
    def mirrorTree(self, root: TreeNode) -> TreeNode:
        if not root: return
        tmp = root.left
        root.left = self.mirrorTree(root.right) #root的左子树为右子树的镜像
        root.right = self.mirrorTree(tmp)  #root的右子树为左子树的镜像
        return root #最后的结果要返回当前的root

方法二:层序遍历,设置一个栈来逐个遍历、处理每个节点,将节点的左右子树交换

class Solution:
    def mirrorTree(self, root: TreeNode) -> TreeNode:
        if not root: return 
        stack = [root]
        while stack:
            node = stack.pop()
            #将节点的左右子树都压入栈来遍历每个节点,并进行左右子树的交换
            if node.left: stack.append(node.left)
            if node.right: stack.append(node.right)
            tmp = node.left
            node.left = node.right
            node.right = tmp
        return root
28 对称的二叉树

判断一个树是不是对称的

方法一:递归

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        def recur(L, R):
            #终止条件:遍历完所有节点、空了返回True,遇到不相等的直接返回False
            if not L and not R: return True                    #终止条件1:当 L和 R同时越过叶节点(都为空),此树从顶至底的节点都对称,因此返回 true
            if not L or not R or L.val != R.val: return False  #终止条件2:其中一个为空、或者不相等
            #如果L/R不为空且相等,则进入递归,判断子树的节点是否相等
            return recur(L.left, R.right) and recur(L.right, R.left)  #如果前面的节点都满足,后面遇到一个返回False的,最终结果返回的正是这个False

#注:没有判断两者相等,然后返回True,因为不相等时返回False,若所有对应节点都相等,最后会返回True

        return recur(root.left, root.right) if root else True

Day8 动态规划(简单)

10-I 斐波那契数列

方法一:动态规划:

#写法一:
class Solution:
    def fib(self, n: int) -> int:
        a, b = 0, 1
        for _ in range(n):
            # a, b = b, a + b  #这里是同时赋值的,即a+b的a是原来的a,而不是a=b后的a
            # a等于上一个b,要求的新b等于上一个b加当前b
            tmp = a
            a = b
            b = tmp + b #tmp保存的a是上一个b,F(N) = F(N-2) + F(N-1)
        return a % 1000000007
#写法二:
class Solution:
    def fib(self, n: int) -> int:
        a, b = 0, 1
        if n == 0: return 0
        if n == 1: return 1
        for i in range(2, n+1):
            res = a + b
            a = b
            b = res
        return res%1000000007

方法二:递归,计算量大

class Solution:
    def fib(self, n: int) -> int:
        if n == 0:return 0
        elif n == 1:return 1
        else:
            return (self.fib(n-1) + self.fib(n-2))%(10**9+7)

方法三:设置一个list计算,实际上也是动态规划

class Solution:
    def fib(self, n: int) -> int:
        if n == 0:return 0
        if n == 1:return 1
        lst = [0,1]
        for i in range(2,n+1):
            lst.append((lst[i-1]+lst[i-2])%1000000007)
        return lst[n]
10-I 青蛙跳台阶问题

一次可以跳1阶也可以跳两个台阶,问有多少中跳法

方法一:递归,超出时间限制

class Solution:
    def numWays(self, n: int) -> int:
        if n == 0 or n == 1: return 1
        return (self.numWays(n-1) + self.numWays(n-2))%1000000007

方法二:动态规划

class Solution:
    def numWays(self, n: int) -> int:
        if n == 0 or n == 1: return 1
        fn = [1,1]
        for i in range(2, n+1):
            fn.append((fn[i-1] + fn[i-2]) % 1000000007)
        return fn[n]

class Solution:
    def numWays(self, n: int) -> int:
        a, b = 1,1
        for i in range(n):
            tmp = a
            a = b
            b = (tmp + b) % 1000000007
        return a
63 股票的最大利益

方法一:动态规划

前 i日最大利润 dp[i]等于前i-1日的利益dp[i-1]和第i日卖出的最大利润中的最大值

不需要找出具体在哪一天买入,那一天卖出

考虑当前日的利润就好,要么等于dp[i-1], 要么等于当前日的价格减去之前价格的最低值

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if not prices: return 0
        cost = prices[0]
        res = 0
        for i in range(1,len(prices)):
            cost = min(cost, prices[i])
            res = max(res, prices[i] - cost)
        return res
#k神:
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        cost, profit = float("+inf"), 0
        for price in prices:
            cost = min(cost, price)
            profit = max(profit, price - cost)
        return profit

Day9 动态规划(中等)

42 连续子数组的最大和(23字节真题)

方法一:动态规划

当前和为sum,对应dp[i],dp[i]要么等于dp[i-1]+当前值,要么等于当前值,取决于dp[i]是否为负数(是否对当前和有贡献)

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        sum  = maxSum = nums[0]
        for i in nums[1:]:
            if sum + i < i:  #这里的sum相当于dp[i],根据i的不同情况来更新
                sum = i
            else: sum += i
            if sum > maxSum:
                maxSum = sum
        return maxSum
47 礼物的最大价值

方法一:动态规划

f(i,j)=max[f(i,j−1), f(i−1,j)] + grid(i,j)

class Solution:
    def maxValue(self, grid: List[List[int]]) -> int:
        #直接修改grid来保存dp
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if i == 0 and j == 0: continue
                elif i == 0: grid[i][j] += grid[i][j-1]
                elif j == 0: grid[i][j] += grid[i-1][j]
                else: grid[i][j] += max(grid[i-1][j], grid[i][j-1])
        return grid[-1][-1]

Day10 动态规划(中等)

46 把数字翻译成字符串

求多少中翻译方式

方法一:动态规划

不用具体想怎么划分,应该想递推方式

class Solution:
    def translateNum(self, num: int) -> int:
        s = str(num)
        dp = [0] * (len(s)+1)
        dp[0] = 1
        dp[1] = 1
        for i in range(2, len(s) + 1):  #2~len(s)
            tmp = s[i-2: i]
            if "10" <= tmp <= "25":
                dp[i] = dp[i-2] + dp[i-1]
            else:
                dp[i] = dp[i-1]
        return dp[len(s)]
48 最长不含重复字符的字符串

求最长不含重复字符串的子字符串的长度

方法一:动态规划

设当前位置是j,s[j]左边最靠近且相同的字符所在的位置是i,dp[j]要么等于j - i,要么等于d[j-1] + 1。取决于s[j]是否在dp[j-1]对应的子字符串内

通过字典记录,检查当前元素在前面出现的最近的位置

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        dic = {}
        res = tmp = 0
        for j in range(len(s)):
            i = dic.get(s[j],-1) #dic.get获取键s[j]的值,若不存在则返回第二参数-1
            dic[s[j]] = j
            tmp = tmp + 1 if j - i > tmp else j - i
            res = max(tmp, res)
        return res

Day 11 双指针(简单)

18 删除链表得的节点

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点

class Solution:
    def deleteNode(self, head: ListNode, val: int) -> ListNode:
        if head.val == val: return head.next
        n1 = head
        n2 = head.next
        while n2:
            if n2.val == val:
                n1.next = n2.next
                return head
            n1 = n1.next #或n1 = n2
            n2 = n2.next
22 链表中的倒数第k个节点

方法一:遍历统计长度n,然后走n-k步

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        cur = head
        n = 0
        while cur:
            n += 1
            cur = cur.next
        
        for _ in range(n - k):
            head = head.next
        return head

方法二:双指针

前指针 former 先向前走 kk 步(结束后,双指针 formerlatter 间相距 kk 步)。

class Solution:
    def getKthFromEnd(self, head: ListNode, k: int) -> ListNode:
        forward = later = head
        for _ in range(k):
            forward = forward.next
        
        while forward:
            forward = forward.next
            later = later.next
        return later

Day11 双指针(简单)

25 合并两个排序的链表

要使合并后的链表还是递增的

方法一:双指针

对两个链表各设置一个指针来遍历,并比较大小

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        res = cur = ListNode(0)
        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 if l1 else l2
        return res.next
52 两个链表的第一个公共节点

方法一:设置两个指针分别指向headA和headB,第一个走完后交替指向headB,第二个走完后指向headB,最终回相遇到共同节点

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        node1, node2 = headA, headB
        while node1 != node2:
            node1 = node1.next if node1 else headB  #注意不是if node1.next
            node2 = node2.next if node2 else headA
        return node1

Day13 双指针(简单)

21 调整数组顺序使奇数位于偶数前面

方法一:双指针

两个指针分别指向左右两端,交换位置

class Solution:
    def exchange(self, nums: List[int]) -> List[int]:
        if not nums: return []
        i, j = 0, len(nums)-1
        while i != j:
            if nums[i] % 2:
                i += 1
                continue
            if not nums[j] % 2:
                j -= 1
                continue
            nums[i], nums[j] = nums[j], nums[i]
        return nums
57 和为s的两个数

排序数组中找出和为target的两个数

方法一:双指针

分别指向两端。如果能想到双指针,则变得非常简单

合理性:最大的加最小的都比target大,所以最大的数舍弃;最小的加最大的都比target小,所以最小的舍弃

#错解
# class Solution:
#     def twoSum(self, nums: List[int], target: int) -> List[int]:
#         i = 0
#         while i <= len(nums)-1 and nums[i] <= target:
#             res = [nums[i]]
#             j = i + 1
#             while j <= len(nums)-1 and nums[j] <= target:
#                 if (nums[i] + nums[j]) == target:
#                     res.append(nums[j])
#                     return res
#                 j += 1
#             i += 1

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        i, j = 0, len(nums) - 1
        while i < j:
            if nums[i] + nums[j] == target:
                return [nums[i], nums[j]]
            elif nums[i] + nums[j] < target:
                i += 1
            else:
                j -= 1
        return
58-I 翻转单词顺序

方法一:分割 + 倒序

s.strip()去掉首尾的空格

split(’ ')解决不了单词间多空格的问题,用split();

反转的时候不要一个个append,直接用reverse 或者lst[::-1]

class Solution:
    def reverseWords(self, s: str) -> str:
        s = s.strip()
        lst = s.split()
        return ' '.join(lst[::-1])

方法二:双指针找边界

从后面往前遍历

class Solution:
    def reverseWords(self, s: str) -> str:
        s = s.strip()
        i = j = len(s)-1
        res = []
        while i >= 0:
            while i >= 0 and s[i] != ' ': i -= 1  #注意这里也要保证i >= 0 ,否则出大问题
            res.append(s[i+1:j+1])
            while s[i] ==' ': i -= 1
            j = i
        return ' '.join(res)

Day14 搜索与回溯算法(中等)

12 矩阵中的路径*

查找矩阵中是否有给出的word

方法一:递归+剪枝(不符合条件则返回False)

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        def dfs(i, j, k):
            if not 0 <= i < len(board) or not 0 <= j < len(board[0]) or board[i][j] != word[k]: return False
            board[i][j] = ' '
            if k == len(word) - 1: return True
            res = dfs(i-1, j, k+1) or dfs(i+1, j, k+1) or dfs(i, j-1, k+1) or dfs(i, j+1, k+1)
            board[i][j] = word[k]
            return res
        
        for i in range(len(board)):  #需要枚举单词的起点
            for j in range(len(board[0])):
                if dfs(i,j,0): return True
        return False
13 机器人的运动范围

方法一:深度优先搜索DFS

递归朝一个方向搜索再回溯

暴力模拟所有路径,判断是否满足条件,不满足则返回0,满足的则最后+1

class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:
        def dfs(i, j, si, sj):
            if i >= m or j >= n or si + sj > k or (i,j) in visited: return 0
            visited.add((i, j))
            return 1 + dfs(i+1, j ,si + 1 if (i+1) % 10 else si - 8, sj) +dfs(i, j + 1, si, sj + 1 if (j + 1) % 10 else sj - 8)

        visited = set()
        return  dfs(0, 0, 0, 0)

方法二:广度优先搜索BFS

队列用list实现,从首端pop出,在末尾append

判断是否满足条件,满足条件的放到集合里,最后统计集合长度

把每格的坐标i,j及其位数之和si,sj作为元组放到队列中

向下向右搜索

class Solution:
    def movingCount(self, m: int, n: int, k: int) -> int:
        queue = [(0, 0, 0 , 0)]
        visited = set() #满足条件的放到集合里,最后统计集合长度
        while queue:
            i, j, si, sj = queue.pop(0)
            if i >= m or j >= n or si + sj > k or (i,j) in visited: continue
            visited.add((i, j))
            queue.append((i + 1, j ,si + 1 if (i + 1) % 10 else si - 8, sj))
            queue.append((i, j + 1, si, sj + 1 if (j + 1) % 10 else sj - 8))
        return len(visited)

Day15 搜索与回溯算法(中等)

34 二叉树中和为某一值的路径

方法一:递归。

肯定是要遍历的

先序遍历每个节点的值,并记录为path,检查path是否满足条件,满足的话添加到res;

然后处理左右节点

class Solution:
    def pathSum(self, root: TreeNode, target: int) -> List[List[int]]:
        res, path = [], []
        def recur(root, tar):
            if not root: return  #无返回值的return,作用是强制结束函数的调用过程,并且返回调用者现场
            path.append(root.val)
            tar -= root.val
            if tar == 0 and not root.left and not root.right:
                res.append(list(path))  #注意这里的list
            recur(root.left, tar)
            recur(root.right, tar)
            path.pop()   #没有return语句的函数或者方法,结束之后返回值是None.不需要用到返回值,关键是结束当前函数调用过程,并返回调用现场

        recur(root, target)
        return res
@打印中序遍历
36 二叉搜索树与双向链表
def dfs(root):
    if not root: return
    dfs(root.left)  # 左
    print(root.val) # 根  (对数据的访问处理)
    dfs(root.right) # 右

方法一:递归。dfs中的中序遍历

使用中序遍历访问树的各节点 cur ;并在访问每个节点时构建 cur 和前驱节点 pre 的引用指向;中序遍历完成后,最后构建头节点和尾节点的引用指向即可

class Solution:
    def treeToDoublyList(self, root: 'Node') -> 'Node':   #类的方法
        def dfs(cur):                                      #在方法成员里面定义的函数
            if not cur: return
            dfs(cur.left)   #递归左子树
            if self.pre:   
                cur.left = self.pre    #当前指针的左指向pre
                self.pre.right = cur    #pre的右指向当前
            else:
                self.head = cur         #一开始pre还是None,此时头结点指向cur
            self.pre = cur              #cur变为pre,再处理下一个
            dfs(cur.right)

        if not root: return
        self.pre = None                                     #类的数据成员
        dfs(root)
        self.head.left = self.pre      #处理头结点和尾结点的指针
        self.pre.right = self.head

        return self.head
54 二叉搜索树的第k大节点

方法一:递归。中序遍历的倒序

递归右子树,根(访问处理),递归左子树

#中序遍历的倒序
def dfs(root):
    if not root: return
    dfs(root.right)  # 右
    print(root.val) # 根  (对数据的访问处理)
    dfs(root.left) # 左
#答案
class Solution:
    def kthLargest(self, root: TreeNode, k: int) -> int:
        def dfs(root):
            if not root:return
            dfs(root.right)
            if self.k == 0: return #这里是为了提前返回。若 k = 0k=0 ,代表已找到目标节点,无需继续遍历,因此直接返回
            self.k -= 1
            if self.k == 0: self.res = root.val
            dfs(root.left)

        self.k = k
        dfs(root)
        return self.res
        #后台判题的时候把参数给kthlargest

#错解:
class Solution:
    def kthLargest(self, root: TreeNode, k: int) -> int:
        def dfs(root, k):
            if not root: return 
            dfs(root.right, k)
            k -= 1
            if k == 0:
                self.res = root.val
                return
            dfs(root.left, k)

        if not root: return
        dfs(root, k)
        return self.res
#参数k改为self.k,正确
class Solution:
    def kthLargest(self, root: TreeNode, k: int) -> int:
        def dfs(root,):
            if not root: return 
            dfs(root.right)
            self.k -= 1
            if self.k == 0:
                self.res = root.val
                return
            dfs(root.left)

        if not root: return
        self.k = k
        dfs(root)
        return self.res

Day16 排序(简单)

45把数组排成最小的数

方法一:自定义排序

快速排序

class Solution:
    def minNumber(self, nums: List[int]) -> str:
        def quick_sort(nums, l, r):
            if l >=r: return
            i, j = l, r
            while i < j:
                while i < j and str(nums[j]) + str(nums[l]) >= str(nums[l]) + str(nums[j]): j -= 1
                while i < j and str(nums[i]) + str(nums[l]) <= str(nums[l]) + str(nums[i]): i += 1
                nums[i], nums[j] = nums[j], nums[i]
            nums[l], nums[i] = nums[i], nums[l]
            quick_sort(nums, l, i-1)
            quick_sort(nums, i+1, r)
        #错误写法:
        # nums_sort = quick_sort(nums, 0, len(nums)-1) 注意quick_sort没有返回值,而是直接改变nums的顺序
        # res = [str(i) for i in nums_sort]
        quick_sort(nums, 0, len(nums)-1)
        res = [str(i) for i in nums]
        return ''.join(res)
#答案写法:
class Solution:
    def minNumber(self, nums: List[int]) -> str:
        def quick_sort(l , r):
            if l >= r: return
            i, j = l, r
            while i < j:
                while strs[j] + strs[l] >= strs[l] + strs[j] and i < j: j -= 1
                while strs[i] + strs[l] <= strs[l] + strs[i] and i < j: i += 1
                strs[i], strs[j] = strs[j], strs[i]
            strs[i], strs[l] = strs[l], strs[i]
            quick_sort(l, i - 1)
            quick_sort(i + 1, r)
        
        strs = [str(num) for num in nums]
        quick_sort(0, len(strs) - 1)
        return ''.join(strs)
61 扑克牌中的顺子

根据题意,此 55 张牌是顺子的 充分条件 如下:

1.除大小王外,所有牌 无重复 ;
2.设此 55 张牌中最大的牌为max ,最小的牌为min (大小王除外),则需满足:
max - min < 5

方法一:排序+查看相邻的是否重复

class Solution:
    def isStraight(self, nums: List[int]) -> bool:
        nums.sort()
        i = 0
        n0 = 0
        while i < len(nums):
            if nums[i] == 0: n0 += 1
            else: break
            i += 1
        dic = set()
        j = i
        while j < len(nums):
            if nums[j] in dic: return False
            dic.add(nums[j])
            j += 1 
        return True if nums[len(nums)-1] - nums[i] == 4 else False
#答案改进:
class Solution:
    def isStraight(self, nums: List[int]) -> bool:
        joker = 0
        nums.sort() # 数组排序
        for i in range(4):
            if nums[i] == 0: joker += 1 # 统计大小王数量
            elif nums[i] == nums[i + 1]: return False # 若有重复,提前返回 false
        return nums[4] - nums[joker] < 5 # 最大牌 - 最小牌 < 5 则可构成顺子

方法二:集合

#方法二:集合+遍历
class Solution:
    def isStraight(self, nums: List[int]) -> bool:
        dic = set()
        ma, mi = 0, 14
        for num in nums:
            if num in dic and num != 0: return False
            dic.add(num)
            if num != 0:
                ma = max(ma, num)
                mi = min(mi, num)
        return ma - mi < 5
#答案写法:
class Solution:
    def isStraight(self, nums: List[int]) -> bool:
        repeat = set()
        ma, mi = 0, 14
        for num in nums:
            if num == 0: continue # 跳过大小王
            ma = max(ma, num) # 最大牌
            mi = min(mi, num) # 最小牌
            if num in repeat: return False # 若有重复,提前返回 false
            repeat.add(num) # 添加牌至 Set
        return ma - mi < 5 # 最大牌 - 最小牌 < 5 则可构成顺子

Day17 排序(中等)

@快排
40 最小的k个数

方法一:快速排序。

选第一个数为基准,数字交换到左右两个子数组,递归进行

class Solution:
    def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
        def quick_sort(arr, l, r):
            if l >= r: return #记得终止条件
            i, j = l, r
            while i < j:
                #先从后面j开始检查,因为此时i指向小于pivot,跳出时是因为j来到i的位置相等了,此时arr[l]换arr[i]正确
                #如果i先右移动,指向j的位置而跳出,此时i指向是大于pivot的数
                #例如,设pivot = arr[l] = 5
                #最后几步:
                #[9, 4],j指向4,i指向9,交换,得
                #[4, 9],i指向4,j指向9
                #[i, j]
                #此时j应该先左移到达跳出的条件,后面arr[l]和arr[i]交换才是正确
                while i < j and arr[j] >= arr[l]: j -= 1 
                while i < j and arr[i] <= arr[l]: i += 1
                arr[i], arr[j] = arr[j], arr[i]
            arr[l], arr[i] = arr[i], arr[l] 
            quick_sort(arr, l, i-1)
            quick_sort(arr, i+1, r)

        quick_sort(arr, 0, len(arr)-1)
        return arr[:k]
大小堆
41 数据流中的中位数

方法一:最大最小堆

class MedianFinder:

    def __init__(self):
        """
        initialize your data structure here.
        """
        self.A = []
        self.B = []


    def addNum(self, num: int) -> None:
        if len(self.A) != len(self.B):#A为最小堆,保存数值大的部分,且为较长的堆
            # heappush(self.A, num)
            # heappush(self.B, -heappop(self.A))
            heappush(self.B, -heappushpop(self.A,num))
        else:
            # heappush(self.B, -num)  #Python 中 heapq 模块是小顶堆。实现 大顶堆 方法: 小顶堆的插入和弹出操作均将元素 取反 即可
            # heappush(self.A, -heappop(self.B))
            heappush(self.A, -heappushpop(self.B, -num))

    def findMedian(self) -> float:
        return self.A[0] if len(self.A) != len(self.B) else (self.A[0] - self.B[0]) / 2 #这里-self.B[0]有负号才是最大堆

Day18 搜索与回溯算法(中等)

55-I 二叉树的深度

方法一:递归,后续遍历

关键点:此树的深度和其左(右)子树的深度之间的关系。显然,此树的深度 等于 左子树的深度右子树的深度 中的 最大值 +1

class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root: return 0
        return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right))

方法二:层序遍历

要统计深度,难免要遍历所有节点

#写法一:
class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root: return 0
        res, queue = 0, [root]

        while queue:
            res += 1
            for _ in range(len(queue)):
                node = queue.pop(0)
                if node.left: queue.append(node.left)
                if node.right: queue.append(node.right)
        return res
#答案写法:
class Solution:
    def maxDepth(self, root: TreeNode) -> int:
        if not root: return 0
        queue, res = [root], 0
        while queue:
            tmp = []  #保存下一层的节点
            for node in queue:  #在循环中将下一层的节点都压入tmp
                if node.left: tmp.append(node.left)
                if node.right: tmp.append(node.right)
            queue = tmp
            res += 1
        return res
55-II 平衡二叉树

判断一棵树是不是平衡二叉树,即左右子树的深度相差是否超过1

方法一:递归,后续遍历 + 剪枝

class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        def recur(root):
            if not root: return 0
            left = recur(root.left)
            if left == -1: return -1
            right = recur(root.right)
            if right == -1: return -1
            return 1 + max(left, right) if abs(left -right) <= 1 else -1
        
        return recur(root) != -1

方法二:先序遍历 + 判断深度

复杂度高一些

isBalanced(root) 函数: 判断树 root 是否平衡

特例处理: 若树根节点 root 为空,则直接返回 truetrue ;
返回值: 所有子树都需要满足平衡树性质,因此以下三者使用与逻辑 &&&& 连接;
1、abs(self.depth(root.left) - self.depth(root.right)) <= 1 :判断 当前子树 是否是平衡树;
2、self.isBalanced(root.left) : 先序遍历递归,判断 当前子树的左子树 是否是平衡树;
3、self.isBalanced(root.right) : 先序遍历递归,判断 当前子树的右子树 是否是平衡树

class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        def depth(root):
            if not root: return 0
            return 1 + max(depth(root.left), depth(root.right))
        
        def dfs(root):
            if not root: return True
            if abs(depth(root.left) - depth(root.right)) > 1: return False
            return dfs(root.left) and dfs(root.right)
        
        return dfs(root)

#答案写法:
class Solution:
    def isBalanced(self, root: TreeNode) -> bool:
        if not root: return True
        return abs(self.depth(root.left) - self.depth(root.right)) <= 1 and \
            self.isBalanced(root.left) and self.isBalanced(root.right)

    def depth(self, root):
        if not root: return 0
        return max(self.depth(root.left), self.depth(root.right)) + 1

Day19 搜索与回溯算法(中等)

64 求1+2+…+n

不能用for,while, if, case等关键词

class Solution:
    def sumNums(self, n: int) -> int:
        if n == 1:
            return 1
        else:
            return n + self.sumNums(n-1)

#不能用if:
class Solution:
    def sumNums(self, n: int) -> int: 
        def recur(n):
            n > 1 and recur(n-1)    #如果n>1为False就不执行后面,直接返回了
            self.res += n           #如果用res += n,在函数recur里面没有定义局部变量res就使用是不行的
            return self.res

        self.res = 0   #需要定义成员数据self.res
        return recur(n)
#答案写法:
class Solution:
    def __init__(self):
        self.res = 0
    def sumNums(self, n: int) -> int:
        n > 1 and self.sumNums(n - 1)
        self.res += n
        return self.res
68-I 二叉搜索树的最近公共节点

关键是观察二叉搜索特点和题意,代码不难写

从根节点开始找,如果是最近公共节点,该节点的值必位于pq之间

例如0和5

6比两者都大,是公共节点但不是最近的

4位于两者之间,但不是找到的第一个位于两者之间的,不是公共节点

方法一:循环迭代

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        while root:
            if root.val < p.val and root.val < q.val:
                root = root.right
            elif root.val > p.val and root.val > q.val:
                root = root.left
            else:
                break
        return root

方法二:递归

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        if root.val < p.val and root.val < q.val:
            return self.lowestCommonAncestor(root.right, p, q)
        elif root.val > p.val and root.val > q.val:
            return self.lowestCommonAncestor(root.left, p, q)  #满足这个条件分支,最终是在这里返回的,不会执行到下面的代码(内层会执行)
        else:
            return root
*68-II 二叉树的最近公共节点

方法一:递归

关键是找出在各种什么条件下要返回

class Solution:
    def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
        if not root: return #如果树为空,直接返回null
        if root == p or root == q: return root #如果 p和q中有等于 root的,那么它们的最近公共祖先即为root(一个节点也可以是它自己的祖先)
        left = self.lowestCommonAncestor(root.left, p, q)  #递归遍历左子树,只要在左子树中找到了p或q,则先找到谁就返回谁
        right = self.lowestCommonAncestor(root.right, p, q)
        # if not left and not right: return
        if not left: return right  #如果在左子树中 p和 q都找不到,则 p和 q一定都在右子树中,右子树中先遍历到的那个就是最近公共祖先(一个节点也可以是它自己的祖先)
        if not right: return left  # 否则,如果 left不为空,在左子树中有找到节点(p或q),这时候要再判断一下右子树中的情况,如果在右子树中,p和q都找不到,则 p和q一定都在左子树中,左子树中先遍历到的那个就是最近公共祖先(一个节点也可以是它自己的祖先)
        return root #否则,当 left和 right均不为空时,说明 p、q节点分别在 root异侧, 最近公共祖先即为 root

Day20 分治算法(中等)

7 重建二叉树

方法一:递归分治

left和right分别是中序遍历的左右边界,分治,分成左右子树后,对子树仍然采用同样的方法处理,left,right作为左右子树中序遍历的边界

分治的思想,递归地创建节点,node、node.left、node.right

看题解的图比较清楚

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
        #第一个参数root在前序遍历中考虑;left、right是中序遍历中的边界,都是指序号
        def recur(root,left,right):
            if left > right: return  #在递归过程中,left、right是要改变的
            Node = TreeNode(preorder[root])
            i = dic [preorder[root]] #得到中序中的序号
            Node.left = recur(root+1,left,i-1)#第一个参数是作为preoder的索引;
            #传入的left也是左子树的left;左子树的right是中序的root的左边,因为访问完左子树的所有元素才会访问root
            
            Node.right = recur(root+i-left+1,i+1,right)
            #右子树的根等于root加上左子树的长度(因为先序中是先遍历根,然后到左子树,再到右子树)
            #而左子树的长度在在中序遍历中就是left到root之间的长度:i-left+1
            #这里的i-1、i+1使得递归到一定的次数就终止、并回溯
            return Node                                                                                                                   
        dic = {}
        preorder = preorder
        for i in range(len(inorder)):
            dic[inorder[i]] = i   #将取值和对应的序号保存到字典中
        return recur(0,0,len(inorder)-1)
16数值的整数次方

方法一:快速幂

分治思想,结果每次与结果本身相乘,而不是乘以原来的x

#快速幂,x^n = (x^2)^n//2,每次把幂降为一般
class Solution:
    def myPow(self, x: float, n: int) -> float:
        if x == 0: return 0
        res = 1
        if n < 0: x, n = 1/x, -n
        while n:
            if n & 1: res *= x
            x *= x  # x = x^2 这里x每次是变为x的平方;不同于循环相乘res *= x, x不变
            n >>= 1  # n//2  注意别写成n>>1
        return res
33二叉搜索树的后续遍历序列

判断一个序列是不是某二叉搜索树的后续遍历结果、

方法一:分治。

找到比根节点大的第一个元素,将数组分为左右子数组,递归分治操作

性质1:左子树<根<右子树

性质2:后续遍历的结果是[左子树|右子树|根],根是知道的,就是最后一个元素

class Solution:
    def verifyPostorder(self, postorder: List[int]) -> bool:
        def recur(i, j):
            if i >= j: return True
            p = i #设置指针用于遍历
            while postorder[p] < postorder[j]: p += 1
            m = p #找到第一个比根节点大的元素,则可以将序列分为左右子树,[i, m-1], [m, j]
            while postorder[p] > postorder[j]: p += 1 #判断后面是否满足都大于根节点,如果是则可以遍历到p == j
            return p == j and recur(i, m-1) and recur(m, j-1)#分为左右子树后,递归分治!
        return recur(0, len(postorder)-1)

Day21 位运算

15 二进制中1的个数
#错解。注意输入还是n=11,只是位运算时会看成1011
#所以这里输入控制台输入1011,返回错误结果2,因为len(str())==2
class Solution:
    def hammingWeight(self, n: int) -> int:
        res = 0
        for _ in range(len(str(n))):
            if n & 1: res += 1
            n >>= 1
        return res

class Solution:
    def hammingWeight(self, n: int) -> int:
        res = 0
        while n:
            res += n & 1
            n >>= 1
        return res
65 不用加减乘除做加法
# class Solution:
#     def add(self, a: int, b: int) -> int:
#         x = 0xffffffff
#         a, b = a & x, b & x  #python的整数范围是无穷大,统一为32位
#         while b:  #b是进位
#             a, b = (a ^ b), (a & b) << 1 & x
#         return a if a <= 0x7fffffff else ~(a ^ x)

#等价于
class Solution:
    def add(self, a: int, b: int) -> int:
        x = 0xffffffff
        a, b = a & x, b & x  #python的整数范围是无穷大,统一为32位
        while b:  #b是进位
            s = a ^ b #非进位和
            c =  (a & b) << 1 & x
            a = s
            b = c
        return a if a <= 0x7fffffff else ~(a ^ x)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Offer》 1. 赋值运算函数 2. 单例设计模式 3. 二维数组中查找目标值 4. 替换字符串中的空格 5. 从尾到头打印链表 6. 由前序和中序遍历重建二叉树 7. 用两个栈实现队列 8. 求旋转数组的最小数字 9. 斐波那契数列的第n项(青蛙跳台阶) 10. 二进制中1的个数 11. 数值的整数次方 12. 打印1到最大的n位数 13. O(1)时间删除链表节点 14. 使数组中的奇数位于偶数前面 15. 找链表中倒数第K个节点 16. 输出反转后的链表 17. 合并两个有序链表 18. 判断二叉树A中是否包含子树B 19. 二叉树的镜像 20. 顺时针打印矩阵 21. 包含min函数的栈 22. 判断一个栈是否是另一个栈的弹出序列 23. 层序遍历二叉树 24. 后序遍历二叉搜索树 25. 二叉树中和为某值的路径 26. 复杂链表的复制 27. 二叉搜索树转换为双向链表 28. 打印字符串中所有字符的排列 29. 数组中出现次数超过一半的数字 30. 找出最小的K个数 31. 连续子数组的最大和 32. 从1到整数n中1出现的次数 33. 把数组中的数排成一个最小的数 34. 求第N个丑数 35. 第一个出现一次的字符 36. 数组中逆序对的个数 37. 两个链表的第一个公共节点 38. 数字在排序数组中出现的次数 39. 二叉树的深度 40. 数组中只出现一次的两个数,而其他数都出现两次 41. 和为s的连续整数序列 42. 翻转字符串 43. n个骰子的点数及出现的概率 44. 扑克牌的顺子 45. 圆圈中最后剩下的数 46. 1+2+3+...+n的和 47. 不用加减乘除做加法 48. 不能被继承的类 49. 字符串转换为整数 50. 树中两个节点的最低公共祖先 51. 找出重复的数 52. 构建乘积数组 53. 正则表达式匹配 54. 表示数值的字符串 55. 字符流中第一个不重复的字符 56. 链表中环的入口节点 57. 删除链表中重复的节点 58. 二叉树的下一个节点 59. 对称的二叉树 60. 按之字形顺序打印二叉树 61. 把二叉树打印成多行 62. 序列化二叉树 63. 二叉搜索树的第K个节点 64. 数据流中的中位数 65. 滑动窗口的最大值 66. 矩阵中的路径 67. 机器人的运动范围

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值