3月

 

216. 组合总和 III

找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。

说明:

所有数字都是正整数。
解集不能包含重复的组合。 
示例 1:

输入: k = 3, n = 7
输出: [[1,2,4]]
示例 2:

输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
class Solution:
    def combinationSum3(self, k: int, n: int) -> List[List[int]]:
        res=[]

        def dfs(count,i,tmp,target):
            if count==k:
                if target==0:
                    res.append(tmp)
                return

            for j in range(i,10):
                if j>target:
                    break
                dfs(count+1,j+1,tmp+[j],target-j)    #此处应该j+1 ,如果选用J,会导致结果由重复数字
           
        dfs(0,1,[],n)
        return res

面试题62. 圆圈中最后剩下的数字

0,1,,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。

例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。

 

示例 1:

输入: n = 5, m = 3
输出: 3
示例 2:

输入: n = 10, m = 17
输出: 2

class Solution:
    def lastRemaining(self, n: int, m: int) -> int:
        res=[i for i in range(n)]
        lp=0
        while n>1:
            lp=(lp+m-1)%n
            res.pop(lp)
            n-=1
        return res[0]

54. 螺旋矩阵

给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。

示例 1:

输入:
[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
输出: [1,2,3,6,9,8,7,4,5]
示例 2:

输入:
[
  [1, 2, 3, 4],
  [5, 6, 7, 8],
  [9,10,11,12]
]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]
class Solution:
    def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
        if not matrix:
            return []
        res=[]
        x,y,count,=0,0,0
        rows,cols=len(matrix),len(matrix[0])
        label=set()
        dx,dy=[0,1,0,-1],[1,0,-1,0]

        for i in range(rows*cols):
            
              #移动总次数
            res.append(matrix[x][y])
            label.add((x,y))
            next_x,next_y=x+dx[count],y+dy[count]
            if 0<=next_x<rows and  0<=next_y<cols and (next_x,next_y) not in label:
                x,y=next_x,next_y
            else:
                count=(count+1)%4
                x,y=x+dx[count],y+dy[count]
        return res

904. 水果成篮

在一排树中,第 i 棵树产生 tree[i] 型的水果。
你可以从你选择的任何树开始,然后重复执行以下步骤:

把这棵树上的水果放进你的篮子里。如果你做不到,就停下来。
移动到当前树右侧的下一棵树。如果右边没有树,就停下来。
请注意,在选择一颗树后,你没有任何选择:你必须执行步骤 1,然后执行步骤 2,然后返回步骤 1,然后执行步骤 2,依此类推,直至停止。

你有两个篮子,每个篮子可以携带任何数量的水果,但你希望每个篮子只携带一种类型的水果。
用这个程序你能收集的水果总量是多少?

 

示例 1:

输入:[1,2,1]
输出:3
解释:我们可以收集 [1,2,1]。
示例 2:

输入:[0,1,2,2]
输出:3
解释:我们可以收集 [1,2,2].
如果我们从第一棵树开始,我们将只能收集到 [0, 1]。
示例 3:

输入:[1,2,3,2,2]
输出:4
解释:我们可以收集 [2,3,2,2].
如果我们从第一棵树开始,我们将只能收集到 [1, 2]。
示例 4:

输入:[3,3,3,1,2,1,1,2,3,3,4]
输出:5
解释:我们可以收集 [1,2,1,1,2].
如果我们从第一棵树或第八棵树开始,我们将只能收集到 4 个水果。
class Solution:
    def totalFruit(self, tree: List[int]) -> int:
        label=0
        count=1
        dic={tree[0]}
        res=0

        for i in range(1,len(tree)):
            if tree[i] in dic:
                count+=1
            elif len(dic)<2:
                dic.add(tree[i])
                count+=1
            else:
                res=max(count,res)
                count=i-label+1   #集合加入新元素,因此count+1
                dic={tree[i-1],tree[i]}
            
            if tree[i]!=tree[i-1]:
                label=i
        return max(count,res)

506. 相对名次

给出 N 名运动员的成绩,找出他们的相对名次并授予前三名对应的奖牌。前三名运动员将会被分别授予 “金牌”,“银牌” 和“ 铜牌”("Gold Medal", "Silver Medal", "Bronze Medal")。

(注:分数越高的选手,排名越靠前。)

示例 1:

输入: [5, 4, 3, 2, 1]
输出: ["Gold Medal", "Silver Medal", "Bronze Medal", "4", "5"]
解释: 前三名运动员的成绩为前三高的,因此将会分别被授予 “金牌”,“银牌”和“铜牌” ("Gold Medal", "Silver Medal" and "Bronze Medal").
余下的两名运动员,我们只需要通过他们的成绩计算将其相对名次即可。
class Solution:
    def findRelativeRanks(self, nums: List[int]) -> List[str]:
        rank_map = {1:"Gold Medal", 2:'Silver Medal', 3:'Bronze Medal'}
        rank_dic = {score: rank+1 for rank,score in enumerate(sorted(nums, reverse=True))}
        res=[]
        for index in nums:
            if rank_dic[index] in rank_map:
                res.append(rank_map[rank_dic[index]])
            else:
                res.append(str(rank_dic[index]))
        return res

1358. 包含所有三种字符的子字符串数目

给你一个字符串 s ,它只包含三种字符 a, b 和 c 。

请你返回 a,b 和 c 都 至少 出现过一次的子字符串数目。

 

示例 1:

输入:s = "abcabc"
输出:10
解释:包含 a,b 和 c 各至少一次的子字符串为 "abc", "abca", "abcab", "abcabc", "bca", "bcab", "bcabc", "cab", "cabc" 和 "abc" (相同字符串算多次)。
示例 2:

输入:s = "aaacb"
输出:3
解释:包含 a,b 和 c 各至少一次的子字符串为 "aaacb", "aacb" 和 "acb" 。
示例 3:

输入:s = "abc"
输出:1
class Solution:
    def numberOfSubstrings(self, s: str) -> int:
         #利用滑窗和规律
        lp,rp=0,2
        count=0
        n=len(s)
        if n<3:
            return 0
        while lp<n-2:
            tmp=s[lp:rp+1]
            if 'a' in tmp and 'b' in tmp and 'c' in tmp:
                count+=n-rp   #末尾统计带‘abc'的
                lp+=1
            else:
                rp+=1
                if rp==n:
                    break
        return count

1008. 先序遍历构造二叉树

返回与给定先序遍历 preorder 相匹配的二叉搜索树(binary search tree)的根结点。

(回想一下,二叉搜索树是二叉树的一种,其每个节点都满足以下规则,对于 node.left 的任何后代,值总 < node.val,而 node.right 的任何后代,值总 > node.val。此外,先序遍历首先显示节点的值,然后遍历 node.left,接着遍历 node.right。)

 

示例:

输入:[8,5,1,7,10,12]
输出:[8,5,10,1,7,null,12]

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def bstFromPreorder(self, preorder: List[int]) -> TreeNode:
        if len(preorder)==0:
            return None
        root=TreeNode(preorder[0])
        # for i in range(len(preorder)):
        #     if preorder[i]>root.val:
        #         lp=preorder[1:i]
        #         rp=preorder[i:]
        lp=[index for index in preorder if index>root.val]
        rp=[index for index in preorder if index<root.val]
        root.left=self.bstFromPreorder(rp)
        root.right=self.bstFromPreorder(lp)
        return root   

697. 数组的度

给定一个非空且只包含非负数的整数数组 nums, 数组的度的定义是指数组里任一元素出现频数的最大值。

你的任务是找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。

示例 1:

输入: [1, 2, 2, 3, 1]
输出: 2
解释: 
输入数组的度是2,因为元素1和2的出现频数最大,均为2.
连续子数组里面拥有相同度的有如下所示:
[1, 2, 2, 3, 1], [1, 2, 2, 3], [2, 2, 3, 1], [1, 2, 2], [2, 2, 3], [2, 2]
最短连续子数组[2, 2]的长度为2,所以返回2.
示例 2:

输入: [1,2,2,3,1,4,2]
输出: 6
from collections import Counter
class Solution:
    def findShortestSubArray(self, nums: List[int]) -> int:
        counter=Counter(nums)
        index=max(counter.values())
        if index==1:
            return 1
        lis=[i for i,j in counter.items() if j==index]
        res=float('inf')
        for key in lis:
            lp,rp=0,len(nums)-1
            while key!=nums[lp]:
                lp+=1
            while key!=nums[rp]:
                rp-=1
            res=min(res,rp-lp+1)
        return res

1025. 除数博弈

爱丽丝和鲍勃一起玩游戏,他们轮流行动。爱丽丝先手开局。

最初,黑板上有一个数字 N 。在每个玩家的回合,玩家需要执行以下操作:

选出任一 x,满足 0 < x < N 且 N % x == 0 。
用 N - x 替换黑板上的数字 N 。
如果玩家无法执行这些操作,就会输掉游戏。

只有在爱丽丝在游戏中取得胜利时才返回 True,否则返回 false。假设两个玩家都以最佳状态参与游戏。

 

示例 1:

输入:2
输出:true
解释:爱丽丝选择 1,鲍勃无法进行操作。
示例 2:

输入:3
输出:false
解释:爱丽丝选择 1,鲍勃也选择 1,然后爱丽丝无法进行操作。
如果N是奇数,因为奇数的所有因数都是奇数,因此 N 进行一次 N-x 的操作结果一定是偶数,所以如果 a 拿到了一个奇数,那么轮到 b 的时候,b拿到的肯定是偶数,这个时候 b 只要进行 -1, 还给 a 一个奇数,那么这样子b就会一直拿到偶数,到最后b一定会拿到最小偶数2,a就输了。

所以如果游戏开始时Alice拿到N为奇数,那么她必输,也就是false。如果拿到N为偶数,她只用 -1,让bob 拿到奇数,最后bob必输,结果就是true。

class Solution:
    def divisorGame(self, N: int) -> bool:

 

56. 合并区间

给出一个区间的集合,请合并所有重叠的区间。

示例 1:

输入: [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:

输入: [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。
class Solution:
    def merge(self, intervals: List[List[int]]) -> List[List[int]]:
        if not intervals:
            return []
        intervals=sorted(intervals,key=lambda x:x[0])
        tmp=intervals[0]
        res=[]
        
        for i in range(1,len(intervals)):
            if intervals[i][0]>tmp[1]:
                res.append(tmp)
                tmp=intervals[i]
            else:
                if tmp[1]<=intervals[i][1]:
                    if tmp[0]>intervals[i][0]:
                        tmp=[intervals[i][0],intervals[i][1]]
                    else:
                        tmp=[tmp[0],intervals[i][1]]
        res.append(tmp)
        return res

516. 最长回文子序列

给定一个字符串s,找到其中最长的回文子序列。可以假设s的最大长度为1000。

示例 1:
输入:

"bbbab"
输出:

4
一个可能的最长回文子序列为 "bbbb"。

示例 2:
输入:

"cbbd"
输出:

2
一个可能的最长回文子序列为 "bb"。
class Solution:
    def longestPalindromeSubseq(self, s: str) -> int:
        n=len(s)
        if n==1:
            return 1
        dp=[[0]*n for i 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]

 

面试题56 - II. 数组中数字出现的次数 II

在一个数组 nums 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。

 

示例 1:

输入:nums = [3,4,3,3]
输出:4
示例 2:

输入:nums = [9,1,7,9,7,9,7]
输出:1

 

class Solution:
    def singleNumber(self, nums):
        res = 0
        for i in range(32):
            cnt = 0  # 记录当前 bit 有多少个1
            bit = 1 << i  # 记录当前要操作的 bit
            for num in nums:
                if num & bit != 0:  #按位与,判单当前位1的个数
                    cnt += 1
            if cnt % 3 != 0:
                print(res |bit)
                res |= bit  #当满足当前位1的个数是不是3的整数倍时,说明目标数在当前位为1,即用1不断与当前位或,老获取目标数

        return res - 2 ** 32 if res > 2 ** 31 - 1 else res
Solution().singleNumber([4,4,4,3])

[56-数组中除了两个元素只出现一次,剩下所有元素出现了两次,找到这两个元素] 

我们进行一次全员异或操作,得到的结果就是那两个只出现一次的不同的数字的异或结果。

我们刚才讲了异或的规律中有一个任何数和本身异或则为0, 因此我们的思路是能不能将这两个不同的数字分成两组 A 和 B。分组需要满足两个条件. (1)两个只出现一次的数字分成不同组 (2)相同的数字分成相同组。这样每一组的数据进行异或即可得到那两个数字。

问题的关键点是我们怎么进行分组呢:由于异或的性质是,同一位相同则为 0,不同则为 1. 我们将所有数字异或的结果一定不是 0,也就是说至少有一位是 1. 我们从右向左找到第一个1出现的位置 idx = 1; while idx & res == 0: idx = idx << 1,分组的依据就来了,遍历nums,你取的那一位是 0 分成 1 组,那一位是 1 的分成一组。这样肯定能保证 相同的数字分成相同组, 不同的那两个数字也会被分成不同组。


class Solution:
    def singleNumbers(self, nums: List[int]) -> List[int]:
        res = 0
        for i in nums:
            res = res^i

        idx = 1
        while idx & res == 0:   #找到两个不同数字,最小位上的区别(1与0) 例如 011 与 1001 则在10位上两个数出现第一次区别 
            idx = idx << 1
    
        a,b = 0,0
        for i in nums:
            if i & idx==0:  #利用10位将数组分开,分别得到两个数字
                a = a^i
            else:
                b = b^i
        return([a,b])
Solution().singleNumber([4,3,4,5])

 

树总结:

二叉树的前序遍历
给定一个二叉树,返回它的 前序 遍历。

 示例:

输入: [1,null,2,3]  
   1
    \
     2
    /
   3 

输出: [1,2,3]


# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def preorderTraversal(self, root: TreeNode) -> List[int]:
        res=[]
        def trival(root,res):
            if not root:
                return 
            res.append(root.val)
            trival(root.left,res)
            trival(root.right,res)
            return res
        trival(root,res)
        return res
        
二叉树的层次遍历
定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。

例如:
给定二叉树: [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7
返回其层次遍历结果:

[
  [3],
  [9,20],
  [15,7]
]

class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root:
            return []
        lis=[root]
        res=[[root.val]]
        while lis:
            tmp=[]
            tmp1=[]
            for index in lis:
                if index.left:
                    tmp.append(index.left)
                    tmp1.append(index.left.val)
                if index.right:
                    tmp.append(index.right)
                    tmp1.append(index.right.val)
            lis=tmp
            if tmp1:
                res.append(tmp1)
        return res

 

递归:

“自顶向下” 的解决方案

“自顶向下” 意味着在每个递归层级,我们将首先访问节点来计算一些值,并在递归调用函数时将这些值传递到子节点。 所以 “自顶向下” 的解决方案可以被认为是一种前序遍历。

如,思考这样一个问题:给定一个二叉树,请寻找它的最大深度。

我们知道根节点的深度是1。 对于每个节点,如果我们知道某节点的深度,那我们将知道它子节点的深度。 因此,在调用递归函数的时候,将节点的深度传递为一个参数,那么所有的节点都知道它们自身的深度。 而对于叶节点,我们可以通过更新深度从而获取最终答案


“自底向上” 的解决方案
“自底向上” 是另一种递归方法。 在每个递归层次上,我们首先对所有子节点递归地调用函数,然后根据返回值和根节点本身的值得到答案。 这个过程可以看作是后序遍历的一种。

继续讨论前面关于树的最大深度的问题,但是使用不同的思维方式:对于树的单个节点,以节点自身为根的子树的最大深度x是多少?

如果我们知道一个根节点,以其左子节点为根的最大深度为l和以其右子节点为根的最大深度为r,我们是否可以回答前面的问题? 当然可以,我们可以选择它们之间的最大值,再加上1来获得根节点所在的子树的最大深度。 那就是 x = max(l,r)+ 1
对称二叉树
给定一个二叉树,检查它是否是镜像对称的。

例如,二叉树 [1,2,2,3,4,4,3] 是对称的。

    1
   / \
  2   2
 / \ / \
3  4 4  3
但是下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:

    1
   / \
  2   2
   \   \
   3    3

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        if not root:
            return True
        def helper(left,right):
            if not left and not right:
                return True
            if not left or not right:
                return False
            if left.val==right.val:
                return helper(left.left,right.right) and helper(right.left,left.right)
            return False
        return helper(root.left,root.right)

 

迭代法

class Solution:
    def isSymmetric(self, root: TreeNode) -> bool:
        if not root:
            return True
        def helper(left,right):
            stack=[left,right]
            while stack:
                left=stack.pop()
                right=stack.pop()
                if not left and not right:
                    continue
                if (not left or not right) or (left.val!=right.val):
                    return False
                stack+=[left.left,right.right,left.right,right.left]
            return True
        return helper(root.left,root.right)
填充每个节点的下一个右侧节点指针
给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

class Solution:
    def connect(self, root: 'Node') -> 'Node':
        if not root:
            return root
        if root.right:
            root.left.next=root.right
            if root.next:
                root.right.next=root.next.left  #A左子树的右子节点  指向  A右子树的左子节点
        self.connect(root.left)
        self.connect(root.right)
        return root
        
填充每个节点的下一个右侧节点指针 II
给定一个二叉树

struct Node {
  int val;
  Node *left;
  Node *right;
  Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。

初始状态下,所有 next 指针都被设置为 NULL。

 

进阶:

你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。

示例:

class Solution:
    def dfs(self,root):
        if not root:
            return None
        while root:     #寻找此时root最右边的一个子树
            if root.left:
                return root.left
            if root.right:
                return root.right
            root=root.next
        return None
            
            
        
        
    def connect(self, root: 'Node') -> 'Node':
        if not root:
            return None
        if root.left:
            if root.right:
                root.left.next=root.right
            else:
                root.left.next=self.dfs(root.next)
        if root.right:
            root.right.next=self.dfs(root.next)
        self.connect(root.right)
        # 注意这里要先递归右子树,因为如果父节点右子树不存在的话,左子树的next需要找父节点next的子树,因此必须先把右边的next关系理顺
        self.connect(root.left)
        return root
                    

路经总和

 路径总和
给定一个二叉树和一个目标和,判断该树中是否存在根节点到叶子节点的路径,这条路径上所有节点值相加等于目标和。

说明: 叶子节点是指没有子节点的节点。

示例: 
给定如下二叉树,以及目标和 sum = 22,

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \      \
        7    2      1
返回 true, 因为存在目标和为 22 的根节点到叶子节点的路径 5->4->11->2。
class Solution:
    def hasPathSum(self, root: TreeNode, sum: int) -> bool:
        if not root:
            return False
        sum-=root.val
        if sum==0 and not root.left and not root.right:
            return True
        else:
            return self.hasPathSum(root.left,sum) or self.hasPathSum(root.right,sum)

 路径总和 II

给定一个二叉树和一个目标和,找到所有从根节点到叶子节点路径总和等于给定目标和的路径。

说明: 叶子节点是指没有子节点的节点。

示例:
给定如下二叉树,以及目标和 sum = 22,

              5
             / \
            4   8
           /   / \
          11  13  4
         /  \    / \
        7    2  5   1
返回:

[
   [5,4,11,2],
   [5,8,4,5]
]

class Solution:
    def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
        self.res = []
        
        def dfs(root,tmp,tol):
            if not root: 
                return 
     #       tmp+=[root.val]
            tol-=root.val
            if not root.left and not root.right and tol== 0:
                tmp += [root.val]
                self.res.append(tmp)
            
            dfs(root.left,tmp+[root.val], tol)
            dfs(root.right,tmp+[root.val], tol )
            
        dfs(root, [], sum)
        return self.res

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值