数组

118. 杨辉三角

给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。
输入: 5
输出:
[    [1],
    [1,1],
   [1,2,1],
  [1,3,3,1],
 [1,4,6,4,1]
]

可以发现每一行比前一行多一个数 121=011+110 可以俩个列表 分别收尾加0后相加得到。

63. 不同路径 II

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
输入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
输出: 2

设置一个dp m行n列都是0. 然后确定边界
首先看原数组[0][0]是不是1,如果是0,则dp[0][0]=1,否则 return 0
然后确定第一行和第一列 for i in range(1,M)如果原数组数是0 则dp[0][i]=1 否则break列同理

row, col = len(obstacleGrid),len(obstacleGrid[0])
        dp = [[0 for j in range(col)] for i in range(row)]
        if obstacleGrid[0][0]==0:
            dp[0][0]=1
        if dp[0][0]==0:
            return 0
        for i in range(1,row):
            if obstacleGrid[i][0]==0:
                dp[i][0]=1
            else:
                break
        for j in range(1,col):
            if obstacleGrid[0][j]==0:
                dp[0][j]=1
            else:
                break
        for i in range(1,row):
            for j in range(1,col):
                if obstacleGrid[i][j]==0:
                    dp[i][j]=dp[i-1][j]+dp[i][j-1]
        return dp[-1][-1]

152乘积最大子数组

给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。

可以分负号奇偶考虑,如果是偶数则是全乘最大;如果是奇数,它的左右两边的负数个数一定为偶数,只需求两边最大值。遇到0,则重置。

nums2=nums[::-1]
for i in range(1,len(nums)):
    nums[i]=nums[i]*(nums[i-1] or 1)
    nums2[i]=nums2[i]*(nums2[i-1] or 1)
return max(nums+nums2)

或者用dp,我们只要记录前i的最小值, 和最大值, 那么 dp[i] = max(nums[i] * pre_max, nums[i] * pre_min, nums[i]), 这里0 不需要单独考虑, 因为当相乘不管最大值和最小值,都会置0

if not nums: return 
res = nums[0]
pre_max = nums[0]
pre_min = nums[0]
for num in nums[1:]:
    cur_max = max(pre_max * num, pre_min * num, num)
    cur_min = min(pre_max * num, pre_min * num, num)
    res = max(res, cur_max)
    pre_max = cur_max
    pre_min = cur_min
return res

546. 移除盒子

给出一些不同颜色的盒子,盒子的颜色由数字表示,即不同的数字表示不同的颜色。
你将经过若干轮操作去去掉盒子,直到所有的盒子都去掉为止。每一轮你可以移除具有相同颜色的连续 k 个盒子(k >= 1),这样一轮之后你将得到 k*k 个积分。
当你将所有盒子都去掉之后,求你能获得的最大积分和。
示例:
输入:boxes = [1,3,2,2,2,3,4,3,1]
输出:23
解释:
[1, 3, 2, 2, 2, 3, 4, 3, 1] 
----> [1, 3, 3, 4, 3, 1] (3*3=9 分) 
----> [1, 3, 3, 3, 1] (1*1=1 分) 
----> [1, 1] (3*3=9 分) 
----> [] (2*2=4 分)
D={}
def m(l,r,n):                   #n代表l位置前面有连续n个和l位置一样的颜色
    if (l,r,n) in D:
        return D[(l,r,n)]
    if l+1==r:                  #只是最后一个数字直接结算
        return (n+1)**2
    if boxes[l+1]==boxes[l]:    # 发现邻居和自己相同,则左边连续的n加一
        return m(l+1,r,n+1)
    else:
        res=(n+1)**2+m(l+1,r,0)           #先直接结算,之后再看有没有和自己一样的
        for j in range(l+2,r):            # 已知下一个和自己不一样,从下下个开始找和自己一样的兄弟
            if boxes[j]==boxes[l]:        # 让自己的下一个到这个兄弟之前结算,然后让自己和兄弟加起来结算,
                res=max(res,m(l+1,j,0)+m(j,r,n+1))
        D[(l,r,n)]=res
        return res
return m(0,len(boxes),0)

50. Pow(x, n)

实现 pow(x, n) ,即计算 x 的 n 次幂函数。
示例 1:
输入: 2.00000, 10
输出: 1024.00000

设置一个函数对n,y=x**(n//2)对n向下取整,

def m(n):
    if n==0:
        return 1
    k=n//2
    y=m(k)
    return y*y*x if n%2 else y*y
return m(n) if n>=0 else 1/m(-n)

2. 两数相加

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字.如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
res1=res=ListNode(0)
temp=0
while l1 or l2:
    a=l1.val if l1 else 0            #这边要用到l1.val 需要if判断l1是否存在
    b=l2.val if l2 else 0
    r=a+b+temp
    res.next=ListNode(r%10)
    res=res.next
    temp=r//10
    l1=l1.next if l1 else None         #这边要用到l1.next 需要if判断l1是否存在
    l2=l2.next if l2 else None
if temp:
    res.next=ListNode(temp)
return res1.next

166. 分数到小数

给定两个整数,分别表示分数的分子 numerator 和分母 denominator,以字符串形式返回小数。
如果小数部分为循环小数,则将循环的部分括在括号内。
示例 1:
输入: numerator = 1, denominator = 2
输出: "0.5"
if numerator==0:
return '0'
res=[]
if (numerator>0)^(denominator>0):  # 首先判断结果正负, 异或作用就是 两个数不同 为 True 即 1 ^ 0 = 1 或者 0 ^ 1 = 1
   res.append('-')
numerator,denominator=abs(numerator),abs(denominator)       # 取绝对值
a,b = divmod(numerator,denominator)
res.append(str(a))
if b==0:                                                    # 判断到底有没有小数
   return ''.join(res)
res.append('.')                                        # 打小数点,准备处理余数
D={b:len(res)}                                        # 余数记录下来
while b:
   b=b*10
   a,b=divmod(b,denominator)
   res.append(str(a))
   if D.get(b):                                     # 余数前面出现过,说明开始循环了,加括号
       res.insert(D[b],'(')
       res.append(')')
       break                                      # 重要的跳出循环
   D[b]=len(res)                                  # 把该余数位置记录下来
return ''.join(res)

36. 有效的数独

判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
row=[{} for i in range(9)]
col=[{} for i in range(9)]
box=[{} for i in range(9)]
for i in range(9):
    for j in range(9):
        if board[i][j].isdigit():                   # 判断是否是数字
            ib=(i//3)*3+j//3                        # 3*3宫格的排序编号
            a=int(board[i][j])
            row[i][a]=row[i].get(a,0)+1
            col[j][a]=col[j].get(a,0)+1
            box[ib][a]=box[ib].get(a,0)+1
            if row[i][a]>1 or col[j][a]>1 or box[ib][a]>1:            #每个数就遍历一次 判断
                return False
return True

454. 四数相加 II

给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -228 到 228 - 1 之间,最终结果不会超过 231 - 1 。
例如:
输入:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
输出:
2
解释:
两个元组如下:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
Di=collections.defaultdict(int)                # 用了俩数之和 复杂度变n**2
res=0
for i in A:
    for j in B:
        Di[i+j]+=1
for i in C:
    for j in D:
        res+=Di[-(i+j)]
return res

134. 加油站

在一条环路上有 N 个加油站,其中第 i 个加油站有汽油 gas[i] 升。
你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i+1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。
如果你可以绕环路行驶一周,则返回出发时加油站的编号,否则返回 -1。
说明: 
如果题目有解,该答案即为唯一答案。
输入数组均为非空数组,且长度相同。
输入数组中的元素均为非负数。
示例 1:
输入: 
gas  = [1,2,3,4,5]
cost = [3,4,5,1,2]
输出: 3
解释:
从 3 号加油站(索引为 3 处)出发,可获得 4 升汽油。此时油箱有 = 0 + 4 = 4 升汽油
开往 4 号加油站,此时油箱有 4 - 1 + 5 = 8 升汽油
开往 0 号加油站,此时油箱有 8 - 2 + 1 = 7 升汽油
开往 1 号加油站,此时油箱有 7 - 3 + 2 = 6 升汽油
开往 2 号加油站,此时油箱有 6 - 4 + 3 = 5 升汽油
开往 3 号加油站,你需要消耗 5 升汽油,正好足够你返回到 3 号加油站。
因此,3 可为起始索引。
dp=[i-j for (i,j) in zip(gas,cost)]
 temp=0                       # 用于计算起始点到当前加起来和是否为正
 r=0                          # 设置初始起点
 for i in range(len(dp)):
     temp+=dp[i]
     if temp<0:                 # 则从r出发行不通,r需要换成下一个加油站开始
         temp=0
         r=i+1                 # 初始起点变更
 return r if sum(dp)>=0 else -1          # 只要总的>=0 ,肯定就会有一个起点

210. 课程表 II

现在你总共有 n 门课需要选,记为 0 到 n-1。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。
可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。
示例 1:
输入: 2, [[1,0]] 
输出: [0,1]
解释: 总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。
res=[]
rd=[0 for i in range(numCourses)]                         # 每个课程的  入度
D=collections.defaultdict(list)                                # 字典记录可以通往哪些课程
for a,b in prerequisites:
    D[b].append(a)                                      # 字典记录b可以通往哪些课程
    rd[a]+=1                                                 # 记录a入度
stack=collections.deque()                        # 存放入度为0的课程 也就是可以选的课程
for i in range(numCourses):
    if rd[i]==0:
        stack.append(i)
while stack:
    p=stack.popleft()
    res.append(p)
    for k in D[p]:                                    # 取完一门入度为0 的课程后 他能通向的课程入度都减去1
        rd[k]-=1
        if rd[k]==0:
            stack.append(k)
return res if len(res)==numCourses else []

240. 搜索二维矩阵 II

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
示例:
现有矩阵 matrix 如下:
[
  [1,   4,  7, 11, 15],
  [2,   5,  8, 12, 19],
  [3,   6,  9, 16, 22],
  [10, 13, 14, 17, 24],
  [18, 21, 23, 26, 30]
]
if not matrix:
	return False
row,col=len(matrix),len(matrix[0])
i=row-1                                            # 从左下角开始,如果正好返回True,比target小就往右 如果大就往上
j=0
while i>=0 and j<col:
    if matrix[i][j]==target:
        return True
    elif matrix[i][j]<target:
        j+=1
    else:
        i-=1
return False

19. 删除链表的倒数第N个节点

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.

用快慢指针,快指正先走n步,然后一起走。

if n==0 or not head:
    return head
h=ListNode(0)                     #  在head前面弄一个节点指向head。因为有可能n就是链表长度,删除的链表头不能表示。
h.next=head
fast,slow=h,h
for i in range(n):
    fast=fast.next
while fast.next:
    fast=fast.next
    slow=slow.next
slow.next=slow.next.next
return h.next

200. 岛屿数量

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
示例 1:
输入:
[
['1','1','1','1','0'],
['1','1','0','1','0'],
['1','1','0','0','0'],
['0','0','0','0','0']
]
输出: 1
if not grid:
    return 0
row,col=len(grid),len(grid[0])
def dfs(i,j):                                        # 深度搜索将这个1周围的1全部变成0
    grid[i][j]='0'
    for x,y in [(1,0),(-1,0),(0,1),(0,-1)]:
        if 0<=i+x<row and 0<=j+y<col and grid[i+x][j+y]=='1':
            dfs(i+x,j+y)
res=0
for i in range(row):
    for j in range(col):
        if grid[i][j]=='1':                     # 每一次深度搜索,结果加一
            dfs(i,j)
            res+=1
return res

334. 递增的三元子序列

给定一个未排序的数组,判断这个数组中是否存在长度为 3 的递增子序列。
数学表达式如下:
如果存在这样的 i, j, k,  且满足 0 ≤ i < j < k ≤ n-1,
使得 arr[i] < arr[j] < arr[k] ,返回 true ; 否则返回 false 。
说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1) 。
示例 1:
输入: [1,2,3,4,5]
输出: true
r1,r2=float('inf'),float('inf')                   #用两个变量 r1, r2 分别记录第一小和第二小的数。然后遍历 nums。
for i in nums:
    if i<=r1:                                  # 只要碰到比 r1 小的数我们就替换掉 r1
        r1=i
    elif i<=r2:                                #,碰到比 r1 大但比 r2 小的数就替换 r2。
        r2=i
    else:
        return True                   # 只要碰到比 r2 大的数就已经满足题意了。
return False

179. 最大数

给定一组非负整数,重新排列它们的顺序使之组成一个最大的整数。
示例 1:
输入: [10,2]
输出: 210
def m(a):                                   # 相同前缀,不同长短的比较 :比如 12和121,只需要把12转化成 0.12 12 12 12......
   a=str(a)                                 #  121转换成0.121 121 121 ...即可。
   n=len(a)                                 # 就是12/99=0.1212121212   
   return int(a)/(10**n-1)                   # 132/999  1234/9999 12345/99999
   
nums.sort(key=lambda x:m(x),reverse=True)
if nums[0]==0:                                  # 如果是00000000就返回一个0
   return '0'
else:
   return ''.join([str(i) for i in nums])

324. 摆动排序 II

给定一个无序的数组 nums,将它重新排列成 nums[0] < nums[1] > nums[2] < nums[3]... 的顺序。
示例 1:
输入: nums = [1, 5, 1, 1, 6, 4]
输出: 一个可能的答案是 [1, 4, 1, 5, 1, 6]
nums.sort(reverse=True)     # 先将nums逆序排序,然后在中间将数组折断,间隔插入
mid = len(nums) // 2           # 因为//是向下取整 所以【:mid】的长度<=【mid:】 又因为先小后大nums[0]<nums[1]>nums[2]
nums[0::2],nums[1::2] =nums[mid:], nums[:mid]           #所以 小的部分是【mid:】 所以从大到小排序

486. 预测赢家

给定一个表示分数的非负整数数组。 玩家 1 从数组任意一端拿取一个分数,随后玩家 2 继续从剩余数组任意一端拿取分数,然后玩家 1 拿,…… 。每次一个玩家只能拿取一个分数,分数被拿取之后不再可取。直到没有剩余分数可取时游戏结束。最终获得分数总和最多的玩家获胜。
给定一个表示分数的数组,预测玩家1是否会成为赢家。你可以假设每个玩家的玩法都会使他的分数最大化。
示例 1:
输入:[1, 5, 2]
输出:False
解释:一开始,玩家1可以从1和2中进行选择。
如果他选择 2(或者 1 ),那么玩家 2 可以从 1(或者 2 )和 5 中进行选择。如果玩家 2 选择了 5 ,那么玩家 1 则只剩下 1(或者 2 )可选。
所以,玩家 1 的最终分数为 1 + 2 = 3,而玩家 2 为 5 。
因此,玩家 1 永远不会成为赢家,返回 False 。

当i>j时,dp [i] [j]=0
当i=j时,只剩一个数字,当前玩家只能拿去这个数字
当i<j时,当前玩家可以选择nums[i]或nums[j],然后轮到另一个玩家在数组剩下的部分选取数字。在两种方案中,当前玩家会选择最优的方案,使得自己的分数最大化。因此可以得到如下状态转移方程:

N=len(nums) 
dp=[[0 for j in range(N)] for i in range(N)]
for i in range(N):
    dp[i][i]=nums[i]
for i in range(N-2,-1,-1):
    for j in range(i+1,N):
        dp[i][j]=max(nums[i]-dp[i+1][j],nums[j]-dp[i][j-1])    # 这是关键根据这个确定i ,j范围
return dp[0][N-1]>=0

60. 第k个排列

给出集合 [1,2,3,…,n],其所有元素共有 n! 种排列。
按大小顺序列出所有排列情况,并一一标记,当 n = 3 时, 所有排列如下:
"123"
"132"
"213"
"231"
"312"
"321"
给定 n 和 k,返回第 k 个排列。
说明:
给定 n 的范围是 [1, 9]。
给定 k 的范围是[1,  n!]。
示例 1:
输入: n = 3, k = 3
输出: "213"

以1开头的排列一共有 (n-1)! 个;

nums=[i for i in range(1,n+1)]          # res从里面取
res=''
while nums:
    ind=(k-1)//(math.factorial(n-1))           # 应为是(1,(n-1)!)是nums[0] 所以用k-1地板除来向下取整
    res+=str(nums.pop(ind))
    k=k%(math.factorial(n-1))                 #规模变成n-1的子问题
    n-=1
return res

1004. 最大连续1的个数 III

给定一个由若干 0 和 1 组成的数组 A,我们最多可以将 K 个值从 0 变成 1 。
返回仅包含 1 的最长(连续)子数组的长度。
示例 1:
输入:A = [1,1,1,0,0,0,1,1,1,1,0], K = 2
输出:6
解释: 
[1,1,1,0,0,1,1,1,1,1,1]
粗体数字从 0 翻转到 1,最长的子数组长度为 6。

设置一个区间【l,r】大小的滑动窗口,r指正一直右移,当count(代表窗口里0的 个数)大于K时就需要右移左指针(确保当前窗口是符合情况的最大窗口),当右移前l指针位置是0则count-1.

N=len(A)
l,r,count=0,0,0
for r in range(N):
    if A[r]==0:
        count+=1
    if count>K:
        if A[l]==0:
            count-=1
        l+=1
return r-l+1

1371. 每个元音包含偶数次的最长子字符串

给你一个字符串 s ,请你返回满足以下条件的最长子字符串的长度:每个元音字母,即 'a','e','i','o','u' ,在子字符串中都恰好出现了偶数次。
示例 1:
输入:s = "eleetminicoworoep"
输出:13
解释:最长子字符串是 "leetminicowor" ,它包含 e,i,o 各 2 个,以及 0 个 a,u 。
dp=[float('-inf')]*(2**5)  # 只考虑每个元音奇偶次数,因此考虑用二进制来记录
dp[0]=-1                        # 特殊
res=0
temp=0
for i in range(len(s)):
    if s[i]=='a':
        temp^=1<<0          # 这是2的0次方就是1的情况
    elif s[i]=='e':
        temp^=1<<1          # 这是2的情况
    elif s[i]=='i':
        temp^=1<<2
    elif s[i]=='o':
        temp^=1<<3
    elif s[i]=='u':
        temp^=1<<4
    if dp[temp]!=float('-inf'):      # 如果都是偶数 就和dp[0]=-1减去;要是有元音就是1个或三个时相同
        res=max(res,i-dp[temp])       # (确保和temp出现第一次时直接相减后中间是偶数个元音)就直接减
    else:
        dp[temp]=i
return res

37. 解数独

编写一个程序,通过已填充的空格来解决数独问题。
一个数独的解法需遵循如下规则:
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
空白格用 '.' 表示。
row,col=len(board),len(board[0])
res=[]
l_row,l_col,l_rc=[[True]*9 for i in range(9)],[[True]*9 for i in range(9)],[[True]*9 for i in range(9)]
for i in range(row):
    for j in range(col):
        if board[i][j]=='.':
            res.append((i,j))
        else:
            k=int(board[i][j])
            l_row[i][k-1]=False
            l_col[j][k-1]=False
            l_rc[(i//3)*3+j//3][k-1]=False
jug=[False]                              # 重点 

def dfs(i):
    if i==len(res):
        jug[0]=True                     # 重点 
        return
    x,y=res[i]
    for j in range(9):
        if l_row[x][j] and l_col[y][j] and l_rc[(x//3)*3+y//3][j]:
            board[x][y]=str(j+1)            # 注意j+1 而且还得是字符形式    因为主要是l_row,l_col,l_rc记录是否可以改后面就不用改了 改了会出错
            l_row[x][j],l_col[y][j],l_rc[(x//3)*3+y//3][j]=False,False,False
            dfs(i+1)
            l_row[x][j],l_col[y][j],l_rc[(x//3)*3+y//3][j]=True,True,True
        if jug[0]:                        # 重点 在让符合条件时跳出for循环返回上面
            return
dfs(0)

685. 冗余连接 II

在本问题中,有根树指满足以下条件的有向图。该树只有一个根节点,所有其他节点都是该根节点的后继。每一个节点只有一个父节点,除了根节点没有父节点。
输入一个有向图,该图由一个有着N个节点 (节点值不重复1, 2, ..., N) 的树及一条附加的边构成。附加的边的两个顶点包含在1到N中间,这条附加的边不属于树中已存在的边。
结果图是一个以边组成的二维数组。 每一个边 的元素是一对 [u, v],用以表示有向图中连接顶点 u 和顶点 v 的边,其中 u 是 v 的一个父节点。
返回一条能删除的边,使得剩下的图是有N个节点的有根树。若有多个答案,返回最后出现在给定二维数组的答案。
示例 1:
输入: [[1,2], [1,3], [2,3]]
输出: [2,3]
解释: 给定的有向图如下:
  1
 / \
v   v
2-->3
N=len(edges)
dp=[0 for i in range(N+1)]
D=collections.defaultdict(list)
r=[]
def huan(a,N):
    temp=a 
    while D[temp] and N:
        temp=D[temp][0]
        N-=1
        if temp==a:
            return True
    return False

for a,b in edges:
    dp[b]+=1
    D[b].append(a)
    r.append(b)
    
if max(dp[1:])==1:                 # 有环 找最后一个促使接入环的
    for i in r[::-1]:
        if huan(i,N):
            return [D[i][0],i]
else:                               # 有冲突
    i=dp.index(2)
    x,y=D[i]
    if huan(x,N):                   # 冲突里先找第一个是不是有环
        return [x,i]               # 没有环就返回后面一个
    return [y,i]

416. 分割等和子集

给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:
每个数组中的元素不会超过 100
数组的大小不会超过 200
示例 1:
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
if not nums or len(nums)<2 or sum(nums)%2:          # 如果数组不存在,和为奇数, 个数小于2是不能分的
    return False
M=sum(nums)//2
if max(nums)>M:                         # 这里要注意如果最大值超过一半就false不然下面数组nums[i]列会越界错误
    return False
N=len(nums)
dp=[[False]*(M+1) for i in range(N)]                    # 设置二维dp数组,行是nums数组个数,列是target目标值就是和的一半(注意M+1)
for i in range(N):                        # 第0列 初始化
    dp[i][0]=True
dp[0][nums[0]]=True                   # 第0行 初始化
for i in range(1,N):
    for j in range(1,M+1):
        if nums[i]>j:
            dp[i][j]=dp[i-1][j]
        else:
            dp[i][j]=dp[i-1][j] or dp[i-1][j-nums[i]]
return dp[-1][-1]

135. 分发糖果

老师想给孩子们分发糖果,有 N 个孩子站成了一条直线,老师会根据每个孩子的表现,预先给他们评分。
你需要按照以下要求,帮助老师给这些孩子分发糖果:
每个孩子至少分配到 1 个糖果。
评分更高的孩子必须比他两侧的邻位孩子获得更多的糖果。
那么这样下来,老师至少需要准备多少颗糖果呢
示例 1:
输入:[1,0,2]
输出:5
解释:你可以分别给这三个孩子分发 2、1、2 颗糖果。
    def candy(self, ratings: List[int]) -> int:
        N = len(ratings)
        res=1    
        inc,dec,temp=1,0,1             # 递增长度,递减长度,当前位置糖果
        for i in range(1,N):
            if ratings[i]>=ratings[i-1]:    # 这里有等号,先算递增
                temp=1 if ratings[i]==ratings[i-1] else temp+1
                inc=temp          # 递增长度就是当前位置的糖果,当前位置糖果temp是一直更新的,所以inc只在递增时更新
                dec=0             # dec和res temp 在增和减都更新
                res+=inc         
            else:
                temp=1
                dec+=1
                if dec==inc:   # 后面递减长度和递增一样时,递增的最后一位算递减元素,递减就要加一个
                    dec+=1
                res+=dec
        return res

714. 买卖股票的最佳时机含手续费

给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
示例 1:
输入: prices = [1, 3, 2, 8, 4, 9], fee = 2
输出: 8
解释: 能够达到的最大利润:  
在此处买入 prices[0] = 1
在此处卖出 prices[3] = 8
在此处买入 prices[4] = 4
在此处卖出 prices[5] = 9
总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
    def maxProfit(self, prices: List[int], fee: int) -> int:
        n = len(prices)
        dp = [[0, -prices[0]]] + [[0, 0] for _ in range(n - 1)]
        for i in range(1, n):
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i] - fee)
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i])
        return dp[n - 1][0]

738. 单调递增的数字

给定一个非负整数 N,找出小于或等于 N 的最大的整数,同时这个整数需要满足其各个位数上的数字是单调递增。
(当且仅当每个相邻位数上的数字 x 和 y 满足 x <= y 时,我们称这个整数是单调递增的。)
示例 1:
输入: N = 10
输出: 9
    def monotoneIncreasingDigits(self, N: int) -> int:
        l=[int(i) for i in str(N)]
        lenL=len(l)
        ind=len(l)-1
        for i in range(lenL-1):
            if l[i]>l[i+1]:
                ind=i 
                break
        if ind==len(l)-1:
            return N                            # 如果本来就是递增的,就返回原来数
        else:
            for i in range(ind+1,lenL):          # 不然从第一个递减的后面全部换成9,该位置变成原来数字减一但是要看减完1后与前面比较
                l[i]=9
            l[ind]=l[ind]-1
            while ind>0 and l[ind-1]>l[ind]:
                l[ind]=9
                l[ind-1]-=1
                ind=ind-1
            if l[0]==0:      # 第一位是0就去掉
                l=l[1:]
            return int(''.join([str(i) for i in l]))

376. 摆动序列

如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。
例如, [1,7,4,9,2,5] 是一个摆动序列,因为差值 (6,-3,5,-7,3) 是正负交替出现的。相反, [1,4,7,2,5] 和 [1,7,4,5,5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
给定一个整数序列,返回作为摆动序列的最长子序列的长度。 通过从原始序列中删除一些(也可以不删除)元素来获得子序列,剩下的元素保持其原始顺序。
示例 1:
输入: [1,7,4,9,2,5]
输出: 6 
解释: 整个序列均为摆动序列。
    def wiggleMaxLength(self, nums: List[int]) -> int:
        N=len(nums)
        if N<2:
            return N
        top,low=[1]+[0]*(N-1),[1]+[0]*(N-1)           # 结尾为上升的摆动序列,结尾趋势为下降的摆动序列
        for i in range(1,N):
            if nums[i]>nums[i-1]:
                top[i]=max(top[i-1],low[i-1]+1)
                low[i]=low[i-1]
            elif nums[i]<nums[i-1]:
                low[i]=max(top[i-1]+1,low[i-1])
                top[i]=top[i-1]
            else:
                top[i]=top[i-1]
                low[i]=low[i-1]
        return max(top[N-1],low[N-1])

85. 最大矩形

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

    def maximalRectangle(self, matrix: List[List[str]]) -> int:
        rows = len(matrix)
        cols = len(matrix[0])
        res=0
        dp=[[0 for j in range(cols)] for i in range(rows)]  # 记录以ij为最右边的连续的1的长度
        for i in range(rows):
            dp[i][0]=1 if matrix[i][0]=='1' else 0
        for i in range(rows):
            for j in range(1,cols):
                if matrix[i][j]=='1':
                    dp[i][j]=dp[i][j-1]+1
        for i in range(rows):
            for j in range(cols):
                if dp[i][j]:
                    res=max(res,dp[i][j])
                k=dp[i][j]                    # 记录从当前所在行往上最小的宽
                for temp in range(i-1,-1,-1): # 以ij为右下角的矩形 k为宽度 i-temp+1为高
                    if dp[temp][j]==0:
                        break
                    k = min(dp[temp][j], k)
                    res=max(res,(i-temp+1)*k)
        return res
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值