1、每行每列的数都是都是递减的,求负数有多少个
O(M+N):
public int countNegatives(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int x = m - 1;
int y = 0;
int res = 0;
while (x >= 0) {
while (y < n && grid[x][y] >= 0) y++;
res += n - y;
x--;
}
return res;
}
2、前缀积,注意到0的情况,需要分段处理
int n;
List<Integer> list;
List<Integer> zero;
public ProductOfNumbers() {
n = 0;
list = new ArrayList<>();
list.add(1);
zero = new ArrayList<>();
}
public void add(int num) {
n++;
if (num == 0) {
zero.add(n);
list.add(0);
} else {
int last = list.get(n - 1);
if (last == 0) list.add(num);
else list.add(last * num);
}
}
public int getProduct(int k) {
int pre = n - k;
for (int x : zero) {
if (x > pre) return 0;
}
int la = list.get(n - k);
if (la == 0) return list.get(n);
else return list.get(n) / list.get(n - k);
}
3、每个作业需要一天来完成,给个每个作业可以在[start, end]内任意一天内去做,每天只能做一个作业,求最多能做多少个作业。
sol:贪心的思想:先按照开始时间排序,那么第一天我先做哪个作业呢?肯定是要先做截止日期最近的任务。
public int maxEvents(int[][] A) {
int res = 0;
Arrays.sort(A, Comparator.comparingInt(o -> o[0]));
//维护任务的结束时间
PriorityQueue<Integer> pq = new PriorityQueue<>();
//枚举任务的开始时间
int i = 0;
for (int d = 1; d <= 100000; d++) {
//把第i天开始的任务的结束时间放到优先队列,优先队列按照任务的结束时间从小到大排序
while (i < A.length && A[i][0] == d) pq.add(A[i++][1]);
//抛掉已经无法完成的任务(这些任务的结束时间在d之前
while (!pq.isEmpty() && pq.peek() < d) pq.poll();
//完成截止日期最短的任务
if (!pq.isEmpty()) {
res++;
pq.poll();
}
if (res == A.length) break;
}
return res;
}
4、给一个target数组。还给了一个起始数组,初始化全部是1,每次可以把数组中的一个数替换为当前数组的和,问是否可以变成目标数组
sol:我们反过来考虑,假设最后达到了目标数组,那么变化的是最大的那个数,那么用最大的数减去其他数的和就是原数组,
举例说明:
比如1 3 5 变成了 3 5 9,那么根据 3 5 9我们知道最大值9是最后一步得到的,用9-8=1就是上次这个位置的数,也就是3 5 1
一直这样看最后能否得到一个全部是1的数组即可。
注意到数字的可能达到1e9,因此对于像1 100这样的用例,按照我们上面的做法,会变为1 99, 1 98 , 1 97 ... 1,1
这样,但是我们可以对此优化,发现一次处理得到的数依然比其他所有数的和还要打的话,要再做一次,这样的话,对于1 100这样的用例,我们可以一次减少1 1
具体看代码吧:
public boolean isPossible(int[] target) {
Arrays.sort(target);
PriorityQueue<Integer> pq = new PriorityQueue<>((o1, o2) -> Integer.compare(o2, o1));
int len = target.length;
long s = 0;
for (int i = 0; i < len; i++){
s += target[i];
pq.add(target[i]);
}
while (!pq.isEmpty()) {
int maxNum = pq.poll();
if (maxNum == 1) return true;
//下一个数
if (maxNum - (s - maxNum) < 0) return false;
//能减多少次
int cishu = (int) (maxNum / (s - maxNum));
long nxt = maxNum - cishu * (s - maxNum);
s = s - maxNum + nxt;
pq.add((int) nxt);
}
//cannot reach here
return true;
}