给你一个 m * n
的矩阵 grid
,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。
请你统计并返回 grid
中 负数 的数目。
示例 1:
输入:grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]]
输出:8
解释:矩阵中共有 8 个负数。
class Solution {
public int countNegatives(int[][] grid) {
int rows = grid.length;
int cols = grid[0].length;
int index = cols - 1;
int ans = 0;
for(int i = 0; i < rows; i++) {
//求出满足条件的index,根据非递增性,下次只需要从此次的index处开始判断即可
while(index >= 0 && grid[i][index] < 0) {
index--;
}
ans = ans + cols - index - 1;
}
return ans;
}
}
请你实现一个「数字乘积类」ProductOfNumbers
,要求支持下述两种方法:
1. add(int num)
num
添加到当前数字列表的最后面。2. getProduct(int k)
k
个数字的乘积。k
个数字。题目数据保证:任何时候,任一连续数字序列的乘积都在 32-bit 整数范围内,不会溢出。
示例:
输入:
["ProductOfNumbers","add","add","add","add","add","getProduct","getProduct","getProduct","add","getProduct"]
[[],[3],[0],[2],[5],[4],[2],[3],[4],[8],[2]]
输出:
[null,null,null,null,null,null,20,40,0,null,32]
解释:
ProductOfNumbers productOfNumbers = new ProductOfNumbers();
productOfNumbers.add(3); // [3]
productOfNumbers.add(0); // [3,0]
productOfNumbers.add(2); // [3,0,2]
productOfNumbers.add(5); // [3,0,2,5]
productOfNumbers.add(4); // [3,0,2,5,4]
productOfNumbers.getProduct(2); // 返回 20 。最后 2 个数字的乘积是 5 * 4 = 20
productOfNumbers.getProduct(3); // 返回 40 。最后 3 个数字的乘积是 2 * 5 * 4 = 40
productOfNumbers.getProduct(4); // 返回 0 。最后 4 个数字的乘积是 0 * 2 * 5 * 4 = 0
productOfNumbers.add(8); // [3,0,2,5,4,8]
productOfNumbers.getProduct(2); // 返回 32 。最后 2 个数字的乘积是 4 * 8 = 32
这道题如果直接按照题意,使用List存取数据通过暴力求解,那么会出现超时。优化的方法是不直接存原数据,而是存储乘积。
//超时
class ProductOfNumbers {
private List list;
public ProductOfNumbers() {
list = new ArrayList<>();
}
public void add(int num) {
list.add(num);
}
public int getProduct(int k) {
int res = 1;
int len = list.size();
int index = 0;
while (index < k) {
int num = list.get(len - 1 - index);
res *= num;
index++;
}
return res;
}
}
class ProductOfNumbers {
private List list;
private int zeroIndex;
public ProductOfNumbers() {
list = new ArrayList<>();
zeroIndex = -1;
}
public void add(int num) {
//如果num为0,将其加到list中,并记录其索引位置
if (num == 0) {
list.add(num);
zeroIndex = list.size() - 1;
//如果list中没有数 或者前一个数刚好是0,那么直接加到list中
} else if (list.size() == 0 || zeroIndex == list.size() - 1) {
list.add(num);
} else {//否则,记录其累乘结果
list.add(num * list.get(list.size() - 1));
}
}
//eg: add:2, 3, 4, 5 -> list:[2, 6, 24, 120]。getProduct(2) = 120 / 6 = 20;
public int getProduct(int k) {
int size = list.size();
//如果k个数中包含0,直接返回0
if (size - k <= zeroIndex) {
return 0;
}
//如果k + 1个数刚好是0,分母不能为0,不能进行除法运算,直接返回即可
if (size - k - 1 == zeroIndex) {
return list.get(size - 1);
}
return list.get(size - 1) / list.get(size - k - 1);
}
}
给你一个数组 events,其中 events[i] = [startDayi, endDayi] ,表示会议 i 开始于 startDayi ,结束于 endDayi 。
你可以在满足 startDayi <= d <= endDayi 中的任意一天 d 参加会议 i 。注意,一天只能参加一个会议。
请你返回你可以参加的 最大 会议数目。
示例 1:
输入:events = [[1,2],[2,3],[3,4]]
输出:3
解释:你可以参加所有的三个会议。
安排会议的一种方案如上图。
第 1 天参加第一个会议。
第 2 天参加第二个会议。
第 3 天参加第三个会议。
这道题考察的是贪心法。具体的策略是哪个会结束得早,就先参加哪一个。
public class Solution {
//方法1:O(n^2)
public int maxEvents(int[][] events) {
Arrays.sort(events, (o1, o2) -> o1[1] - o2[1]); //按照结束时间进行排序
Set set = new HashSet<>();
for (int[] event : events) {
int s = event[0];
int e = event[1];
for (int i = s; i <=e; i++) {
if (!set.contains(i)) { //寻找不冲突的天参加
set.add(i);
break; //跳出循环
}
}
}
return set.size();
}
//方法2:小顶堆(优先队列)优化 O(nlogn)
public int maxEvents1(int[][] events) {
Arrays.sort(events, (o1, o2) -> o1[0] - o2[0]);
PriorityQueue pq = new PriorityQueue<>();
//结果、开始时间、events下标、有多少组数据
int res = 0, start = 1, i = 0, n = events.length;
while (i < n || !pq.isEmpty()) {
//将start相同的会议都放进堆里
while (i < n && events[i][0] == start) {
pq.offer(events[i++][1]);
}
//pop掉当前天数之前的
while (!pq.isEmpty() && pq.peek() < start) {
pq.poll();
}
//顶上的要参加的
if (!pq.isEmpty()) {
pq.poll();
res++;
}
start++;
}
return res;
}
}
给你一个整数数组 target 。一开始,你有一个数组 A ,它的所有元素均为 1 ,你可以执行以下操作:
如果能从 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] 完成
解题关键:倒推当前数组中最大元素的位置上它的上一个值是多少。这里我们采用逆推法。
class Solution {
//思路:倒推[5,8]==>[5,3]==>[2,3]==>[2,1]==>[1,1][5,8]==>[5,3]==>[2,3]==>[2,1]==>[1,1]
public boolean isPossible(int[] target) {
PriorityQueue pq = new PriorityQueue<>(Collections.reverseOrder());
int sum = 0;
for (int i = 0; i < target.length; i++) {
pq.add(target[i]);
sum += target[i];
}
while (sum != target.length) { //不全是1
int cur = pq.poll();
int rest = sum - cur;
int pre = cur - rest;
if (pre >= cur || pre < 1) {
return false;
}
sum = cur;
pq.offer(pre);
}
return true;
}
}