我是靠谱客的博主 舒服酸奶,最近开发中收集的这篇文章主要介绍剑指offer分类代码总结,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

      • Day1 栈与队列(简单)
        • 09 两个栈实现队列
        • 30 包含min函数的栈
      • Day2 链表(简单)
        • 06 从尾到头打印链表
        • 24 反转链表
        • 35 复杂链表的复制
      • Day3 字符串(简单)
        • 05 替换空格
        • 58-II 旋转字符串
      • Day4 查找算法(简单)
        • 03 数组中重复的数字
        • @二分查找
        • 53-I 在排序数组中查找数字 I
        • 53-II 0~n-1中缺失的数字
      • Day5 查找算法(中等)
        • 04 二维数组中的查找
        • *11 旋转数组中的最小数字
        • 50 第一个只出现一次的字符
      • Day6 搜索与回溯算法(简单)
        • @层序遍历
        • 32-I 从上到下打印二叉树I
        • 32-II 从上到下打印二叉树II
        • 32-III 从上到下打印二叉树III
      • Day7 搜索与回溯算法
        • 26 树的子结构
        • 27 二叉树的镜像
        • 28 对称的二叉树
      • Day8 动态规划(简单)
        • 10-I 斐波那契数列
        • 10-I 青蛙跳台阶问题
        • 63 股票的最大利益
      • Day9 动态规划(中等)
        • 42 连续子数组的最大和(23字节真题)
        • 47 礼物的最大价值
      • Day10 动态规划(中等)
        • 46 把数字翻译成字符串
        • 48 最长不含重复字符的字符串
      • Day 11 双指针(简单)
        • 18 删除链表得的节点
        • 22 链表中的倒数第k个节点
      • Day11 双指针(简单)
        • 25 合并两个排序的链表
        • 52 两个链表的第一个公共节点
      • Day13 双指针(简单)
        • 21 调整数组顺序使奇数位于偶数前面
        • 57 和为s的两个数
        • 58-I 翻转单词顺序
      • Day14 搜索与回溯算法(中等)
        • 12 矩阵中的路径*
        • 13 机器人的运动范围
      • Day15 搜索与回溯算法(中等)
        • 34 二叉树中和为某一值的路径
        • @打印中序遍历
        • 36 二叉搜索树与双向链表
        • 54 二叉搜索树的第k大节点
      • Day16 排序(简单)
        • 45把数组排成最小的数
        • 61 扑克牌中的顺子
      • Day17 排序(中等)
        • @快排
        • 40 最小的k个数
        • 大小堆
        • 41 数据流中的中位数
      • Day18 搜索与回溯算法(中等)
        • 55-I 二叉树的深度
        • 55-II 平衡二叉树
      • Day19 搜索与回溯算法(中等)
        • 64 求1+2+...+n
        • 68-I 二叉搜索树的最近公共节点
        • *68-II 二叉树的最近公共节点
      • Day20 分治算法(中等)
        • 7 重建二叉树
        • 16数值的整数次方
        • 33二叉搜索树的后续遍历序列
      • Day21 位运算
        • 15 二进制中1的个数
        • 65 不用加减乘除做加法

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)

最后

以上就是舒服酸奶为你收集整理的剑指offer分类代码总结的全部内容,希望文章能够帮你解决剑指offer分类代码总结所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(42)

相关文章

评论列表共有 0 条评论

立即
投稿
返回
顶部