LeetCode 每日一题 2021/5/24-2021/5/30

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




5/24 664. Strange Printer 奇怪的打印机

动态规划
如果只有一个字符a 那么只需打印一次
如果字符串abcdefa头尾相同 那么与去掉尾部的情况abcdef是相同的
起始位置i从后向前遍历
i往前移动一步 意味着在开头位置增加一个字符
最坏的情况就是前一种情况下多打印一次
此时再判断中间位置k的值 如果与i相同判断是否可以缩小

def strangePrinter(s):
    """
    :type s: str
    :rtype: int
    """
    n = len(s)
    dp = [[float('inf')]*n for _ in range(n)]
    for i in range(n-1,-1,-1):
        dp[i][i]=1
        for j in range(i+1,n):
            if s[i]==s[j]:
                dp[i][j] =dp[i][j-1]
                continue
            dp[i][j] = dp[i+1][j]+1 #多印一次
            for k in range(i+1,j+1):
                if s[i]==s[k]:
                    if k<j:
                        dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j])
                    else:
                        dp[i][j] = min(dp[i][j],dp[i][k-1])
    return dp[0][n-1]

5/25 1787. Make the XOR of All Segments Equal to Zero 使所有区间的异或结果为零

num[i]num[i+k-1]=0
num[i+1]num[i+k]=0
两式异或 得到num[i]^num[i+k]=0 说明每隔k个数 必定相等
将所有间隔k的数分为1组 一共k组
得到每一组内出现最多的数(众数)的次数 zs 总数个数-众数次数总和 及将每组数变为一致(众数)需要改变的最少次数
每一组数改变为每组众数的值 此时有可能无法满足 k组数异或值为0
zs[0]zs[1]…^zs[k-1] = 0
需要牺牲一组 zs[i]
将这一组全部变为能够使k组数异或为0的值 zs[i] = zs[0]zs[i-1]zs[i+1]…^zs[k-1]
keys 记录每一组内每个数出现的次数
考虑将该组从众数变为key时 是否能够减少次数

def minChanges(nums, k):
    """
    :type nums: List[int]
    :type k: int
    :rtype: int
    """
    from collections import Counter
    from collections import defaultdict
    n = len(nums)
    count = defaultdict(Counter)
    for i in range(k):
        for j in range(i,n,k):
            count[i][nums[j]]+=1
    
    #每组数中的众数 数量
    zs = [count[i].most_common(1)[0][1] for i in range(k)]
    ans = n - sum(zs) #将每组数变为当前组的众数 需要改变的个数
    keys = [sorted(count[i].keys(),key=lambda x:-count[i][x]) for i in range(k)]
    
    #为了使得k个数异或为0 需要牺牲其中一组数
    def dfs(idx,curr):
        if idx==k and curr==0:
            return 0
        elif idx==k:
            return float('inf')
        res = zs[idx]
        for key in keys[idx]:
            if zs[idx]-count[idx][key] >= res:
                continue
            res = min(res,dfs(idx+1,curr^key)-count[idx][key]+zs[idx])
        return res
    return ans+dfs(0,0)

5/26 1190. Reverse Substrings Between Each Pair of Parentheses 反转每对括号间的子串


遇到’(’ 将当前num放入栈中,重新记录后续的数值num
遇到’)’ 将记录的字符串num翻转 并从栈中取出一个连接到头部

def reverseParentheses(s):
    """
    :type s: str
    :rtype: str
    """
    ans = []
    num=''
    for i in s:
        if i=='(':
            ans.append(num)
            num=''
        elif i==')':
            a = ans.pop()
            num = num[::-1]
            num = a+num
        else:
            num+=i
    return num

5/27 461. Hamming Distance 汉明距离

计算两数异或之后 二进制表示有多少个1
数值s与s-1相与 能够消除最低位一个1
100100 & 100011 = 100000

def hammingDistance(x, y):
    """
    :type x: int
    :type y: int
    :rtype: int
    """
    s = x^y
    ret = 0
    while s>0:
        ret += 1
        s&=(s-1)
    return ret

5/28 477. Total Hamming Distance 汉明距离总和

1.根据461计算两个数之间的汉明距离
枚举 超时
2.遍历每一个数
记录这个数每一个维度包含的0,1数量
3.遍历每一个维度 最多2^30
记录每一个数在该维度包含0,1的数量
“”"

def totalHammingDistance(nums):
    """
    :type nums: List[int]
    :rtype: int
    """
    def hamming(x,y):
        s = x^y
        ret = 0
        while s>0:
            ret += 1
            s&=(s-1)
        return ret
    ret = 0
    for i in range(len(nums)-1):
        for j in range(i+1,len(nums)):
           ret+=hamming(nums[i],nums[j]) 
    return ret

def totalHammingDistance2(nums):
    """
    :type nums: List[int]
    :rtype: int
    """
    n=len(nums)
    dim = {}
    for num in nums:
        loc =0
        while num>0:
            dim[loc] = dim.get(loc,0)+(num&1)
            loc+=1
            num>>=1
    ret = 0
    for v in dim.values():
        ret += (n-v)*v
    return ret
        
def totalHammingDistance3(nums):
    """
    :type nums: List[int]
    :rtype: int
    """
    n = len(nums)
    ret = 0
    for i in range(30):
        s=0
        for num in nums:
            s += (num>>i)&1
        ret += s*(n-s)
    return ret

5/29 1074. Number of Submatrices That Sum to Target 元素和为目标值的子矩阵数量

1.使用矩阵s 记录从原点到i,j的总和
左上角[x,y]到右下角[i,j]区域内的元素和:[i,j]-[x-1,j]-[i,y-1[+[x-1,y-1]
超时
2.设置上下边界 将每一列的数相加 从二维转化为一维

0,1,0 <-上边界
1,1,1 <-下边界
0,1,0
如果上下边界为0,1
可将这两行每一列相加 得到1,2,1
转化为在一位数组内 [i:j]的和为target

def numSubmatrixSumTarget(matrix, target):
    """
    :type matrix: List[List[int]]
    :type target: int
    :rtype: int
    """
    n = len(matrix)
    m = len(matrix[0])
    s = [[0]*(m+1) for _ in range(n+1)]
    for i in range(n):
        for j in range(m):
            s[i+1][j+1] = s[i][j+1]+s[i+1][j]-s[i][j]+matrix[i][j]

    ret = 0
    for i in range(1,n+1):
        for j in range(1,m+1):
            for x in range(1,i+1):
                for y in range(1,j+1):
                    ans = s[i][j]-s[x-1][j]-s[i][y-1]+s[x-1][y-1]
                    if ans == target:
                        #print(i,j,x,y)
                        ret+=1
    return (ret)

def numSubmatrixSumTarget2(matrix, target):
    """
    :type matrix: List[List[int]]
    :type target: int
    :rtype: int
    """
    n = len(matrix)
    m = len(matrix[0])
    ret = 0
    
    #在一维数组内寻找[i,j]和为target
    def find(nums):
        mem={}
        mem[0]=1
        pre = 0
        count = 0
        for c in nums:
            pre +=c
            if pre-target in mem:
                count += mem[pre-target]
            mem[pre] = mem.get(pre,0)+1
        return count
        
    #上边界
    for i in range(n):
        s = [0]*m
        #下边界
        for j in range(i,n):
            for c in range(m):
                #每一列相加
                s[c] +=matrix[j][c]
            ret += find(s)
    return ret

5/30 231. Power of Two 2 的幂

1.排除负数
转换为二进制 如果是2的幂 必定只有第一位为1 其它为0
2.去除最低位1的方法 n与n-1相与
如果只有1个1 那么n&(n-1)==0
不为零说明不止一个1

def isPowerOfTwo(n):
    """
    :type n: int
    :rtype: bool
    """
    if n<=0:
        return False
    s = bin(n)[2:]
    return True if s.count('1')==1 else False

def isPowerOfTwo2(n):
    """
    :type n: int
    :rtype: bool
    """
    if n<=0:
        return False
    return n&(n-1)==0

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值