2021-01-24 第 225 场周赛
1736. 替换隐藏数字得到的最晚时间
思路:只需要枚举时间,然后看是否匹配,匹配的时间里面取最大的就可以了。
class Solution {
public boolean check(char[] a, char[] b) {
for(int i = 0;i < a.length;i++) {
if(a[i] == '?' || a[i] == ':') continue;
else if(a[i] != b[i]){
return false;
}
}
return true;
}
public String maximumTime(String time) {
char[] s = time.toCharArray();
int n = s.length;
String res = "";
for(int h = 0;h <= 23;h++) {
for(int m = 0;m < 60;m++) {
String hour = h >= 10 ? "" + h : "0" + h;
String minute = m >= 10 ? "" + m : "0" + m;
String curTime = hour + ":" + minute;
if(check(time.toCharArray(), curTime.toCharArray())) {
res = curTime;
}
}
}
return res;
}
}
1737. 满足三条件之一需改变的最少字符数
思路:这道题一开始的时候WA了一次,以为是简单的枚举三种情况就好了,其实并不是。需要的是枚举以下情况:
- a以字母
α
最大, b 以字母β
最小,α < β
,此时需要修改的个数 - a以字母
α
最小, b 以字母β
最大,α > β
,此时需要修改的个数 - a 和 b 都只含有字母
α
时,需要修改的次数
a以字母α
最大需要修改的个数,可以通过前缀和的方式求出。同理, b 以字母β
最小需要修改的个数,也可以通过前缀和的方式求出。所以这题就可以做出来了。
class Solution {
public int cal(int[] cntA, int[] sumA, int[] cntB, int[] sumB) {
int res = (int) (1e6);
for(int i = 0;i < 25;i++) {
int changeA = sumA[25] - sumA[i];
for(int j = i+1;j <= 25;j++) {
int changeB = sumB[j-1];
res = Math.min(res, changeA + changeB);
}
}
return res;
}
public int minCharacters(String _a, String _b) {
char[] a = _a.toCharArray(), b = _b.toCharArray();
int A = a.length, B = b.length, res = (int) (1e6);
int[] cntA = new int[26], cntB = new int[26];
int[] sumA = new int[26], sumB = new int[26];
for(char ch : a) cntA[ch-'a']++;
for(char ch : b) cntB[ch-'a']++;
for(int i = 0;i < 26;i++) {
sumA[i] = cntA[i]; sumB[i] = cntB[i];
if(i > 0) {
sumA[i] += sumA[i-1];
sumB[i] += sumB[i-1];
}
}
res = Math.min(res, cal(cntA, sumA, cntB, sumB));
res = Math.min(res, cal(cntB, sumB, cntA, sumA));
for(int i = 0;i < 26;i++) {
res = Math.min(res, A + B - cntA[i] - cntB[i]);
}
return res;
}
}
1738. 找出第 K 大的异或坐标值
思路:就是个二维前缀和的模板,来计算二维前缀异或值。然后把它们放到一个list里面,取出第k大的值即可。
class Solution {
public int kthLargestValue(int[][] matrix, int k) {
int rows = matrix.length, cols = matrix[0].length;
int[][] a = new int[rows][cols];
List<Integer> list = new ArrayList<>();
for(int i = 0;i < rows;i++) {
int v = 0;
for(int j = 0;j < cols;j++) {
v = v ^ matrix[i][j];
if(i > 0) {
a[i][j] = v ^ a[i-1][j];
} else {
a[i][j] = v;
}
list.add(a[i][j]);
}
}
Collections.sort(list, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});
return list.get(k-1);
}
}
1739. 放置盒子
有一个立方体房间,其长度、宽度和高度都等于 n 个单位。请你在房间里放置 n 个盒子,每个盒子都是一个单位边长的立方体。放置规则如下:
- 你可以把盒子放在地板上的任何地方。
- 如果盒子 x 需要放置在盒子 y 的顶部,那么盒子 y 竖直的四个侧面都 必须 与另一个盒子或墙相邻。
给你一个整数 n ,返回接触地面的盒子的 最少 可能数量。
思路:其实就是一道数学题,当时比赛过程中觉得太麻烦没仔细推。赛后看题解发现规律其实也还蛮简单的
底下盒子数 | 总盒子数 | 盒子总量增加 |
---|---|---|
0 | 0 | 0 |
1 | 1 | 1 |
2 | 2 | 1 |
3 | 4 | 2 |
4 | 5 | 1 |
5 | 7 | 2 |
6 | 10 | 3 |
7 | 11 | 1 |
底下的盒子每增加一个,可以放置的总盒子增加数呈现规律性:1,1,2,1,2,3,1,2,3,4……。
那么这样代码写起来就简单了。。。
class Solution {
public int minimumBoxes(int n) {
int sum = 0, bottom = 0;
for(int height = 1; sum < n;height++) {
// i表示盒子总量增加数
for(int i = 1;i <= height && sum < n;i++) {
bottom++;
sum += i;
}
}
return bottom;
}
}
更快速的方法,我们可以先不停的加盒子数,直到总数超过给定n的大小,再开始移除。移除的时候,如果当前高度是height,每想要减小一个底下盒子数,需要拿掉的盒子数为:height,height-1,height-2……
class Solution {
public int minimumBoxes(int n) {
int sum = 0, bottom = 0,height = 1;
for(height = 0; sum < n;) {
height++;
bottom = height * (height + 1) / 2;
sum += bottom;
}
for(int i = height;i > 0 && sum >= n;i--) {
sum -= i;
bottom--;
}
// 这时候盒子总数已经比n小,所以上次操作是不能进行的,需要加回来
return bottom+1;
}
}