2022-01-14 每日打卡:难题精刷

2022-01-14 每日打卡:难题精刷

写在前面

“这些事儿在熟练之后,也许就像喝口水一样平淡,但却能给初学者带来巨大的快乐,我一直觉得,能否始终保持如初学者般的热情、专注,决定了在做某件事时能走多远,能做多好。” 该系列文章由python编写,所刷题目共三个来源:之前没做出来的 ;Leetcode中等,困难难度题目; 周赛题目;某个专题的经典题目,所有代码已AC。每日1-3道,随缘剖析,希望风雨无阻,作为勉励自己坚持刷题的记录。

扫雷

在这里插入图片描述
只要确定两个之后,后面的都可以排下去,检查是否满足最后没有剩余雷即可。枚举第一个雷的可能性。

	num = input()
	a = input().split(" ")
	a.pop()
	a = [int(x) for x in a]
	
	ans,tmp = 0, 0
	def check(fisrt, second):
	    for _ in range(1, len(a)):
	        tmp = fisrt+second
	        fisrt, second = second, a[_]-tmp
	        if not (second==0 or second==1):
	            break
	    if second==0:
	        return True
	    return False
	a0 = a[0]
	if a0==1:
	    fisrt, second = 1,0
	    if check(fisrt,second):
	        ans+=1
	    fisrt, second = 0, 1
	    if check(fisrt,second):
	        ans+=1
	elif a0==2: 
	    fisrt, second = 1, 1
	    if check(fisrt,second):
	        ans+=1
	else:
	    fisrt, second =0,0
	    if check(fisrt, second):
	        ans+=1
	print(ans)

积木大赛

在这里插入图片描述
起初想用类似拓扑的方法,每次从中筛出为0的数,后来发现了一种更为巧妙的思路,先放代码:

	maxx, width, ans = 0, eval(input()), 0
	a = [eval(_) for _ in input().split(" ")]
	
	for _ in a:
	    if _>maxx:
	        ans += (_-maxx)
	    maxx = _
	
	print(ans)

对于从maxx开始检查,比它高的一定至少有一次安放,所以高的只需要加上差值即可。
比它低的无须加,原因在于最开始我们指定maxx为0,比它低的一定有共同部分被加过。

304. 二维区域和检索 - 矩阵不可变

在这里插入图片描述

  • 一维前缀和:
class NumMatrix:

    def __init__(self, matrix: List[List[int]]):
        m, n = len(matrix), (len(matrix[0]) if matrix else 0)
        self.sums = [[0] * (n + 1) for _ in range(m)]
        _sums = self.sums

        for i in range(m):
            for j in range(n):
                _sums[i][j + 1] = _sums[i][j] + matrix[i][j]

    def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
        _sums = self.sums

        total = sum(_sums[i][col2 + 1] - _sums[i][col1] for i in range(row1, row2 + 1))
        return total

  • 二维前缀和:公式如下所示
    • 前缀和的计算公式:
      在这里插入图片描述
    • 面积和的计算公式:
      在这里插入图片描述
class NumMatrix:

    def __init__(self, matrix: List[List[int]]):
        m, n = len(matrix), (len(matrix[0]) if matrix else 0)
        self.sums = [[0] * (n + 1) for _ in range(m + 1)]
        _sums = self.sums

        for i in range(m):
            for j in range(n):
                _sums[i + 1][j + 1] = _sums[i][j + 1] + _sums[i + 1][j] - _sums[i][j] + matrix[i][j]

    def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
        _sums = self.sums

        return _sums[row2 + 1][col2 + 1] - _sums[row1][col2 + 1] - _sums[row2 + 1][col1] + _sums[row1][col1]


2132. 用邮票贴满网格图

在这里插入图片描述
这是力扣双周赛69场最后的困难题,当时想用枚举做,把自己枚举晕了…然后解析如下:
在这里插入图片描述
这个题中会用到三个矩阵:

  • 二维前缀和:表示累计。用于快速检查矩阵结果,即前缀和为0时不覆盖格子。
  • 二维差分:表示差值。用于快速更新矩阵加减,对每个可以放置邮票的地方都放置邮票。
  • 二维计数:表示个数。用于最后的验证,遍历放置后,如果还填不满则不成立。二维计数矩阵是可以由前缀和矩阵or差分矩阵推导出来的。
class Solution:
class Solution:
    def possibleToStamp(self, grid: List[List[int]], stampHeight: int, stampWidth: int) -> bool:
        m, n = len(grid), len(grid[0])
        sum = [[0] * (n + 1) for _ in range(m + 1)]
        diff = [[0] * (n + 1) for _ in range(m + 1)]
        # grid 的二维前缀矩阵
        for i, row in enumerate(grid):
            for j, v in enumerate(row):
                sum[i + 1][j + 1] = sum[i + 1][j] + sum[i][j + 1] - sum[i][j] + v

        for i, row in enumerate(grid):
            for j, v in enumerate(row):
                if v == 0:
                    # 注意这是矩形右下角横纵坐标都 +1 后的位置
                    x, y = i + stampHeight, j + stampWidth
                    # 检查可以放下邮票,更新二维差分 
                    if x <= m and y <= n and sum[x][y] - sum[x][j] - sum[i][y] + sum[i][j] == 0:
                        diff[i][j] += 1
                        diff[i][y] -= 1
                        diff[x][j] -= 1
                        diff[x][y] += 1  

        # 还原二维差分矩阵对应的计数矩阵,就是更新后的结果
        # 这里用滚动数组实现
        cnt, pre = [0] * (n + 1), [0] * (n + 1)
        for i, row in enumerate(grid):
            for j, v in enumerate(row):
                cnt[j + 1] = cnt[j] + pre[j + 1] - pre[j] + diff[i][j]
                if cnt[j + 1] == 0 and v == 0:
                    return False
            cnt, pre = pre, cnt
        return True

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值