LeetCode 每日一题 2023/9/18-2023/9/24

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


目录

      • 9/18 337. 打家劫舍 III
      • 9/19 2560. 打家劫舍 IV
      • 9/20 LCP 06. 拿硬币
      • 9/21 2603. 收集树中金币
      • 9/22 2591. 将钱分给最多的儿童
      • 9/23
      • 9/24


9/18 337. 打家劫舍 III

对于一节node有两种情况 偷 或者 不偷
lrrob函数返回 偷这个node 和 不偷这个node 能够得到的最佳情况
如果这个点为空 那么 偷不偷的情况都是0
获得改点左右子节点的情况 lrob,lnot(偷/不偷左节点) rrob,rnot(偷/不偷右节点)
如果要偷 那么对于就不能偷他的左右子节点 得到 val+lnot+rnot
如果不偷 那么对于左右子节点可以选择偷或不偷 选最大值 max(lrob,lnot)+max(rrob,rnot)

class TreeNode(object):
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

def rob(root):
    """
    :type root: TreeNode
    :rtype: int
    """
    def lrrob(node):
        if not node:
            return 0,0
        lrob,lnot = lrrob(node.left)
        rrob,rnot = lrrob(node.right)
        
        return node.val+lnot+rnot, max(lrob,lnot)+max(rrob,rnot)
    
    return max(lrrob(root))



9/19 2560. 打家劫舍 IV

二分 偷窃能力必定在min(nums),max(nums)的区间内
对与偷窃能力m
遍历所有房子
只关心偷或者不偷 所以遇到能偷的就偷 统计能偷的数量

def minCapability(nums, k):
    """
    :type nums: List[int]
    :type k: int
    :rtype: int
    """
    l,r = min(nums),max(nums)
    while l<r:
        m = (l+r)//2
        pre,take=0,0
        for num in nums:
            if pre:
                pre=0
                continue
            if num<=m:
                take+=1
                pre=1
            if take>=k:
                break
        if take>=k:
            r = m
        else:
            l = m+1
    return l



9/20 LCP 06. 拿硬币

减少次数 每次尽量拿两枚
对于一对n个硬币 需要拿取(n+1)//2次


def minCount(coins):
    """
    :type coins: List[int]
    :rtype: int
    """
    ans = 0
    for c in coins:
        ans +=(c+1)//2
    return ans


9/21 2603. 收集树中金币

如果一个节点度数为1 即只有一个邻居 可以称作叶子节点
如果一个叶子节点没有金币 则这叶子节点可以直接去除
直至所有叶子节点都包含金币
由于可以直接收集距离为2以内的金币 所以我们只需要访问叶子节点的父节点的父节点
将所有叶子节点去除 再将新叶子节点去除 剩余的是我们必须要访问的节点
因为要回到出发点 所以每条边必定走两次

def collectTheCoins(coins, edges):
    """
    :type coins: List[int]
    :type edges: List[List[int]]
    :rtype: int
    """
    n= len(coins)
    g = [[] for _ in range(n)]
    for x,y in edges:
        g[x].append(y)
        g[y].append(x)
    deg = list(map(len,g))
    
    eg = n-1
    l = []
    for i,(d,c) in enumerate(zip(deg,coins)):
        if d==1 and c==0:
            l.append(i)
    while l:
        eg-=1
        for y in g[l.pop()]:
            deg[y]-=1
            if deg[y]==1 and coins[y]==0:
                l.append(y)
                
    for i,(d,c) in enumerate(zip(deg,coins)):
        if d==1 and c:
            l.append(i)
    eg -= len(l)
    for x in l:
        for y in g[x]:
            deg[y]-=1
            if deg[y]==1:
                eg-=1
    return max(eg*2,0)



9/22 2591. 将钱分给最多的儿童

如果钱少于儿童 则没有分配方案
先将每个儿童分配1元 然后查看还能分配出几个7元
处理特殊情况

def distMoney(money, children):
    """
    :type money: int
    :type children: int
    :rtype: int
    """
    if money<children:
        return -1
    left = money-children
    ans = min(children,left//7)
    if ans+1==children and ans*8+4==money:
        ans-=1
    if ans==children and ans*8!=money:
        ans-=1
    return ans



9/23





9/24





你可能感兴趣的:(Exercise,leetcode,算法)