LeetCode 每日一题 2021/6/14-2021/6/20

记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步




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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值