LeetCode 每日一题 2021/12/27-2022/1/2

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




12/27 825. 适龄的朋友

1.用户x不会对大于自己岁数的y发送好友请求
统计各个年龄各有多少人 存入m
将年龄从下到大排列 生成前缀和数组
统计每个年龄会加好友的区间 二分
2.因为年纪范围知道 计数排序 前缀和

def numFriendRequests1(ages):
    """
    :type ages: List[int]
    :rtype: int
    """
    from collections import defaultdict
    m = defaultdict(int)
    for age in ages:
        m[age]+=1
    ageList = list(m.keys())
    ageList.sort()
    presum = [0,m[ageList[0]]]
    
    for i in range(1,len(ageList)):
        presum.append(presum[i]+m[ageList[i]])
    ans = 0
    for loc,age in enumerate(ageList):
        num = m[age]
        minage = age*1.0/2+7 #大于minage
        if minage<age:
            ans += num*(num-1)
        l,r = 0,loc-1
        while l<=r:
            mid = (l+r)//2
            if ageList[mid]>minage:
                r = mid-1
            else:
                l = mid+1
        if l>=0 and loc>=0:
            ans += (presum[loc]-presum[l])*num
    return ans
    
def numFriendRequests(ages):
    """
    :type ages: List[int]
    :rtype: int
    """
    total = [0]*121
    for age in ages:
        total[age]+=1
    presum = [0]*121
    for i in range(1,121):
        presum[i] = presum[i-1]+total[i]
    ans = 0
    for age in range(15,121):
        if total[age]>0:
            minage = int(age/2+8)-1
            ans += total[age]*(presum[age]-presum[minage]-1)
    return ans

12/28 472. 连接词

1.要包含合成词 必须要含有三个以上的单词
合成词肯定是若干个短的词拼接而成 所以我们可以先从短的词开始分析
使用一个set来存储已经考虑过的list中较短的单词 当以后再次需要分析这个单词时可直接返回True
使用set可以减少用in查找时的耗时
超时
2.字典树
将词组从短到长排序
判断一个单词是否是连接词 在字典树中DFS

def findAllConcatenatedWordsInADict1(words):
    """
    :type words: List[str]
    :rtype: List[str]
    """
    ret = []
    if len(words)<3:
        return ret
    words.sort(key=lambda x:len(x))
    exist_dict = set()
    def check(w):
        if w in exist_dict:
            return True
        for i in range(len(w)-1,0,-1):
            if w[:i] in exist_dict and check(w[i:]):
                return True
            
        return False
   
    for w in words:
        if check(w):
            ret.append(w)
        exist_dict.add(w)
    return ret
    
def findAllConcatenatedWordsInADict(words):
    """
    :type words: List[str]
    :rtype: List[str]
    """
    trie = {}
    
    def add(word):
        node = trie
        for c in word:
            if c in node:
                node = node[c]
            else:
                node[c] = {}
                node = node[c]
        node['end']=1
    def dfs(word):
        if word=="":
            return True
        node = trie
        for i,c in enumerate(word):
            if c in node:
                tmp = node[c]
                if 'end' in tmp and dfs(word[i+1:]):
                    return True
                node = node[c]                  
            else:
                return False
    ret = []
    if len(words)<3:
        return ret
    words.sort(key=lambda x:len(x))
    for word in words:
        if word =="":
            continue
        if dfs(word):
            ret.append(word)
        else:
            add(word)
    return ret

12/29 1995. 统计特殊四元组

1.普通四重枚举
2.a+b+c=d
从后往前枚举c位置 map存储d可能的数值出现次数

def countQuadruplets1(nums):
    """
    :type nums: List[int]
    :rtype: int
    """
    n = len(nums)
    ans = 0
    for a in range(n-3):
        for b in range(a+1,n-2):
            for c in range(b+1,n-1):
                for d in range(c+1,n):
                    if nums[a]+nums[b]+nums[c]==nums[d]:
                        ans +=1
    return ans

def countQuadruplets(nums):
    """
    :type nums: List[int]
    :rtype: int
    """
    from collections import defaultdict
    n = len(nums)
    m = defaultdict(int)
    ans = 0
    for c in range(n-2,1,-1):
        m[nums[c+1]]+=1
        for a in range(c-1):
            for b in range(a+1,c):
                s = nums[a]+nums[b]+nums[c]
                if s in m:
                    ans += m[s]
    return ans

12/30 846. 一手顺子

每一组有groupSize张牌 所以hand的个数必定需要被其整除
如果无法整除必定false
map统计每种牌的张数
使用最小堆存放出现的所有牌面值
从最小堆中取出个数不为0的最小牌面
依次增大连续groupSize张
从map中将相应的牌数量减一
如果出现中途某一牌面无牌 则说明false
小优化:
如果某一牌面数量k每组数量已经大于剩余的数量
说明无法组成完整的k组 返回false
例如 每组数量为4 剩余牌8张为 1,1,1,2,2,3,3,4,
取最小值1 此时1的数量为2 3
4>8 必定无法组成三组

def isNStraightHand(hand, groupSize):
    """
    :type hand: List[int]
    :type groupSize: int
    :rtype: bool
    """
    from collections import defaultdict
    import heapq
    l = []
    heapq.heapify(l)
    n = len(hand)
    if n%groupSize!=0:
        return False
    if groupSize==1:
        return True
    m = defaultdict(int)
    for num in hand:
        m[num]+=1
        if m[num]==1:
            heapq.heappush(l,num)
            
    while n>0:
        start = l[0]
        while m[start]==0:
            heapq.heappop(l)
            start = l[0]     
        for i in range(start,start+groupSize):
            num = m[i]
            if num==0 or groupSize*num>n:
                return False
            m[i]-=1
        n-=groupSize
    return True

12/31 507. 完美数

求出Num的2次方根sqrt
从2到sqrt判断是否是num的因数 将不同的因数累加

def checkPerfectNumber(num):
    """
    :type num: int
    :rtype: bool
    """
    if num==1:
        return False
    sqrt = int(num**(1/2))+1
    s = 1
    for i in range(2,sqrt):
        if num%i==0:
            s += i
        if num//i!=i:
            s += num//i
        if s>num:
            return False
    return s==num

1/1 2022. 将一维数组转变成二维数组

判断个数是否等于m*n个
共m行 依次取n个

def construct2DArray(original, m, n):
    """
    :type original: List[int]
    :type m: int
    :type n: int
    :rtype: List[List[int]]
    """
    ans = []
    if len(original)!=m*n:
        return ans
    for i in range(m):
        ans.append(original[i*n:i*n+n])
    return ans

1/2 390. 消除游戏

每次去除一半
如果是第k轮 间隔step = 2^k
k为偶数 从左到右
此时开头位置x数值必定改变 为x+step
k为奇数 从右到左
如果个数为奇数 开头位置变为x+step
如果个数为偶数 开头位置保留

def lastRemaining(n):
    """
    :type n: int
    :rtype: int
    """
    start = 1
    step = 1
    k = 0
    num = n
    while num>1:
        if k%2==0: 
            start += step
        elif num%2==1:
            start +=step
        
        k+=1
        num >>=1
        step<<=1
    return start

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值