No.1判断矩阵经轮转后是否一致
解题思路
模拟矩阵的旋转即可。
代码展示
class Solution {
public boolean findRotation(int[][] mat, int[][] target) {
for (int i = 0; i < 4; i++) {
if (equal(mat, target)) {
return true;
}
mat = rotate(mat);
}
return false;
}
private int[][] rotate(int[][] mat) {
int[][] r = new int[mat.length][mat[0].length];
for (int i = 0, y = 0; i < mat.length; i++, y++) {
for (int j = 0, x = mat.length - 1; j < mat[0].length; j++, x--) {
r[i][j] = mat[x][y];
}
}
return r;
}
boolean equal(int[][] mat, int[][] target) {
for (int i = 0; i < mat.length; i++) {
for (int j = 0; j < mat[0].length; j++) {
if (mat[i][j] != target[i][j]) {
return false;
}
}
}
return true;
}
}
No.2 使数组元素相等的减少操作次数
解题思路
简单暴力地,从大到小依次处理每个元素即可。使用 TreeMap 的代码非常简洁,或者可以使用链表,速度更快。
代码展示
class Solution {
public int reductionOperations(int[] nums) {
TreeMap
for (var num : nums) {
count.put(num, count.getOrDefault(num, 0) + 1);
}
int result = 0;
while (count.size() > 1) {
var largest = count.pollLastEntry();
var nextLargest = count.lastEntry();
result += largest.getValue();
count.put(nextLargest.getKey(), nextLargest.getValue() + largest.getValue());
}
return result;
}
}
No.3 使二进制字符串字符交替的最少反转次数
解题思路
枚举类型 1 操作执行的次数即可。
执行完类型 1 的操作之后,需要执行的类型 2 的操作次数是固定的。
我们只需要知道奇数下标上 0 和 1 的数量、偶数下标上 0 和 1 的数量就可以计算出类型 2 的操作次数。
每执行一次类型 1 的操作,奇数下标上 0 和 1 的数量、偶数下标上 0 和 1 的数量的变化都可以 O(1) 地计算出来。
代码展示
class Solution {
public int minFlips(String s) {
char[] str = s.toCharArray();
// count[0] 表示偶数下标上 0 和 1 的数量
// count[1] 表示奇数下标上 0 和 1 的数量
int[][] count = new int[2][2];
for (int i = 0; i < str.length; i++) {
count[i % 2][str[i] - '0']++;
}
int result = Math.min(count[1][1] + count[0][0], count[1][0] + count[0][1]);
for (int i = 0; i < str.length - 1; i++) {
count[0][str[i] - '0']--;
int tmp = count[1][0];
count[1][0] = count[0][0];
count[0][0] = tmp;
tmp = count[1][1];
count[1][1] = count[0][1];
count[0][1] = tmp;
count[(str.length - 1) % 2][str[i] - '0']++;
result = Math.min(result, Math.min(count[1][1] + count[0][0], count[1][0] + count[0][1]));
}
return result;
}
}
No.4 装包裹的最小浪费空间
解题思路
二分查找。
对所有的包裹和供应商的盒子都排序,然后依次枚举每个供应商即可。
计算一个供应商的盒子的浪费空间时,从小到大使用每种盒子,每种盒子尽可能多装包裹即可,使用前缀和数组和二分查找可以快速计算结果。
代码展示
class Solution {
public int minWastedSpace(int[] packages, int[][] boxes) {
Arrays.sort(packages);
long[] preSum = new long[packages.length];
preSum[0] = packages[0];
for (int i = 1; i < preSum.length; i++) {
preSum[i] = preSum[i - 1] + packages[i];
}
long result = -1;
for (int[] box : boxes) {
Arrays.sort(box);
long t = waste(packages, preSum, box);
if (t != -1 && (result == -1 || t < result)) {
result = t;
}
}
return (int) (result % 1000000007L);
}
private long waste(int[] packages, long[] preSum, int[] boxes) {
int start = 0;
long result = 0;
for (int box : boxes) {
if (box < packages[start]) {
continue;
}
int index = binarySearch(packages, box);
// [start, index] 之间的包裹使用 box 装
result += (long) box * (index - start + 1) - preSum[index];
if (start != 0) {
result += preSum[start - 1];
}
start = index + 1;
if (start >= packages.length) {
return result;
}
}
return -1;
}
private int binarySearch(int[] arr, int target) {
int l = 0, r = arr.length - 1;
while (l + 1 < r) {
int mid = (l + r) / 2;
if (arr[mid] <= target) {
l = mid;
} else {
r = mid;
}
}
return arr[r] <= target ? r : l;
}
}