链接:LeetCode
[Leetcode]5340. 统计有序矩阵中的负数
给一个(m * n)的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。
请你统计并返回 grid 中 负数 的数目。
示例 1:
输入:grid = ([[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]])
输出:8
解释:矩阵中共有 8 个负数。
因为是非递增顺序排列,所以最小的数在矩阵左下角,每次跟矩阵左下角进行比较即可,时间复杂度(O(m+n))。
class Solution:
def countNegatives(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
r, c, cnt = m - 1, 0, 0
while r >= 0 and c < n:
if grid[r][c] < 0:
cnt += n - c
r -= 1
else:
c += 1
return cnt
[Leetcode]5341. 最后 K 个数的乘积
实现一个「数字乘积类」ProductOfNumbers,要求支持下述两种方法:
1. add(int num)
将数字 num 添加到当前数字列表的最后面。
2. getProduct(int k)
返回当前数字列表中,最后(k)个数字的乘积。
你可以假设当前列表中始终 至少 包含(k)个数字。
题目数据保证:任何时候,任一连续数字序列的乘积都在 32-bit 整数范围内,不会溢出。
类似于在数组中寻找K个数的和,我们可以先求出从开始位到每一位的总积,然后用总积除以从开始位到最后k-1位的总积,即可。但有一种特殊情况就是出现了0,当出现0的时候,后面每一个位置的总积都是0,无法用这种方法,这个时候我们将数组清零即可,当判断最后(k)个数字的乘积,如果数组个数小于K个,则说明之前是出现了0。这也是最简单的一种判别方法了。
class ProductOfNumbers:
def __init__(self):
self.products = []
def add(self, num: int) -> None:
if not num:
self.products = []
else:
if not self.products:
self.products.append(num)
else:
self.products.append(self.products[-1]*num)
def getProduct(self, k: int) -> int:
if k>len(self.products):
return 0
if k == len(self.products):
return self.products[-1]
n = len(self.products)
return self.products[-1]//self.products[n-k-1]
[Leetcode]5342. 最多可以参加的会议数目
给你一个数组 events,其中(events[i] = [startDayi, endDayi]),表示会议(i)开始于 (startDay_i),结束于(endDay_i)。
你可以在满足(startDay_i <= d <= endDay_i)中的任意一天(d)参加会议(i)。注意,一天只能参加一个会议。
请你返回你可以参加的最大会议数目。
输入:events = ([[1,2],[2,3],[3,4]])
输出:3
解释:你可以参加所有的三个会议。
安排会议的一种方案如上图。
第 1 天参加第一个会议。
第 2 天参加第二个会议。
第 3 天参加第三个会议。
这实际是一道考验贪婪法求解的题目。首先,我们很明确一个事情,就是给定一个event,如果我要参加其会议,当然是越早越好,这可以给后面的会议让出时间,所以选择不是问题,而问题在于排序。怎么明确,先参加哪个会议呢?
答案是(endDay_i)最小的那个。假设我们先将(endDay_i)排序,那么对于(endDay_i)最小的那个会议,我选择其(startDay_i)一天参加会议不会影响后面的会议的选择。想想反证法:假设我们占用了任何一个其他会议(event_j)的时间,最佳的选择应该是会议(event_j)在(startDay_i),而会议(event_i)在其他时间,那么这种情况对于(event_i)其(endDay_i<=endDay_j),所以无论会议
(event_i)选在哪个时间,(event_j)也可以选择那个时间。这说明,我们选任何一个其他会议(event_j)的情况,都能在先选(event_i)的策略中找到一样的,即选择(endDay_i)最小的那个会议先参加,其最大会议数目大于等于先参加其他任何会议。
接下来,我们用一个集合set来存储我们参加会议的时间即可。
class Solution:
def maxEvents(self, events: List[List[int]]) -> int:
if not events or not events[0]:
return 0
events = sorted(events, key=lambda x: x[1])
visited = set()
for s, e in events:
for t in range(s, e+1):
if t not in visited:
visited.add(t)
break
return len(visited)
[Leetcode]5343. 多次求和构造目标数组
给你一个整数数组 target 。一开始,你有一个数组 A ,它的所有元素均为 1 ,你可以执行以下操作:
令 x 为你数组里所有元素的和
选择满足 0 <= i < target.size 的任意下标 i ,并让 A 数组里下标为 i 处的值为 x 。
你可以重复该过程任意次
如果能从 A 开始构造出目标数组 target ,请你返回 True ,否则返回 False 。
示例 1:
输入:(target = [9,3,5])
输出:true
解释:从 ([1, 1, 1]) 开始
([1, 1, 1]), 和为 3 ,选择下标 1
([1, 3, 1]), 和为 5, 选择下标 2
([1, 3, 5]), 和为 9, 选择下标 0
([9, 3, 5]) 完成
这是一道贪婪+堆的题目。
首先,我们先看看例子,对于(target = [9,3,5]),虽然我们不知道([1, 1, 1])怎么开始求和构成成如此数组,但显然最后一层构造所替换掉的元素,必然是数组中的最大值,也就是9。接下来,我们要逆向思考,9之前替换的数字是什么呢?根据规则,我们知道,9,即x等于3加5加本来的元素,所以本来的元素是(1),那么此时,(target = [1,3,5]),接下来,我们再按照这种方式求最大值原来的值是多少,并进行替换即可。
这里比较高效的方法是大顶堆,在每次进行(pop)的时候,提取出数组最大值,然后把替换前的数(push)进去,这里有两个技巧:
1.因为是大顶堆,python默认的 heapq是小顶堆,所以我们放入的时候取负数即可。
2.如果我们计算出的替换出的数<1,那么说明这是无法从([1, 1, 1]) 开始构造而成的,返回False即可。
class Solution:
def isPossible(self, target: List[int]) -> bool:
total=sum(target)
target=[-x for x in target]
heapq.heapify(target)
while target:
curMax=-heapq.heappop(target)
if curMax==1:
return len(target)==0 or max(target)==-1
total-=curMax
next_sum=curMax-total
total+=next_sum
if next_sum < 1:
return False
heapq.heappush(target,-next_sum)