记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步
目录
6/14 374. Guess Number Higher or Lower 猜数字大小
二分
def guessNumber(n):
"""
:type n: int
:rtype: int
"""
def guess(num):
if n==num:
return 0
elif n>num:
return 1
else:
return -1
l,r=1,n
while l<=r:
mid = l+(r-l)//2
ans = guess(mid)
if ans==0:
return mid
elif ans==-1:
r = mid-1
else:
l = mid+1
6/15 852. Peak Index in a Mountain Array 山脉数组的峰顶索引
1.从第二个位置开始遍历 找到arr[i-1]<arr[i] arr[i+1]<arr[i]
2.二分查找
山峰位置ans
根据题目可以知道
当i<ans arr[i]<arr[i+1]
当i>=ans arr[i]>arr[i+1]
def peakIndexInMountainArray(arr):
"""
:type arr: List[int]
:rtype: int
"""
for i in range(1,len(arr)-1):
if arr[i]>arr[i-1] and arr[i]>arr[i+1]:
return i
def peakIndexInMountainArray2(arr):
"""
:type arr: List[int]
:rtype: int
"""
l,r=0,len(arr)-1
ans = 0
while l<=r:
mid = l+(r-l)//2
if arr[mid]>arr[mid+1]:#在左边
ans = mid
r = mid-1
else:
l = mid+1
return ans
6/16 877. Stone Game 石子游戏
1.动态规划
dp[i][j] (a,b)
在i~j石子中 先手最大为a 后手最大为b
先手如果取左边那么得到 piles[i] + dp[i+1][j].b //下一次i+1为后手
取右边 piles[j] + dp[i][j-1].b //下一次j-1为后手
2.数学方法
因为是偶数 可以将石子间隔分为两组a,b
a,b,a,b,a,b 开始时必定有一头是a,另一头是b
总数为奇数 必定存在某一组sum(a)>sum(b) 或者sum(b)>sum(a)
先手的人可以选择总和大的一组 假设为sum(a)>sum(b) 选择a
剩下b,a,b,a,b 第二个人无论头尾都只能选得到b
剩下 a,b,a,b 或b,a,b,a 又轮到先手的人可以选择a
所以最后先手的人能够选择到sum(a) 必定大于后手选到的sum(b)
3.动态规划
dp[i][j] 在[i,j]之中 先手的人与后手的人能拿到的最大差值
如果i=j dp[i][i] = piles[i]
如果i>j dp[i][j] = 0
如果i<j dp[i][j] = max(piles[i]-dp[i+1][j],piles[j]-dp[i][j-1])
最后如果dp[0][len(piles)-1]>0则先手能够获胜
def stoneGame(piles):
"""
:type piles: List[int]
:rtype: bool
"""
n = len(piles)
dp=[[(0,0)]*n for _ in range(n) ]
for i in range(n):
dp[i][i]=(piles[i],0)
for l in range(2,n+1):
for i in range(n-l+1):
j = l+i-1
left = piles[i] + dp[i+1][j][1]
right = piles[j] + dp[i][j-1][1]
if left>right:
dp[i][j]=(left,dp[i+1][j][0])
else:
dp[i][j]=(right,dp[i][j-1][0])
res = dp[0][n-1]
return res[0]-res[1]
def stoneGame2(piles):
"""
:type piles: List[int]
:rtype: bool
"""
return True
def stoneGame3(piles):
"""
:type piles: List[int]
:rtype: bool
"""
n = len(piles)
dp=[[0]*n for _ in range(n) ]
for i in range(n):
dp[i][i]=piles[i]
for i in range(n-2,-1,-1):
for j in range(i+1,n):
dp[i][j] = max(piles[i]-dp[i+1][j],piles[j]-dp[i][j-1])
return dp[0][n-1]>0
6/17 65. Valid Number 有效数字
比较繁琐 列举各种可能状态及转移
0:初始状态
1.符号位
2.整数部分
3.左侧有整数的小数点
4.左侧无整数的小数点(根据前面的第二条额外规则,需要对左侧有无整数的两种小数点做区分)
5.小数部分
6.字符
7.指数部分的符号位
8.指数部分的整数部分
最后2,3,7,8四种状态满足
def isNumber(s):
"""
:type s: str
:rtype: bool
"""
states = [
{ ' ': 0, 's': 1, 'd': 2, '.': 4 }, # 0. 初始状态 后可接 空格 符号 数字 小数点
{ 'd': 2, '.': 4 } , # 1. 符号位 后可以接数字 小数点
{ 'd': 2, '.': 3, 'e': 5, ' ': 8, 'E':5 }, # 2. 数字 后可接 数字 小数点 e/E 空格
{ 'd': 3, 'e': 5, 'E':5, ' ': 8 }, # 3. 左侧有整数的小数点 后可接 数字 e/E 空格
{ 'd': 3 }, # 4. 左侧无整数的小数点 后可接数字
{ 's': 6, 'd': 7 }, # 5. e/E 后可接 数字 指数符号
{ 'd': 7 }, # 6. 指数符号 后可接 数字
{ 'd': 7, ' ': 8 }, # 7. 指数符号后数字 后可接 数字
{ ' ': 8 } # 8. 指数部分整数 后可接空格
]
p = 0 # start with state 0
for c in s:
if '0' <= c <= '9': t = 'd' # digit
elif c in "+-": t = 's' # sign
elif c in ".eE ": t = c # dot, e, blank
else: t = '?' # unknown
if t not in states[p]: return False
p = states[p][t]
return p in (2, 3, 7, 8)
6/18 483. Smallest Good Base 最小好进制
将字符串n转换为整形num
给定整数num 对于k=n-1进制 有(11)满足条件 所以最大的好进制必定是n-1进制
因为k>=2 所以最小进制为2进制 进制越大必定位数越小
最小位数为2 最大位数为2进制条件下 得到l = int(num**(1/2))+1
为了能够是k进制中的k最小 我们假设长度越长越好 及length越大越好
length 遍历[l,3] 因为length=2必定满足 为保底答案无需考虑
确定了长度length 考虑k进制 k最小为2 最大 k^(length-1)<num
长度 固定的条件下 k越大必定总和越大 单调递增 我们使用二分法查找
tmp = k^(length-1) 从大到小加 可以跳过一些计算
当ans=num 并且tmp=1 意味着已经到了最低位 则表示满足了所有数位为1的条件 返回此时的k=mid
def smallestGoodBase(n):
"""
:type n: str
:rtype: str
"""
l = 1
tmp = 2
num = int(n)
l = int(num**(1/2))+1
for length in range(l,2,-1):
left,right=2,int(num**(1/(length-1)))
while left<=right:
mid = left+(right-left)//2
ans = 0
tmp = mid**(length-1)
bigger = False
while tmp>=1:
ans += tmp
if ans == num and tmp==1:
return str(mid)
if ans>num:
bigger = True
break
tmp = tmp//mid
if bigger:
right = mid-1
continue
left = mid+1
return str(num-1)
6/19 1239. Maximum Length of a Concatenated String with Unique Characters 串联字符串的最大长度
想到类似dp的流程
最大长度为length
mem[i] 记录长度为i的可能字符串
初始mem[0]=""
从头开始遍历字符串
对于word=arr[i]
从后开始处理长度j 考虑之前j-len(word)长度的可选字符pre
这里需要遍历pre内的字符串w与当前word是否可做拼接
如果可以讲答案加入当前长度j中
最后从后遍历可以达到的最大长度j
看似dp的方法 但是在pre中又进行了一层循环 其实还是指数级的复杂度
def maxLength(arr):
"""
:type arr: List[str]
:rtype: int
"""
n = len(arr)
length = 0
for i in range(n):
length += len(arr[i])
if length>26:
length=26
break
mem = {}
for i in range(length+1):
mem[i]=[]
mem[0]=[""]
for i in range(n):
word = arr[i]
if len(word)>len(set(word)):
continue
l = len(word)
for j in range(length,l-1,-1):
pre = mem[j-l]
tmp = []
for w in pre:
if len(w)+len(word)==len(set(w+word)):
tmp.append(w+word)
mem[j].extend(tmp)
for j in range(length,-1,-1):
if len(mem[j])>0:
return j
6/20 1600. Throne Inheritance 皇位继承顺序
live记录是否存活
childs记录每个人的子嗣
获取继承顺序使用dfs深度优先 存活的放入结果中
class ThroneInheritance(object):
def __init__(self, kingName):
"""
:type kingName: str
"""
self.live = {}
self.live[kingName] = 1
self.childs = {}
self.childs[kingName] = []
self.king = kingName
def birth(self, parentName, childName):
"""
:type parentName: str
:type childName: str
:rtype: None
"""
ch = self.childs[parentName]
ch.append(childName)
self.childs[parentName] = ch
self.childs[childName] = []
self.live[childName] = 1
def death(self, name):
"""
:type name: str
:rtype: None
"""
self.live[name]=0
def getInheritanceOrder(self):
"""
:rtype: List[str]
"""
l = []
def dfs(name):
if self.live[name]==1:
l.append(name)
ch = self.childs[name]
for child in ch:
dfs(child)
dfs(self.king)
return l