一天一道LeetCode(61-90)

一天一道LeetCode(61-90)

61.旋转链表

题目

给定一个链表,旋转链表,将链表每个节点向右移动k个位置,其中k是非负数

实例

输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None
class Solution:
    def rotateRight(self, head, k):
        if not head:
            return None
        # 获取链表长度
        p = head
        length = 0
        while p :
            length += 1
            p = p.next
        # 让k对length取余,避免重复循环导致超时
        k = k % length
        if k == 0:
            return head
        pre, post = head, head
        # 让一个指针先走k步
        for i in range(k):
            post = post.next
        # 两个指针一起走
        while post.next:
            pre = pre.next
            post = post.next
        tmp = pre.next
        pre.next = None
        post.next = head
        
        return tmp
62.不同路径

题目

一个机器人位于一个m x n 网格的左上角(起始点在下图中标记为"start"),机器人每次只能向下或者向右移动一步,机器人试图到达网格的右下角(图中标记为"finish"),总共有多少条不同的路径?

在这里插入图片描述

实例

输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
输入: m = 7, n = 3
输出: 28

思路

动态规划

机器人智能向下或者向右移动一步,对于任意的i, j,机器人只能从左侧或者上方移动过来,特别的对于上边界或左边界,机器人只有一种移动方式,就有如下公式:

d p [ i ] [ j ] = { 1 (i = 0, j = 0) d p [ i ] [ j − 1 ] (i = 0, j  ≠  0) d p [ i − 1 ] [ j ] (i  ≠  0, j = 0) d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] (i  ≠  0, j  ≠ 0 ) dp[i][j] = \begin{cases}1& \text{(i = 0, j = 0)}\\dp[i][j - 1]& \text{(i = 0, j $\neq$ 0)}\\dp[i - 1][j]& \text{(i $\neq$ 0, j = 0)}\\dp[i - 1][j] + dp[i][j - 1]& \text{(i $\neq$ 0, j $\neq 0 $)}\end{cases} dp[i][j]=1dp[i][j1]dp[i1][j]dp[i1][j]+dp[i][j1](i = 0, j = 0)(i = 0, j = 0)(i = 0, j = 0)(i = 0, j =0)

在该题中还可以简化为:

d p [ i ] [ j ] = { 1 (i = 0 or j = 0) d p [ i − 1 ] [ j ] + d p [ i ] [ j − 1 ] (i  ≠ 0 , j  ≠ 0 ) dp[i][j] = \begin{cases}1& \text{(i = 0 or j = 0)}\\dp[i - 1][j] + dp[i][j - 1]& \text{(i $\not= 0 $, j $\not= 0$)}\end{cases} dp[i][j]={1dp[i1][j]+dp[i][j1](i = 0 or j = 0)(i =0, j =0)

class Solution:
    def uniquePaths(self, m, n):
        dp[[1]*n for _ in range(m)]
        for i in range(1, m):
            for j in range(1, n):
                dp[i][j] = dp[i][j - 1] + dp[i - 1][j]
        return dp[-1][-1]
63.不同路径 II

题目

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用1和0来表示

实例

输入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
class Solution:
    def uniquePathsWithObstacles(self, obstacleGrid):
        m, n = len(obstacleGrid[0]), len(obstacleGrid)
        dp = [1] + [0]*m
        for i in range(0, n):
            for j in range(0, m):
                dp[j] = 0 if obstacleGrid[i][j] else dp[j]+dp[j-1]
        return dp[-2]
64.最小路径和

题目

给定一个包含非负整数的m x n网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和最小(每次只能向下或者向右移动一步)

实例

输入:
[
  [1,3,1],
  [1,5,1],
  [4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小

思路

动态规划

  • 状态定义:设dp为大小m x n矩阵,其中dp[i][j]的值代表走到(i, j)的最小路径和

  • 转移方程:根据题目,只能向右或者向下走,也就是说,当前单元格(i, j)只能从左方单元格(i - 1, j)或上方单元格(i, j - 1)走到,因此只需要考虑矩阵的左边界和上边界

    走到当前单元格(i, j)的最小路径和 = “从左方单元格(i - 1, j)与从上方单元格(i, j - 1)走来的两个最小路径和中较小的 + 当前单元格值grid[i][j],具体分为以下4中情况:

    • 1.当左边和上边都不是矩阵边界时:即当 i ≠ 0 , j ≠ 0 i \not= 0, j \not= 0 i=0,j=0时,dp[i][j] = min(dp[i - 1][j], dp[i][j - 1] + grid[i][j])
    • 2.当只有左边是矩阵边界时:只能从上面来,即当 i = 0 , j ≠ 0 i = 0, j \not= 0 i=0,j=0时,dp[i][j] = dp[i][j - 1] + grid[i][j]
    • 3.当只有上边是矩阵边界时:只能从左边来,即当 i ≠ 0 , j = 0 i \neq 0, j = 0 i=0,j=0 时,dp[i][j] = dp[i - 1][j] + grid[i][j]
    • 4.当左边和上边都是矩阵边界时:即当 i = 0 , j = 0 i = 0, j = 0 i=0,j=0时,其实就是起点,dp[i][j] = grid[i][i]
  • 初始状态:dp初始化即可,不需要修改初始0值

class Solution:
    def minPathSum(self, grid):
        for i in range(len(grid)):
            for j in range(len(grid[0])):
                if i == j == 0:
                    continue
                elif i == 0:
                    grid[i][j] = grid[i][j - 1] + grid[i][j]
                elif j == 0:
                    grid[i][j] = grid[i - 1][j] + grid[i][j]
                else:
                    grid[i][j] = min(grid[i - 1][j], grid[i][j - 1]) + grid[i][j]
        return grid[-1][-1]
65.有效数字(未解决)

题目

验证给定的字符串是否可以解释为十进制数字

实例

"0" => true
" 0.1 " => true
"abc" => false
"1 a" => false
"2e10" => true
" -90e3   " => true
" 1e" => false
"e3" => false
" 6e-1" => true
" 99e2.5 " => false
"53.5e93" => true
" --6 " => false
"-+3" => false
"95a54e53" => false

说明

可能存在于有效十进制数字中的字符表:

  • 数字 0-9
  • 指数 - “e”
  • 正/负号 - “+”/"-"
  • 小数点 - “.”
66.加一

题目

给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一

最高位数字存放在数组的首位,数组中每个元素只存储单个数字

可以假设除了整数0之外,这个整数不会以0开头

实例

输入: [1,2,3]
输出: [1,2,4]
解释: 输入数组表示数字 123
输入: [4,3,2,1]
输出: [4,3,2,2]
解释: 输入数组表示数字 4321
# 投机解法
class Solution:
    def plusOne(self, digits):
        cur = ''
        for ele in digits:
            cur += str(ele)
        cur = int(cur) + 1
        res = [int(i) for i in str(cur)]
        return res
# 正常解法
class Solution:
    def plusOne(self, digits):
        carry = 1
        for i in range(len(digits)-1, -1, -1):
            if digits[i] == 9:
                if carry == 1:
                    digits[i] = 0
                    carry = 1
            else:
                digits[i] += carry
                carry = 0
        if carry == 1:digits = [1] + digits
        return digits
67.二进制求和

题目

给你一个二进制字符串,返回他们的和(用二进制表示)

输入为非空字符串且只包含数字1和0

实例

输入: a = "11", b = "1"
输出: "100"
输入: a = "1010", b = "1011"
输出: "10101"

提示

  • 每个字符串仅由字符 '0''1' 组成。
  • 1 <= a.length, b.length <= 10^4
  • 字符串如果不是 "0" ,就都不含前导零。
class Solution:
    def addBinary(self, a, b):
        if len(a) < len(b):
            a, b = b, a
        n = len(a)
        # 补齐b不足的位为0
        b = '0' * (n - len(b)) + b
        result = ''
        summ = 0 # 进位值
        for i in range(n):
            a_1 = int(a[-i-1])
            b_1 = int(b[-i-1])
            # 当前数位相加余2,连接更小位数的值
            result = str((a_1 + b_1 + summ) % 2) + result
            # 当前位数之和整除2,得到下一位运算的进位值
            summ = (a_1 + b_1 + summ) // 2
        # 判断最高位是否需要进位
        if summ == 1:
            result = '1' + result
        return result
# 内置方法
class Solution:
    def addBinary(self, a, b):
        return bin(int(a, 2) + int(b, 2))[2:]
68.文本左右对齐

题目

给定一个单词数组和一个长度maxWidth,重新排版单词,使其成为每行恰好有maxWidth个字符,且左右两段对齐的文本

应该使用“贪心算法”来放置给定的单词,也就是说,尽可能多的往每行中放置单词,必要时可以使用空格填充,使得每行恰好有maxWidth个字符

要求尽可能均匀分配单词间的空格数量,如果某一行单词间的空格不能均匀分配,则左侧放置的空格数要多于右侧的空格数

文本的最后一行应为左对齐,且单词之间不插入额外的空格

说明

  • 单词是指由非空格字符组成的字符序列。
  • 每个单词的长度大于 0,小于等于 maxWidth
  • 输入单词数组 words 至少包含一个单词。

实例

输入:
words = ["This", "is", "an", "example", "of", "text", "justification."]
maxWidth = 16
输出:
[
   "This    is    an",
   "example  of text",
   "justification.  "
]
输入:
words = ["What","must","be","acknowledgment","shall","be"]
maxWidth = 16
输出:
[
  "What   must   be",
  "acknowledgment  ",
  "shall be        "
]
解释: 注意最后一行的格式应为 "shall be    " 而不是 "shall     be",
     因为最后一行应为左对齐,而不是左右两端对齐。       
     第二行同样为左对齐,这是因为这行只包含一个单词
输入:
words = ["Science","is","what","we","understand","well","enough","to","explain",
         "to","a","computer.","Art","is","everything","else","we","do"]
maxWidth = 20
输出:
[
  "Science  is  what we",
  "understand      well",
  "enough to explain to",
  "a  computer.  Art is",
  "everything  else  we",
  "do                  "
]

思路

设定一下几个变量:

ans 最后答案 / cur_c 当前行的字母数 / cur_w 当前行的单词数 / wl 当前行的单词列表

然后一个单词一个单词的过,判断加上这个单词是否会超过最大长度,一行的最低长度是:

cur_c + cur_w - 1

如果大于maxWidth,就把这一行加入ans中,所有单词过完了再把余下的词放入最后一行

如何安排每一行的单词

1.如果这一行只有一个单词,单词左对齐,后面补满空格

2.一行多个单词

​ 空格正好可以平均分配,求出平均每个间隔几个空格,直接调用python的join方法

​ 有多余的空格,题目要求左边空格多于右边,先算平均每个间隔几个空格,然后余下几个,如果平均b个,余下x个,则前x个间隔空b + 1个,后面的都空b个

class Solution:
    def fullJustify(self, words, maxWidth):
        ans = []   # 最后的答案
        cur_c = 0  # 当前行的字母数
        cur_w = 0  # 当前行的单词数
        wl = []    # 当前行的单词列表
        for i, wd in enumerate(words):
            l = len(wd)
            if cur_c + l + cur_w > maxWidth: # 加上这个单词是否会超过最大长度
                if cur_w == 1: # 当前行仅有一个超长的单词,后面全部补空格
                    ans.append(wl[0] + ' ' * (maxWidth-cur_c))
                else:
                    left = maxWidth - cur_c # 这行一共有几个空格
                    if left % (cur_w-1) == 0: # 空格刚好平均分配
                        ans.append((' '*(left//(cur_w-1))).join(wl))
                    else: # 空格不能平均分配
                        x = left % (cur_w-1)  # 多余的空格
                        b = left // (cur_w-1) # 平均每个间隔最少的空格数
                        cans = wl[0]
                        for i in range(x): # 前 x 个间隔空 b + 1 个
                            cans += ' ' * (b+1) + wl[i+1]
                        for i in range(x+1, len(wl)): # 后面的都空 b 个
                            cans += ' ' * b + wl[i]
                        ans.append(cans)
                cur_c = l
                cur_w = 1
                wl = [wd]
            else:
                cur_c += l
                cur_w += 1
                wl.append(wd)

        if cur_w > 0: # 所有单词过完了把余下的词放入最后一行
            cans = ' '.join(wl)
            cans += ' ' * (maxWidth - len(cans))
            ans.append(cans)
        return ans
69.x 的平方根

题目

实现int sqrt(int x)函数,计算并返回x的平方根,其中x 是非负整数

由于返回类型是整数,结果只保留整数的部分,小数部分被舍去

实例

输入: 4
输出: 2
输入: 8
输出: 2
说明: 8 的平方根是 2.82842..., 
     由于返回类型是整数,小数部分将被舍去

思路

牛顿迭代

y = f ( x ) = x 2 − C y = f(x) = x^2 - C y=f(x)=x2C,其中C表示待求出平方根的那个整数,C的平方就是函数的零点

牛顿迭代的本质是借助泰勒级数,从初始值开始快速向零点逼近

任取一个 x 0 x_0 x0作为初始值,在每一步的迭代中,我们找到函数图像上的点 ( x i , f ( x i ) ) (x_i, f(x_i)) (xi,f(xi)),过该点做一条斜率为该点倒数 f ′ ( x i ) f'(x_i) f(xi)的直线,与横轴的交点记为 x i + 1 x_{i+1} xi+1 x i + 1 x_{i+1} xi+1相较于 x i x_i xi而言距离零点更接近,在经过多次迭代后,可以得到一个距离零点非常接近的交点,下图是两次迭代得到 x 1 和 x 2 x_1和x_2 x1x2的过程

在这里插入图片描述

选取 x 0 = C x_0 = C x0=C作为初始值

在每一步迭代中,通过当前的交点 x i x_i xi,找到函数图像上的点 ( x i , x i 2 − C ) (x_i, x_i^2-C) (xi,xi2C),做一条斜率为 f ′ ( x i ) = 2 x i f'(x_i) = 2x_i f(xi)=2xi的直线,直线方程为:

y l = 2 x i ( x − x i ) + x i 2 − C = 2 x i x − ( x i 2 + C ) yl = 2x_i(x - x_i) + x_i^2 - C = 2x_ix - (x_i^2 + C) yl=2xi(xxi)+xi2C=2xix(xi2+C)

与横轴的交点为方程 2 x i x − ( x i 2 + C ) = 0 2x_ix - (x_i^2 +C) = 0 2xix(xi2+C)=0的解,即为更新的迭代结果 x i + 1 x_{i+1} xi+1 x i + 1 = 1 2 ( x i + C x i ) x_{i+1} = \frac{1}{2}(x_i+\frac{C}{x_i}) xi+1=21(xi+xiC)

在进行k次迭代后, x k x_k xk的值与真实的零点 C \sqrt{C} C 足够接近,即可作为答案

class Solution:
    def mySqrt(self, x):
        if x == 0:
            return 0
        C, x0 = float(x), float(x)
        while True:
            xi = 0.5 * (x0 + C / x0)
            if abs(x0 - xi) < 1e-7:
                break
            x0 = xi
        return int(x0)

方法二

二分查找

由于x的平方根的整数部分ans是满足 k 2 < = x k^2 <= x k2<=x的最大k值,可以对k进行二分查找

二分查找的下界为0,上界可以设定为x,在二分查找的每一步中,我们只需要比较中间元素mid的平方与x的大小关系,并通过比较的结果调整上下界的范围

class Solution:
    def mySqrt(self, x):
        l, r, ans = 0, x, -1
        while l <= r:
            mid = (l + r) // 2
            if mid * mid <= x:
                ans = mid
                l = mid + 1
            else:
                r = mid - 1
        return ans
70.爬楼梯

题目

假设你正在爬楼梯,需要n阶才能到达楼顶

每次你可以爬1或2个台阶,有多少种不同的方法可以爬到楼顶?

实例

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。
1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

思路

其实就是斐波那契数列

class Solution:
    def climbStairs(self, n):
        count = 0
        tmp1 = 0
        tmp2 = 1
        ans = 0
        while count < n :
            ans = tmp1 + tmp2
            tmp1 = tmp2
            tmp2 = ans
            count += 1
        return ans
71.简化路径

题目

以Unix风格给出一个文件的绝对路径,你需要简化它,将其转换为规范路径

在Unix风格的文件系统中,一个点.,表示当前目录本身,此外,两个点..,表示将目录切换到上一级(指向父目录),两者都可以是复杂相对路径的组成部分

请注意,返回的规范路径必须始终以斜杠/开头,并且,两个目录名之间必须只有一个斜杠/,最后一个目录名(如果存在),不能以/结尾,此外,规范路径必须是表示绝对路径的最短字符串

实例

输入:"/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠
输入:"/../"
输出:"/"
解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级
输入:"/home//foo/"
输出:"/home/foo"
解释:在规范路径中,多个连续斜杠需要用一个斜杠替换
输入:"/a/./b/../../c/"
输出:"/c"
输入:"/a/../../b/../c//.//"
输出:"/c"
输入:"/a//bc/d//././/.."
输出:"/a/b/c"

思路

把当前目录压入栈中,遇到..,弹出栈顶,最后返回栈中元素

class Solution:
    def simplifyPath(self, path):
        stack = []
        path = path.split('/')
        
        for item in path:
                if item == '..':
                    if stack:stack.pop()
                elif item and item != '.':
                    stack.append(item)
        return '/' + '/'.join(stack)
72.编辑距离

题目

给你两个单词word1和word2,请你计算出将word1转换成word2所用的最少操作数

可以对一个单词进行如下三种操作:

1.插入一个字符

2.删除一个字符

3.替换一个字符

实例

输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')
输入:word1 = "intention", word2 = "execution"
输出:5
解释:
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')

思路

动态规划

dp[i][j]代表word1 到i位置转换成word2到j位置需要最少步数

所以,当word1[i] == word2[j], dp[i][j] = dp[i - 1][j - 1]

word1[i] != word2[j], dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1] + 1),其中dp[i - 1][j - 1]表示替换操作,dp[i - 1][j]表示删除操作,dp[i][j - 1]表示插入操作

补充:

以 word1 为 “horse”,word2 为 “ros”,且 dp[5][3] 为例,即要将 word1的前 5 个字符转换为 word2的前 3 个字符,也就是将 horse 转换为 ros,因此有:

(1) dp[i-1][j-1],即先将 word1 的前 4 个字符 hors 转换为 word2 的前 2 个字符 ro,然后将第五个字符 word1[4](因为下标基数以 0 开始) 由 e 替换为 s(即替换为 word2 的第三个字符,word2[2])

(2) dp[i][j-1],即先将 word1 的前 5 个字符 horse 转换为 word2 的前 2 个字符 ro,然后在末尾补充一个 s,即插入操作

(3) dp[i-1][j],即先将 word1 的前 4 个字符 hors 转换为 word2 的前 3 个字符 ros,然后删除 word1 的第 5 个字符

注意,针对第一行,第一列要单独考虑,引入'',如下图所示:

在这里插入图片描述

第一行,是word1为空变成word2最少步数,就是插入步数

第一列,是word2为空,需要的最少步数,就是删除操作

# 自底向上
class Solution:
    def minDistance(self, word1, word2):
        n1 = len(word1)
        n2 = len(word2)
        dp = [[0] * (n2 + 1) for _ in range(n1 + 1)]
        for j in range(1, n2 + 1):
            dp[0][j] = dp[0][j - 1] + 1
        for i in range(1, n1 + 1):
            dp[i][0] = dp[i - 1][0] + 1
        for i in range(1, n1 + 1):
            for j in range(1, n2 + 1):
                if word1[i - 1] == word2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1]
                else:
                    dp[i][j] = min(dp[i][j - 1], dp[i - 1][j], dp[i - 1][j - 1]) + 1
        return dp[-1][-1]
73.矩阵置零

题目

给定一个m x n 的矩阵,如果一个元素为0,则将其所在行和列的所有元素都设为0,请使用原地算法

实例

输入: 
[
  [1,1,1],
  [1,0,1],
  [1,1,1]
]
输出: 
[
  [1,0,1],
  [0,0,0],
  [1,0,1]
]
输入: 
[
  [0,1,2,0],
  [3,4,5,2],
  [1,3,1,5]
]
输出: 
[
  [0,0,0,0],
  [0,4,5,0],
  [0,3,1,0]
]

思路

1.用 O ( m + n ) O(m + n) O(m+n)额外空间

扫两遍matrix,第一遍用集合记录哪些行,哪些列有0,第二遍置0

class Solution:
    def setZeroes(self, matrix):
        row = len(matrix)
        col = len(matrix[0])
        row_zero = set()
        col_zero = set()
        for i in range(row):
            for i in range(col):
                if matrix[i][j] == 0:
                    row_zero.add(i)
                    col_zero.add(j)
        for i in range(row):
            for j in range(col):
                if i in row_zero or j in col_zero:
                    matrix[i][j] = 0

2.用 O ( 1 ) O(1) O(1)空间

用matrix第一行和第一列记录该行该列是否有0作为标志位,但是对于第一行和第一列要设置一个标志位,为了防止自己这一行(一列)也有0的情况

class Solution:
    def setZeroes(self, matrix):
        row = len(matrix)
        col = len(matrix[0])
        row0_flag = False
        col0_flag = False
        # 找第一行是否有0
        for j in range(col):
            if matrix[0][j] == 0:
                row0_flag = True
                break
        # 第一列是否有0
        for i in range(row):
            if matrix[i][0] == 0:
                col0_flag = True
                break

        # 把第一行或者第一列作为 标志位
        for i in range(1, row):
            for j in range(1, col):
                if matrix[i][j] == 0:
                    matrix[i][0] = matrix[0][j] = 0
        # 置0
        for i in range(1, row):
            for j in range(1, col):
                if matrix[i][0] == 0 or matrix[0][j] == 0:
                    matrix[i][j] = 0

        if row0_flag:
            for j in range(col):
                matrix[0][j] = 0
        if col0_flag:
            for i in range(row):
                matrix[i][0] = 0
74.搜索二维矩阵

题目

编写一个高效的算法来判断m x n 矩阵中,是否存在一个目标值,该矩阵有如下特性:

  • 每行中的整数从左到右按升序排列
  • 每行的第一个整数大于前一行的最后一个整数

实例

输入:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 3
输出: true
输入:
matrix = [
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]
target = 13
输出: false
# 法一(推荐):从左下角开始查找,如果比当前值大,则去上一行找,如果比当前值小,则向后找
class Solution:
    def searchMatrix(self, matrix, target):
        row = len(matrix) - 1
        col = len(matrix[0]) - 1
       	i = row
        j = 0
        while j <= col and i >= 0 :
            if target < matrix[i][j]:
                i -= 1
            elif target > array[i][j]:
                j += 1
            else:
                return True
        return False
# 法二:转换成一维数组,然后使用二分查找
class Solution:
    def searchMatrix(self, matrix, target):
        if not matrix or not matrix[0]:
            return False
        left, right = 0, len(matrix) * len(matrix[0]) - 1
        array = [column for row in matrix for column in row]
        while left <= right:
            mid = ((right - left) >> 1) + left
            if array[mid] == target:
                return True
            elif array[mid] < target:
                left = mid + 1
            else:
                right = mid - 1
        return False
75.颜色分类

题目

给定一个包含红色,白色和蓝色,一共n个元素的数组,原地对他们进行排序,使得相同颜色的元素相邻,比男找红色,白色,蓝色的顺序排序

使用0, 1, 2分别表示红色,白色,蓝色

实例

输入: [2,0,2,1,1,0]
输出: [0,0,1,1,2,2]

思路
三指针

1.定义0的右界bound_0 = 0, 2的左界bound_2 = n - 1,n为数组长度,cur为当前元素

2.当cur <= bound_2时,进入循环

​ 若nums[cur] == 0,此时和0的右界bound_0进行交换,并更新右界和cur,即bound_0 += 1,cur += 1

​ 若nums[cur] == 2,和2的左界bound_2进行交换,并更新左界,向左移动,即bound_2 -= 1

​ 若nums[cur] == 1,则将cur指向下一元素

class Solution:
    def sortColors(self, nums):
        n = len(nums)
        bound_0 = 0
        bound_2 = n - 1
        cur = 0
        while cur <= bound_2:
            if nums[cur] == 0:
                nums[cur], nums[bound_0] = nums[bound_0], nums[cur]
                bound_0 += 1
                cur += 1
            elif nums[cur] == 2:
                nums[cur], nums[bound_2] = nums[bound_2], nums[cur]
                dound_2 -= 1
            else:
                cur += 1

补充

三色旗问题

假设有一条绳子,上面有红,白,蓝三种颜色的棋子,起初绳子上的棋子颜色并没有顺序,希望将之分类,并排序为蓝,白,红的顺序,要如何移动次数才会最少,(只能在绳子上进行移动,并且一次只能调换两色旗子)

方法一:直接交换蓝旗和红旗的位置,剩下的就是白旗位置

方法二:从绳子开头进行,那么遇到蓝色往前移,遇到白色留在中间,遇到红色后移

在这里插入图片描述

在这里插入图片描述

'''
	1.如果w所在的位置为白色,则w+1,表示未处理的部分移至白色群组;
	2.如果w部分为蓝色,则b与w的元素对调,而b与w必须各+1,表示两个群组都多了一个元素
	  当w指向的是蓝色而要和b的指向交换时,如果b指向的不是蓝色,则交换,否则,如果b指向	  的是蓝色,则也没有必要把两个蓝色的旗子交换,这时只需要把b和w都往后移一位
	3.如果w所在的位置是红色,则将w与r交换,但r要减1,表示未处理的部分减1
	  当w指向的是红色而和r交换时,如果此时r指向的是红色,显然没有必要把两个红色旗子交		  换,所以这时应该把r前移,知道r指向的不是红色的时候才和w指向的旗子交换
'''
# 定义三个标识,wFlag和bFlag初始状态为0,表示在开头,rFlag初始为len(color)-1表示在末尾
color = ['R','B','R','W','R','R','W','B','B','W']
wFlag, bFlag, rFlag = 0, 0, len(color) - 1

# 当红旗索引小于白旗索引,表示剩下的旗子都是红色,程序结束
while wFlag <= rFlag:
    if color[wFlag] == 'W':
        wFlag += 1
    elif color[wFlag] == 'B':
        color[bFlag], color[wFlag] = color[wFlag], color[bFlag]
        bFlag += 1
        wFlag += 1
    else:
        while wFlag < rFlag and color[rFlag] == 'R':
            rFlag -= 1
        color[rFlag], clolr[wFlag] = color[wFlag], color[rFlag]
        rFlag -= 1
76.最小覆盖子串

题目

给你一个字符串S,一个字符串T,请在字符串S里面找出:包含T所有字符的最小子串

实例

输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"

说明

如果S中不存在这样的子串,返回''

如果S中存在这样的子串,保证他是唯一答案

思路

滑动窗口

用i, j表示滑动窗口的左边界和右边界,通过改变i, j来扩展和收缩滑动窗口,可以想象成一个窗口在字符串上游走,当这个窗口包含的元素满足条件,即包含字符串T的所有元素,记录下这个滑动窗口的长度j - i + 1,这些长度中最小的值就是要求的结果

  • 步骤1:

    不断增加j,使滑动窗口增大,知道窗口包含了T的所有元素

  • 步骤2:

    不断增加i,使滑动窗口缩小,因为是要求最小字串,所以将不必要的元素排除在外,使长度缩小,直到碰到一个必须包含的元素

  • 步骤3:

    让i增加一个位置,这个时候原本的窗口不满足条件,继续执行步骤1,寻找新的满足条件的窗口,如此反复,知道j超出了字符串S的范围

class Solution:
    def minWindow(self, s, t):
        need = collections.defaultdict(int)
        for c in t:
            need[c] += 1
        needCnt = len(t)
        i = 0
        res = (0, float('inf'))
        for j, c in enumerate(s):
            if need[c] > 0:
                needCnt -= 1
            need[c] -= 1
            # 步骤1,滑动窗口包含了所有T元素
            if needCnt == 0:
                # 步骤2增加i,排除多余元素
                while True:
                    c = s[i]
                    if need[c] == 0:
                        break
                    need[c] += 1
                    i += 1
                if j - i < res[1] - res[0]:
                    res = (i, j)
                # 步骤3,i增加一个位置,寻找新的满足条件滑动窗口
                need[s[i]] += 1
                needCnt += 1
                i += 1
        return '' if res[1] > len(s) else s[res[0] : res[1]+1]
77.组合

题目

给定两个整数n和k,返回1…n中所有可能的k个数的组合

实例

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

在这里插入图片描述

在这里插入图片描述

绿色的部分是不能产生结果的分枝

class Solution:
    def combine(self, n, k):
        if n <= 0 or k <= 0 or k > n :
            return []
        res = []
        self.__dfs(1, k, n, [], res)
        return res
    
    def __dfs(self, start, k, n, pre, res):
        if len(pre) == k:
            res.append(pre[:])
            return 
        
        for i in range(start, n-(k-len(pre))+2):
            pre.append(i)
            self.__dfs(i+1, k, n, pre, res)
            pre.pop()
78.子集

题目

给定一组不含重复元素的整数数组nums,返回该数组所有可能的子集(幂集)

说明

解集不能包含重复的子集

实例

输入: nums = [1,2,3]
输出:
[
  [3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
# 方法1:递归
class Solution:
    def subsets(self, nums):
        res = []
        n = len(nums)
        
        def helper(i, tmp):
            res.append(tmp)
            for j in range(i, n):
                helper(j + 1, tmp + [nums[j]])
        helper(0, [])
        return res
# 方法2:内置函数
# product 笛卡尔积(有放回抽样排列)
# permutations 排列(不放回抽样排列)
# combinations 组合,没有重复(不放回抽样组合)
# combinations_with_replacement 组合,有重复(有放回抽样组合)
class Solution:
    def subsets(self, nums):
        res = [[],]
        for i in range(1, len(nums) + 1):
            for tup in itertools.combinations(nums, i):
                res.append(list(tup))
        return res
79.单词搜索

题目

给定一个二维网格和一个单词,找出该单词是否存在于网格中

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是哪些水平相邻或垂直相邻的单元格,同一个单元格内的字母不允许被重复使用

实例

board =
[
  ['A','B','C','E'],
  ['S','F','C','S'],
  ['A','D','E','E']
]

给定 word = "ABCCED", 返回 true
给定 word = "SEE", 返回 true
给定 word = "ABCB", 返回 false
class Solution:
    def exist(self, board, word):
        if not board:
            return False
        for i in range(len(board)):
            for j in range(len(board[0])):
                if self.dfs(board, i, j, word):
                    return True
        return False
    
    def dfs(self, board, i, j, word):
        if len(word) == 0:
            return True
        if i < 0 or i >= len(board) or j < 0 or j >= len(board[0]) or word[0] != board[i][j]:
            return False
        tmp = board[i][j]
        board[i][j] = '0'
        res = self.dfs(board, i+1, j, word[1:]) or self.dfs(board, i-1, j, word[1:]) or self.dfs(board, i, j+1, word[1:]) or self.dfs(board, i, j-1, word[1:])
        board[i][j] = tmp
        return res
80.删除排序数组中的重复项 II

题目

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度

不要使用额外的数组空间,你必须在原地修改输入数组,并在使用O(1)额外空间的条件下完成

实例

给定 nums = [1,1,1,2,2,3],

函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。

你不需要考虑数组中超出新长度后面的元素
给定 nums = [0,0,1,1,1,1,2,3,3],

函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。

你不需要考虑数组中超出新长度后面的元素
class Solution:
    def removeDuplicates(self, nums):
        if not nums:
            return None
        i = 0
        # 添加一个标识为flag,如果flag = True则跳过,如果flag = False则移动
        flag = False
        for j in range(1, len(nums)):
            if nums[j] != nums[i]:
                i += 1
                nums[i] = nums[j]
                flag = False
            else:
                if not flag:
                    i += 1
                    nums[i] = nums[j]
                    flag = True
        return i+1
81.搜索旋转排序数组 II

题目

假设按照升序排序的数组在预先位置的某个点上进行了旋转

例如(数组[0, 0, 1, 2, 2, 5, 6]可能变为[2, 5, 6, 0, 0, 1, 2]

编写一个函数来判断给定的目标值是否存在于数组中,若存在,返回true,否则返回false

实例

输入: nums = [2,5,6,0,0,1,2], target = 0
输出: true
输入: nums = [2,5,6,0,0,1,2], target = 3
输出: false

思路

二分法

1.初始化 l = 0 和右指针r = n - 1

2.循环条件 l <= r

  • mid = (l + r) // 2,若nums[mid] == target,返回true
  • 若nums[mid] == nums[l] == nums[r],将左右指针同时向里移一位,l += 1, r -= 1
  • 若nums[mid] >= nums[l] 说明此时mid在左子列中:
    • 若此时nums[l] <= target < nums[mid],说明target在左子列中,则此时令r = mid - 1,否则令l = mid + 1
  • 否则,说明mid在右子列中:
    • 若nums[mid] < target <= nums[r]说明target在右子列中,则此时令l = mid + 1,否则令r = mid - 1

3.返回False

class solution:
    def search(self, nums, target):
        l = 0
        r = len(nums) - 1
        while l<=r:
            mid = (l+r) // 2
            if nums[mid] == target:
                return True
			# l和mid重复,l加一
            if nums[mid] == nums[l]:  
                l += 1
            # mid和r重复,r减一
            elif nums[mid] == nums[r]: 
                r -= 1
            # l到mid是有序的,判断target是否在其中
            elif nums[mid] > nums[l]: 
                # target在其中,选择l到mid这段
                if nums[l] <= target < nums[mid]:  
                    r = mid - 1
                # target不在其中,扔掉l到mid这段
                else:  
                    l = mid + 1
            # mid到r是有序的,判断target是否在其中
            elif nums[mid] < nums[r]:  
                if nums[mid] < target <= nums[r]:
                    l = mid + 1
                else:
                    r = mid - 1 
        return False
82.删除排序链表中的重复元素 II

题目

给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中没有出现的数字

实例

输入: 1->2->3->3->4->4->5
输出: 1->2->5
输入: 1->1->1->2->3
输出: 2->3

思路

快慢指针,用快指针跳过哪些有重复的数字,慢指针负责和快指针拼接

class Solution:
    def deletteDuplicates(self, head):
        if head == None or head.next == None:
            return head
        dummy = ListNode(-1)
        dummy.next = head
        slow = dummy
        fast = dummy.next
        while fast:
            if fast.next and fast.next.val == fast.val:
                tmp = fast.val
                # 移动快指针的标准:跳过重复数字
                while fast and tmp == fast.val:
                    fast = fast.next
            else:
                slow.next = fast
                slow = fast
                fast = fast.next
        slow.next = fast
        return dummy.next
83.删除排序链表中的重复元素

题目

给定一个排序链表,删除所有重复元素,使得每个元素出现一次

实例

输入: 1->1->2
输出: 1->2
输入: 1->1->2->3->3
输出: 1->2->3
class Solution:
    def deleteDuplicates(self, head):
        if head == None or head.next == None:
            return head
       	dummy_head = ListNode(None)
        dummy_head.next = head
        
        pre = dummy_head
        cur = head
        while cur:
            # 在pre存在的情况下,如果当前值和上一个值相等,就跳过当前值,将上一个值的指针直接指向当前值得下一个
            if pre and cur.val == pre.val:
                pre.next = cur.next
                # 将当前值的next指针置为空
                cur.next = None
                # 依然保证当前值在pre的下一个位置
                cur = pre.next
                continue
            pre = cur
            cur = cur.next
        return dummy_head.next
# 递归解法:
'''
	递归函数返回的不重复子链的头结点,在回溯过程中,比较当前节点和子链头结点的val是否相同,若相同则保留当前节点(删除子链头结点)
'''
class Solution:
    def deleteDuplicates(self, head):
        if head is None or head.next is None:
            return head
        child = self.deleteDuplicates(head.next)
        if child and head.val == child.val:
            head.next = child.next
            child.next = None
        return head
84.柱状图中最大的矩形

题目

给定n个非负整数,用来表示柱状图中各个柱子的高度,每个柱子彼此相邻,宽为1,求在该柱状图中,能够勾勒出来的矩形的最大面积

在这里插入图片描述

实例

输入: [2,1,5,6,2,3]
输出: 10

思路

要想找以第i根柱子为最矮柱子所能延伸的最大面积,是以i为中心,向左找第一个小于heights[i]的位置left_i;向右找第一个小于heights[i]的位置right_i,即最大面积为heights[i] * (right_i - left_i - 1)

当找i左边第一个小于heights[i]如果heights[i-1] >= heights[i]其实就是和heights[i-1]左边第一个小于heights[i-1]一样

单调栈

从左到右遍历柱子,对于每一个柱子,我们想找到第一个高度小于它的柱子,那么我们就可以使用一个单调递增栈来实现,如果柱子大于栈顶的柱子,那么说明不是我们要找的柱子,就入栈,继续遍历,如果比栈顶小,那么我们就找到了第一个小于栈顶的柱子

对于栈顶元素,其右边第一个小于它的就是当前遍历到的柱子,左边第一个小于它的就是栈中下一个要被弹出的元素,因此以当前栈顶为最小柱子的面积为当前栈顶的柱子高度 * (当前遍历到的柱子索引 - 1 - 栈中下一个要被弹出的元素索引 - 1 + 1)

class Solution:
    def largestRectangleArea(self, heights):
        stack = []
        # 防止空栈的情况
        heights = [0] + heights + [0]
        res = 0
        for i in range(len(heights)):
            # 构建单调栈
            while stack and heights[stack[-1]] > heights[i]:
                tmp = stack.pop()
                res = max(res, (i - stack[-1] - 1) * heights[tmp])
            stack.append(i)
        return res

补充

单调栈

设栈顶元素为b,栈顶第二个元素为a,自然有a < b(因为堆栈越往上越大)

这时候,若c出现,且c小于b,那么b的左右第一个比b小的两个元素就找到了,分别是a和c,b在中间最大

这时可以处理b,并重新整理堆栈,使其保持递增

若c大于b,那c入栈,继续循环,最后清理栈

# 单调栈的结构
for i in list:
    while i is not empyt and stack[-1] > i : # 先调整位置
        stack.pop()
    # 当前元素一定会入栈,不同的只是需不需要pop来调整位置
    stack.append(i)

问题在于:以B点位高的矩形的最大宽度为从a到c,其中a, c分别为B左边和右边第一个小于B的元素

单调栈的特点在于:

当遇见大数的时候,压入堆栈,等待之后处理

当遇见小数c的时候,意味着大数b的右边界c已经确定了,这时候开始pop,而以被pop出来的值(b)为高度的矩形的左右边界需要被确定

其右边界就是当前的小数,即c,左边界是堆栈的下一层元素,因为下一层的元素一定比当前小,且是第一小的元素,这时a确定

则以被pop出来的数为高度的矩形是(c - a - 1)* pop(),这里pop() == b

这里需要注意的是:

1.栈底要垫上 -1,表示栈底

2.循环结束,要清理堆栈,此时所有栈中继续存放的元素的右边界c都是结尾len(height) - 1

85.最大矩形

题目

给定一个仅包含0和1的二维二进制矩阵,找出只包含1的最大矩形,并返回其面积

实例

输入:
[
  ["1","0","1","0","0"],
  ["1","0","1","1","1"],
  ["1","1","1","1","1"],
  ["1","0","0","1","0"]
]
输出: 6

思路

可以转换为上一题的思路:栈

只需要遍历每行的高度,用上一题的方法求出最大矩形

在这里插入图片描述

class Solution:
    def maximalRectangle(self, matrix):
        if not matrix or not matrix[0]:
            return 0
        row = len(matrix)
        col = len(matrix[0])
        heights = [0] * (col + 2)
        res = 0
        for i in range(row):
            stack = []
            for j in range(col):
                if matrix[i][j] == '1':
                    heights[j+1] += 1
                else:
                    heights[j+1] = 0
            for j in range(col + 2):
                while stack and heights[stack[-1]] > heights[j]:
                    temp = stack.pop()
                    res = max(res, (j - stack[-1] - 1) * heights[temp])
                stack.append(j)
        return res
86.分隔链表

题目

给定一个链表和一个特定值x,对链表进行分隔,使得所有小于x的节点都在大于或等于x的节点之前,应当保留两个分区中每个节点的初始相对位置

实例

输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
class Solution:
    def partition(self, head, x):
        # before, after是用来创建两个链表的两个指针
        before = before_head = ListNode(0)
        # before_head, after_head用于保存两个链表的头部
        after = after_head = ListNode(0)
        
        while head:
            # 如果原始链表节点小于给定的x,将它分配给before链表
            if head.val < x:
                before.next = head
                before = before.next
            else: # 如果原始链表节点大于或等于给定的x,将它分配给after链表
                after.next = head
                after = after.next
            head = head.next
        # after链表的最后一个节点也是经过修改的链表的结束节点
        after.next = None
        # 一旦所有的节点都被正确分配到两个链表中,将它们组合返回
        before.next = after_head.next
        return before_head.next
87.扰乱字符串

题目

给定一个字符串s1,我们可以把它递归的分割成两个非空子字符串,从而将其表示为二叉树

	great
   /    \
  gr    eat
 / \    /  \
g   r  e   at
           / \
          a   t

上图是s1 = great的一种可能的表示形式

在扰乱这个字符串的过程中,我们可以挑选任何一个非叶结点,然后交换它的两个子节点

例如,挑选非叶结点gr,交换它的两个子节点,将会产生扰乱字符串rgeat

	rgeat
   /    \
  rg    eat
 / \    /  \
r   g  e   at
           / \
          a   t

rgeat称作great的一个扰乱字符串

同样,如果继续交换节点eatat的子节点,将会产生另一个新的扰乱字符串rgtae

	rgtae
   /    \
  rg    tae
 / \    /  \
r   g  ta  e
       / \
      t   a

rgtae称作great的一个扰乱字符串

给出两个长度相等的字符串s1和s2,判断s2是否是s1的扰乱字符串

实例

输入: s1 = "great", s2 = "rgeat"
输出: true
输入: s1 = "abcde", s2 = "caebd"
输出: false

思路

递归

S和T如果是扰动的话,那么必然存在一个再S上的长度l1,将S分成S1和S2两段,同样T上也有一个长度l2,把T分为T1和T2

1.如果S1和T1是扰动的,且S2和T2是扰动的,即字符串未交换

2.如果S1和T2是扰动的,且S2和T1是扰动的,即字符串交换了

例如:rgeat和great,rgeat可分成rg和eat两段,great可分成gr和eat两段,rg和gr是扰动的,eat和eat也是扰动的

class Solution:
    def isScramble(self, s1, s2):
        if len(s1) != len(s2):  
            return False
        if s1 == s2:  
            return True
        if sorted(s1) != sorted(s2):  
            return False
        for i in range(1, len(s1)):
            S1, S2 = s1[:i], s1[i:]
            T1, T2 = s2[:i], s2[i:]
            if self.isScramble(S1, T1) and self.isScramble(S2, T2):  
                return True
            T1, T2 = s2[:-i],s2[-i:]  # S1、S2不变,更新T1、T2
            if self.isScramble(S1, T2) and self.isScramble(S2, T1):  
                return True
        return False
88.合并两个有序数组

题目

给你两个有序整数数组,nums1和nums2,请你将nums2合并到nums1中,使nums1称为一个有序数组

说明

  • 初始化nums1和nums2的元素量分别为m和n
  • 可以假设nums1有足够的空间来保存nums2的元素

实例

输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3

输出: [1,2,2,3,5,6]
class Solution:
    def merge(self, nums1,m, nums2, n):
        end = m + n - 1
        end_1 = m - 1
        end_2 = n - 1
        while end_1 >= 0 and end_2 >= 0:
            if nums1[end_1] >= nums2[end_2]:
                nums1[end] = nums1[end_1]
                end_1 -= 1
                end -= 1
            else:
                nums1[end] = nums2[end_2]
                end_2 -= 1
                end -= 1
        nums1[:end_2+1] = nums2[:end_2+1]
89.格雷编码(未解决)

题目

格雷编码是一个二进制数字系统,在该系统中,两个连续的数值仅有一个位数的差异

给定一个代表编码总位数的非负整数n,打印其格雷编码序列,即使有多个不同答案,你也只需要返回其中的一种

格雷编码序列必须以0开头

实例

输入: 2
输出: [0,1,3,2]
解释:
00 - 0
01 - 1
11 - 3
10 - 2

对于给定的 n,其格雷编码序列并不唯一。
例如,[0,2,3,1] 也是一个有效的格雷编码序列。

00 - 0
10 - 2
11 - 3
01 - 1
输入: 0
输出: [0]
解释: 我们定义格雷编码序列必须以 0 开头。
     给定编码总位数为 n 的格雷编码序列,其长度为 2n。当 n = 0 时,长度为 20 = 1。
     因此,当 n = 0 时,其格雷编码序列为 [0]。
90.子集 II

题目

给定一个可能包含重复元素的整数数组nums,返回该数组所有可能的子集(幂集)

说明

解集不能包含重复的子集

实例

输入: [1,2,2]
输出:
[
  [2],
  [1],
  [1,2,2],
  [2,2],
  [1,2],
  []
]
# 递归
class Solution:
    def subsetsWithDup(self, nums):
     	res = []
        n = len(nums)
        nums.sort()
        def helper(idx, tmp):
            res.append(tmp)
            for i in range(idx, n):
                if i > idx and nums[i] == nums[i-1]:
                    continue
                helper(i+1, tmp+[nums[i]])
        helper(0, [])
        return res

# 迭代
class Solution:
    def subsetsWithDup(self, nums):
        if not nums:
            return []
        nums.sort()
        res = [[]]
        cur = []
        for i in range(len(nums)):
            if i > 0 and nums[i-1] == nums[i]:
                cur = [tmp + [nums[i]] for tmp in cur]
            else:
                cur = [tmp + [nums[i]] for tmp in res]
            res += cur 
        return res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值