记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步
目录
4/3 1053. 交换一次的先前排列
从后往前
记录每个数字右侧第一次出现的位置
对于当前位置i num=arr[i]
遍历比num小的数值 是否在右侧出现过
挑选最大值且最靠前的位置
def prevPermOpt1( arr):
"""
:type arr: List[int]
:rtype: List[int]
"""
n = len(arr)
m = {}
for i in range(n-1,-1,-1):
num = arr[i]
m[num] = i
tmp = n
for j in range(num-1,-1,-1):
if j in m:
tmp = m[j]
break
if tmp<n:
arr[i],arr[tmp]=arr[tmp],arr[i]
break
return arr
4/4 1000. 合并石头的最低成本
每次减少k-1堆 最后剩下一对
所以n=len(stones) n%(k-1)=1
dp[l][r][t]描述在[l,r]区间内合并为t堆的最低成本
对于所有dp[i][i][1]=0 其他为正无穷
t=1时 dp[l][r][t] = d[l][r][k]+sum([l,r])
否则 dp[l][r][t] = min(dp[l][p][1]+d[p+1][r][t-1])
目标为dp[0][n-1][1]
def mergeStones(stones, k):
"""
:type stones: List[int]
:type k: int
:rtype: int
"""
n = len(stones)
if n%(k-1)!=1 and k>2:
return -1
dp = [[[float("inf")]*(k+1) for _ in range(n)] for _ in range(n)]
su = [0]*n
s = 0
for i in range(n):
dp[i][i][1] = 0
s += stones[i]
su[i] = s
for num in range(2,n+1):
for l in range(n-num+1):
r = l+num-1
for t in range(2,k+1):
for p in range(l,r,k-1):
dp[l][r][t] = min(dp[l][r][t],dp[l][p][1]+dp[p+1][r][t-1])
tmp = su[r]
if l>0:
tmp -= su[l-1]
dp[l][r][1] = min(dp[l][r][1],dp[l][r][k]+tmp)
return dp[0][n-1][1]
4/5 2427. 公因子的数目
遍历每个数
def commonFactors(a, b):
"""
:type a: int
:type b: int
:rtype: int
"""
v = min(a,b)
ans = 0
for i in range(1,v+1):
if a%i ==0 and b%i==0:
ans +=1
return ans
4/6 1017. 负二进制转换
先转换为正常二进制
对于奇数位 0,2,4,8 不会产生影响
对于偶数位 1,3,5 需要负二进制增加后一位相加实现
例如 2^3=8 需要(-2)4+(-2)3=16-8=8
def baseNeg2(n):
"""
:type n: int
:rtype: str
"""
if n==0:
return "0"
l = [0]*40
tmp = n
cur = 0
while tmp>0:
l[cur]=tmp%2
tmp//=2
cur+=1
cur = 0
while cur<35:
l[cur+1]+=l[cur]//2
l[cur] = l[cur]%2
if cur%2==0:
cur +=1
continue
if l[cur]==1:
l[cur+1]+=1
cur+=1
for i in range(29,-1,-1):
if l[i]==1:
cur = i
break
return "".join([str(l[loc]) for loc in range(cur,-1,-1)])
4/7 1040. 移动石子直到连续 II
按位置从小到大排序
假设有n个石子
最小移动次数 判断每个石子为滑动窗口左端 在连续n的长度下拥有最多的石子数m n-m及最小移动次数
最大移动次数 端点石子只移动到最近可移动的位置 那么处于0~n-2 或者1~n-1位置间的空位都能移动到
def numMovesStonesII(stones):
"""
:type stones: List[int]
:rtype: List[int]
"""
n= len(stones)
stones.sort()
if stones[n-1]-stones[0]+1==n:
return [0,0]
mi = n
r = 0
for l in range(n):
while r+1<n and stones[r+1]-stones[l]+1<=n:
r+=1
if r-l+1==n-1 and stones[r]-stones[l]+1==n-1:
mi = min(mi,2)
else:
mi = min(mi,n-(r-l+1))
ma = max(stones[n-2]-stones[0]+1,stones[n-1]-stones[1]+1)-(n-1)
return [mi,ma]
4/8 1125. 最小的必要团队
技能最多16个 使用一个16位二进制表示技能拥有状态
遍历所有人 求出每个人的技能状态
dp[i] 表示满足技能i的最小人数 初始值为m
preskill[i] 表示最小dp[i]是由此技能而来
prepeo[i] 表示最小dp[i]是增加了这个人
从而记录每一步的人
最后从满状态开始往回寻找路径上的人
n = len(req_skills)
m = len(people)
skillind = {s:i for i,s in enumerate(req_skills)}
dp = [m]*(1<<n)
dp[0] = 0
preskill = [0]*(1<<n)
prepeo = [0]*(1<<n)
for i,p in enumerate(people):
curskill = 0
for s in p:
curskill |= 1<<skillind[s]
for pre in range(1<<n):
nxt = pre|curskill
if dp[nxt]>dp[pre]+1:
dp[nxt] = dp[pre]+1
preskill[nxt] = pre
prepeo[nxt] = i
ans = []
i = (1<<n)-1
while i>0:
ans.append(prepeo[i])
i = preskill[i]
return ans
4/9 2399. 检查相同字母间的距离
从头遍历 遇到第二次时判断两字母之间的距离
def checkDistances(s, distance):
"""
:type s: str
:type distance: List[int]
:rtype: bool
"""
m={}
for i,c in enumerate(s):
if c in m:
dis = i-m[c]-1
loc = ord(c)-ord("a")
if distance[loc]!=dis:
return False
else:
distance[loc] = 0
else:
m[c]=i
return True