记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步
目录
6/24 503. 下一个更大元素 II
循环数组 拼接两个数组即可
单调栈保存下标 遇到栈顶小于当前值
则栈顶下标结果为当前值
def nextGreaterElements(nums):
"""
:type nums: List[int]
:rtype: List[int]
"""
n=len(nums)
ans=[-1]*n
st = []
for i in range(2*n-1):
while st and nums[st[-1]]<nums[i%n]:
ans[st.pop()]=nums[i%n]
st.append(i%n)
return ans
6/25 2732. 找到矩阵中的好子集
将每一行看做一个二进制数
如果答案至少有一行 那么这一行都为0
如果答案至少两行 那么每一列最多一个1 这两行二进制and为0
如果答案至少3行 每一列最多为1 和两行相同
如果答案至少4行 每一列和不超过2
因为两行找不到答案说明任选两行至少存在一列这两行都为1 但其他两行必须为0
若要满足这个条件至少需要4列 但题目矩阵列数n<=5 所以不存在
只考虑答案为1行或2行的情况即可
def goodSubsetofBinaryMatrix(grid):
"""
:type grid: List[List[int]]
:rtype: List[int]
"""
m = {}
for i,row in enumerate(grid):
mask = 0
for j,v in enumerate(row):
mask |= v<<j
if mask ==0:
return [i]
m[mask]=i
for x,i in m.items():
for y,j in m.items():
if (x&y)==0:
return sorted([i,j])
return []
6/26 2741. 特别的排列
长度<14 用一个最长14位的二进制数s 描述当前可以用的数值位置
dfs(s,i) 搜索当前集合s的情况下 选取i位置的数值放在当前位置的情况
def specialPerm(nums):
"""
:type nums: List[int]
:rtype: int
"""
MOD=10**9+7
mem={}
def dfs(s,i):
if (s,i) in mem:
return mem[(s,i)]
if s==0:
return 1
res = 0
pre = nums[i]
for j,x in enumerate(nums):
if s>>j &1 and(pre%x==0 or x%pre==0):
res = (res+dfs(s^(1<<j),j))%MOD
mem[(s,i)]=res
return res
n = len(nums)
ans = 0
u = (1<<n)-1
for i in range(n):
ans = (ans+dfs(u^(1<<i),i))%MOD
return ans
6/27 2734. 执行子串操作后的字典序最小字符串
除了a 别的字符执行都会变小 所以从左到右遇到第一个非a字符开始执行操作
遇到a停止操作
如果全是a 则将最后一个操作一次为 z
def smallestString(s):
"""
:type s: str
:rtype: str
"""
l=list(s)
for i,c in enumerate(l):
if c=='a':
continue
for j in range(i,len(l)):
if l[j]=='a':
break
l[j]=chr(ord(l[j])-1)
return ''.join(l)
l[-1]='z'
return ''.join(l)
6/28 2742. 给墙壁刷油漆
dp[i,j]表示前i面墙 免费工作次数为j的最小开销
对于第i堵墙
如果付费将花费cost[i] 并且获得time[i]次免费油漆匠工作机会
如果免费 将减少1次免费工作机会
j最多可以为n 最小为-n
使用0~2n来代替
因为依次判断i 所以dp[i,j]只会影响dp[i+1,x]
所以只需要一维dp[j]即可
def paintWalls(cost, time):
"""
:type cost: List[int]
:type time: List[int]
:rtype: int
"""
n= len(cost)
dp=[float('inf')]*(2*n+1)
dp[n]=0
for (c,t) in zip(cost,time):
g=[float('inf')]*(2*n+1)
for j in range(2*n+1):
g[min(j+t,2*n)]=min(g[min(j+t,2*n)],dp[j]+c)
if j>0:
g[j-1]=min(g[j-1],dp[j])
dp=g
return min(dp[n:])
6/29 2710. 移除字符串中的尾随零
从后往前判断 如果遇到0则往前一步
def removeTrailingZeros(num):
"""
:type num: str
:rtype: str
"""
for i in range(len(num)):
if num[-1-i]!='0':
break
return num if i==0 else num[:-i]
6/30 494. 目标和
1.dp 动态规划
dp[i][value] 前i个数 答案为value的可能情况
因为-1000<=value<=1000
方便起见 全部加1000 => 0<=value<=2000
v为当前位置数值 j为当前考虑value值
dp[i][j] = dp[i-1][j-v] + dp[i-1][j+v]
2.dp 动态规划
总和为total 变负数的总和绝对值为neg 正数总和total-neg target=total-2*neg
转化为neg = (total-target)/2 选取若干个数 总和为neg
dp[i][j] 前i个数 总和可以为j的可能方式
num = nums[i]
dp[i+1][j] = dp[i][j]+dp[i][j-num]
def findTargetSumWays(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
total = sum(nums)
if target>total or target<-total:
return 0
n = len(nums)
m = 2001
dp = [[0]*m for _ in range(n+1)]
dp[0][nums[0]+1000]+=1
dp[0][1000-nums[0]]+=1
for i in range(1,n):
v = nums[i]
for j in range(m):
if j-v>=0 and dp[i-1][j-v]>0:
dp[i][j] += dp[i-1][j-v]
if j+v<m and dp[i-1][j+v]>0:
dp[i][j]+=dp[i-1][j+v]
return dp[n-1][target+1000]
def findTargetSumWays2(nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
diff = sum(nums) - target
if diff<0 or diff%2==1:
return 0
n = len(nums)
neg = diff//2
dp = [[0]*(neg+1) for _ in range(n+1)]
dp[0][0]=1
for i in range(n):
num = nums[i]
for j in range(neg+1):
dp[i+1][j]=dp[i][j]
if j>=num:
dp[i+1][j] += dp[i][j-num]
return dp[n][neg]