modify code

master
algorithmzuo 3 years ago
parent d3e5e2f9ad
commit b8f21fed8d

@ -46,6 +46,56 @@ public class Code04_SumEvenSubNumber {
return even[n][k]; return even[n][k];
} }
// 补充一个更数学的方法
// 统计arr中的偶数个数、奇数个数
// k个数加起来是偶数的方案 :
// 1) 奇数选0个偶数选k个
// 2) 奇数选2个偶数选k-2个
// 3) 奇数选4个偶数选k-4个
// ...
public static int number3(int[] arr, int k) {
if (arr == null || arr.length == 0 || k < 1 || k > arr.length) {
return 0;
}
int even = 0;
int odd = 0;
for (int num : arr) {
if ((num & 1) == 0) {
even++;
} else {
odd++;
}
}
int ans = 0;
for (int pick = 0, rest = k; pick <= k; pick += 2, rest -= 2) {
ans += c(pick, odd) * c(rest, even);
}
return ans;
}
public static long c(long m, long n) {
if (m > n) {
return 0;
}
if (m == 0 && m == n) {
return 1;
}
long up = 1;
long down = 1;
for (long i = m + 1, j = 1; i <= n; i++, j++) {
up *= i;
down *= j;
long gcd = gcd(up, down);
up /= gcd;
down /= gcd;
}
return up;
}
public static long gcd(long m, long n) {
return n == 0 ? m : gcd(n, m % n);
}
// 为了测试 // 为了测试
public static int[] randomArray(int n, int v) { public static int[] randomArray(int n, int v) {
int[] ans = new int[n]; int[] ans = new int[n];
@ -67,7 +117,8 @@ public class Code04_SumEvenSubNumber {
int k = (int) (Math.random() * n) + 1; int k = (int) (Math.random() * n) + 1;
int ans1 = number1(arr, k); int ans1 = number1(arr, k);
int ans2 = number2(arr, k); int ans2 = number2(arr, k);
if (ans1 != ans2) { int ans3 = number3(arr, k);
if (ans1 != ans2 || ans1 != ans3) {
System.out.println("出错了"); System.out.println("出错了");
for (int num : arr) { for (int num : arr) {
System.out.print(num + " "); System.out.print(num + " ");
@ -76,6 +127,7 @@ public class Code04_SumEvenSubNumber {
System.out.println(k); System.out.println(k);
System.out.println(ans1); System.out.println(ans1);
System.out.println(ans2); System.out.println(ans2);
System.out.println(ans3);
} }
} }
System.out.println("测试结束"); System.out.println("测试结束");

@ -0,0 +1,176 @@
package class_2022_09_4_week;
// 来自学员问题
// 智能机器人要坐专用电梯把货物送到指定地点
// 整栋楼只有一部电梯,并且由于容量限制智能机器人只能放下一件货物
// 给定K个货物每个货物都有所在楼层(from)和目的楼层(to)
// 假设电梯速度恒定为1相邻两个楼层之间的距离为1
// 例如电梯从10层去往19层的时间为9
// 机器人装卸货物的时间极快不计入
// 电梯初始地点为第1层机器人初始地点也是第1层
// 并且在运送完所有货物之后机器人和电梯都要回到1层
// 返回智能机器人用电梯将每个物品都送去目标楼层的最快时间
// 注意:如果智能机器人选了一件物品,则必须把这个物品送完,不能中途丢下
// 输入描述:
// 正数k表示货物数量1 <= k <= 16
// from、to数组长度都是k1 <= from[i]、to[i] <= 10000
// from[i]表示i号货物所在的楼层
// to[i]表示i号货物要去往的楼层
// 返回最快的时间
public class Code01_RobotDeliverGoods {
// 0 1 2
// from = {3, 6, 2}
// to = {7, 9, 1}
// from[i] : 第i件货在哪个楼层拿货固定
// to[i] : 第i件货去哪个楼层送货固定
// k : 一共有几件货,固定
// status : 00110110
// last : 在送过的货里,最后送的是第几号货物
// 返回值: 送完的货由status代表
// 而且last是送完的货里的最后一件后续所有没送过的货都送完
// 最后回到第一层,返回最小耗时
// k = 7
// status = 01111111
// 0000000000001
// 0000010000000 -1
// 0000001111111
public static int zuo(int status, int last, int k, int[] from, int[] to) {
if (status == (1 << k) - 1) { // 所有货送完了回到1层去了
return to[last] - 1;
} else { // 不是所有货都送完!
int ans = Integer.MAX_VALUE;
for (int cur = 0; cur < k; cur++) {
// status : 0010110
// 1
if ( (status & (1 << cur)) == 0) { // 当前cur号的货物可以去尝试
// to[last]
// cur号的货to[last] -> from[cur]
int come = Math.abs(to[last] - from[cur]);
int delive = Math.abs(to[cur] - from[cur]);
int next = zuo(status | (1 << cur), cur, k, from, to);
int curAns = come + delive + next;
ans = Math.min(ans, curAns);
}
}
return ans;
}
}
// 暴力方法
// 全排序代码
public static int minCost1(int k, int[] from, int[] to) {
return process(0, k, from, to);
}
public static int process(int i, int k, int[] from, int[] to) {
if (i == k) {
int ans = 0;
int cur = 1;
for (int j = 0; j < k; j++) {
ans += Math.abs(from[j] - cur);
ans += Math.abs(to[j] - from[j]);
cur = to[j];
}
return ans + cur - 1;
} else {
int ans = Integer.MAX_VALUE;
for (int j = i; j < k; j++) {
swap(from, to, i, j);
ans = Math.min(ans, process(i + 1, k, from, to));
swap(from, to, i, j);
}
return ans;
}
}
public static void swap(int[] from, int[] to, int i, int j) {
int tmp = from[i];
from[i] = from[j];
from[j] = tmp;
tmp = to[i];
to[i] = to[j];
to[j] = tmp;
}
// 正式方法
public static int minCost2(int k, int[] from, int[] to) {
int m = 1 << k;
int[][] dp = new int[m][k];
for (int i = 0; i < m; i++) {
for (int j = 0; j < k; j++) {
dp[i][j] = -1;
}
}
return f(0, 0, k, from, to, dp);
}
// 2^16 = 65536 * 16 = 1048576
// 1048576 * 16 = 16777216
public static int f(int status, int i, int k, int[] from, int[] to, int[][] dp) {
if (dp[status][i] != -1) {
return dp[status][i];
}
int ans = Integer.MAX_VALUE;
if (status == (1 << k) - 1) {
ans = to[i] - 1;
} else {
for (int j = 0; j < k; j++) {
if ((status & (1 << j)) == 0) {
int come = Math.abs(from[j] - (status == 0 ? 1 : to[i]));
int deliver = Math.abs(to[j] - from[j]);
int next = f(status | (1 << j), j, k, from, to, dp);
ans = Math.min(ans, come + deliver + next);
}
}
}
dp[status][i] = ans;
return ans;
}
public static int[] randomArray(int n, int v) {
int[] ans = new int[n];
for (int i = 0; i < n; i++) {
ans[i] = (int) (Math.random() * v) + 1;
}
return ans;
}
public static void main(String[] args) {
int k = 5;
int[] from = { 1, 3, 6, 5, 7 };
int[] to = { 4, 6, 3, 2, 8 };
System.out.println(minCost1(k, from, to));
System.out.println(minCost2(k, from, to));
int N = 8;
int V = 100;
int testTimes = 5000;
System.out.println("功能测试开始");
for (int i = 0; i < testTimes; i++) {
k = (int) (Math.random() * N) + 1;
from = randomArray(k, V);
to = randomArray(k, V);
int ans1 = minCost1(k, from, to);
int ans2 = minCost2(k, from, to);
if (ans1 != ans2) {
System.out.println("出错了!");
}
}
System.out.println("功能测试结束");
System.out.println("性能测试开始");
k = 16;
V = 10000;
from = randomArray(k, V);
to = randomArray(k, V);
System.out.println("货物数量 : " + k);
System.out.println("楼层范围 : " + V);
long start = System.currentTimeMillis();
minCost2(k, from, to);
long end = System.currentTimeMillis();
System.out.println("运行时间 : " + (end - start) + " 毫秒");
System.out.println("性能测试结束");
}
}

@ -0,0 +1,262 @@
package class_2022_09_4_week;
// 来自华为
// 一个n*n的二维数组中只有0和1两种值
// 当你决定在某个位置操作一次
// 那么该位置的行和列整体都会变成1不管之前是什么状态
// 返回让所有值全变成1最少的操作次数
// 1 < n < 10没错原题就是说n < 10, 不会到10最多到9
public class Code02_SetAllOneMinTimes {
// public static int minTimes(int[][] matrix) {
// int n = matrix.length;
// int m = matrix[0].length;
// int[] arr = new int[n];
// for (int i = 0; i < n; i++) {
// int status = 0;
// for (int j = 0; j < m; j++) {
// // 0列 1列 2列 3列
// // 1 0 1 1
// // 1101
// if (matrix[i][j] == 1) {
// status |= 1 << m;
// }
// }
// arr[i] = status;
// }
//
// }
//
// // arr替代了原来的二维数组
// // n行m列固定
// // 目前来到i行、j列
// // rowStatus : 之前哪些行点过鼠标
// // colStatus : 之前哪些列点过鼠标
// // i 行变化 9 * 9 * 2^9 * 2^9 * 9 = 191,102,976
// public static int zuo(int[] arr, int n, int m, int i, int j, int clickRows, int clickCols) {
// if (i == n) {
// for (int row = 0; row < n; row++) {
// if ((clickRows & (1 << row)) != 0) {
// continue;
// }
// // row行没点过鼠标
// int merge = arr[row] | clickCols;
// int full = (1 << m) - 1;
// if (merge != full) {
// return Integer.MAX_VALUE;// 表示无效
// }
// }
// return 0;
// }
// if (j == m) {
// return zuo(arr, n, m, i + 1, 0, clickRows, clickCols);
// }
// // i,j 正常的行、正常的列
// // 当前就是不点鼠标
// int p1 = zuo(arr, n, m, i, j + 1, clickRows, clickCols);
// // 当前就是点鼠标
// int p2 = Integer.MAX_VALUE;
// int next = zuo(arr, n, m, i, j + 1,
// clickRows | (1 << i), clickCols | (1 << j));
// if(next != Integer.MAX_VALUE) {
// p2 = 1 + next;
// }
// return Math.min(p1, p2);
// }
// 暴力方法
// 为了验证
public static int setOneMinTimes1(int[][] matrix) {
int n = matrix.length;
int m = matrix[0].length;
int limit = 1 << (n * m);
int ans = Integer.MAX_VALUE;
// 0000000000000
// 0000000000001
// 0000000000010
// 0000000000011
// 0000000000100
for (int status = 0; status < limit; status++) {
if (ok(status, matrix, n, m)) {
ans = Math.min(ans, hammingWeight(status));
}
}
return ans;
}
public static boolean ok(int status, int[][] matrix, int n, int m) {
int[][] help = new int[n][m];
int limit = n * m;
for (int i = 0; i < limit; i++) {
if ((status & (1 << i)) != 0) {
int row = i / m;
int col = i % m;
for (int j = 0; j < n; j++) {
help[j][col] = 1;
}
for (int j = 0; j < m; j++) {
help[row][j] = 1;
}
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (help[i][j] == 0 && matrix[i][j] == 0) {
return false;
}
}
}
return true;
}
public static int hammingWeight(int n) {
n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);
n = (n & 0x00ff00ff) + ((n >>> 8) & 0x00ff00ff);
n = (n & 0x0000ffff) + ((n >>> 16) & 0x0000ffff);
return n;
}
// 正式方法
public static int setOneMinTimes2(int[][] matrix) {
int n = matrix.length;
int m = matrix[0].length;
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
int status = 0;
for (int j = 0; j < m; j++) {
if (matrix[i][j] == 1) {
status |= 1 << j;
}
}
arr[i] = status;
}
int[][][][] dp = new int[1 << n][1 << m][n][m];
for (int a = 0; a < (1 << n); a++) {
for (int b = 0; b < (1 << m); b++) {
for (int c = 0; c < n; c++) {
for (int d = 0; d < m; d++) {
dp[a][b][c][d] = -1;
}
}
}
}
return process2(arr, n, m, 0, 0, 0, 0, dp);
}
public static int process2(int[] arr, int n, int m, int row, int col, int r, int c, int[][][][] dp) {
if (r == n) {
for (int i = 0; i < n; i++) {
if ((row & (1 << i)) == 0 && (arr[i] | col) != (1 << m) - 1) {
return Integer.MAX_VALUE;
}
}
return 0;
}
if (c == m) {
return process2(arr, n, m, row, col, r + 1, 0, dp);
}
if (dp[row][col][r][c] != -1) {
return dp[row][col][r][c];
}
int p1 = process2(arr, n, m, row, col, r, c + 1, dp);
int p2 = Integer.MAX_VALUE;
int next2 = process2(arr, n, m, row | (1 << r), col | (1 << c), r, c + 1, dp);
if (next2 != Integer.MAX_VALUE) {
p2 = 1 + next2;
}
int ans = Math.min(p1, p2);
dp[row][col][r][c] = ans;
return ans;
}
// 正式方法 + 贪心
public static int setOneMinTimes3(int[][] matrix) {
int n = matrix.length;
int m = matrix[0].length;
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
int status = 0;
for (int j = 0; j < m; j++) {
if (matrix[i][j] == 1) {
status |= 1 << j;
}
}
arr[i] = status;
}
int[][][][] dp = new int[1 << n][1 << m][n][m];
for (int a = 0; a < (1 << n); a++) {
for (int b = 0; b < (1 << m); b++) {
for (int c = 0; c < n; c++) {
for (int d = 0; d < m; d++) {
dp[a][b][c][d] = -1;
}
}
}
}
return process3(arr, n, m, 0, 0, 0, 0, dp);
}
public static int process3(int[] arr, int n, int m, int row, int col, int r, int c, int[][][][] dp) {
if (r == n) {
for (int i = 0; i < n; i++) {
if ((row & (1 << i)) == 0 && (arr[i] | col) != (1 << m) - 1) {
return Integer.MAX_VALUE;
}
}
return 0;
}
if (c == m) {
return process3(arr, n, m, row, col, r + 1, 0, dp);
}
if (dp[row][col][r][c] != -1) {
return dp[row][col][r][c];
}
int p1 = process3(arr, n, m, row, col, r, c + 1, dp);
int p2 = Integer.MAX_VALUE;
int next2 = process3(arr, n, m, row | (1 << r), col | (1 << c), r + 1, 0, dp);
if (next2 != Integer.MAX_VALUE) {
p2 = 1 + next2;
}
int ans = Math.min(p1, p2);
dp[row][col][r][c] = ans;
return ans;
}
public static int[][] randomMatrix(int n, int m, double p0) {
int[][] ans = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
ans[i][j] = Math.random() < p0 ? 0 : 1;
}
}
return ans;
}
public static void main(String[] args) {
int N = 3;
int testTimes = 5000;
System.out.println("功能测试开始");
for (int i = 0; i < testTimes; i++) {
int n = (int) (Math.random() * N) + 1;
int m = (int) (Math.random() * N) + 1;
double p0 = Math.random();
int[][] matrix = randomMatrix(n, m, p0);
int ans1 = setOneMinTimes1(matrix);
int ans2 = setOneMinTimes2(matrix);
int ans3 = setOneMinTimes3(matrix);
if (ans1 != ans2 || ans1 != ans3) {
System.out.println("出错了!");
}
}
System.out.println("功能测试结束");
int[][] matrix = randomMatrix(9, 9, 0.9);
long start = System.currentTimeMillis();
setOneMinTimes2(matrix);
long end = System.currentTimeMillis();
System.out.println("最极限的数据下的运行时间 : " + (end - start) + "毫秒");
}
}

@ -0,0 +1,292 @@
package class_2022_09_4_week;
import java.util.Arrays;
// 来自华为
// 给定一个二维数组map代表一个餐厅其中只有0、1两种值
// map[i][j] == 0 表示(i,j)位置是空座
// map[i][j] == 1 表示(i,j)位置坐了人
// 根据防疫要求,任何人的上、下、左、右,四个相邻的方向都不能再坐人
// 但是为了餐厅利用的最大化,也许还能在不违反防疫要求的情况下,继续安排人吃饭
// 请返回还能安排的最大人数
// 如果一开始的状况已经不合法,直接返回-1
// 比如:
// 1 0 0 0
// 0 0 0 1
// 不违反防疫要求的情况下这个餐厅最多还能安排2人如下所示X是新安排的人
// 1 0 X 0
// 0 X 0 1
// 再比如:
// 1 0 0 0 0 1
// 0 0 0 0 0 0
// 0 1 0 0 0 1
// 0 0 0 0 0 0
// 不违反防疫要求的情况下这个餐厅最多还能安排7人如下所示X是新安排的人
// 1 0 0 X 0 1
// 0 0 X 0 X 0
// 0 1 0 X 0 1
// X 0 X 0 X 0
// 数据范围 : 1 <= 矩阵的行、列 <= 20
public class Code03_MostSeats {
// public static int maxPeople(int[][] matrix) {
// int n = matrix.length;
// int m = matrix[0].length;
// for (int i = 0; i < n; i++) {
// for (int j = 0; j < m; j++) {
// if (matrix[i][j] == 1) {
// if (i > 0 && matrix[i - 1][j] == 1) {
// return -1;
// }
// if (i < n - 1 && matrix[i + 1][j] == 1) {
// return -1;
// }
// if (j > 0 && matrix[i][j - 1] == 1) {
// return -1;
// }
// if (j < m - 1 && matrix[i][j + 1] == 1) {
// return -1;
// }
// }
// }
// }
// int[] arr = new int[n];
// for (int i = 0; i < n; i++) {
// int status = 0;
// for (int j = 0; j < m; j++) {
// if (matrix[i][j] == 1) {
// status |= 1 << j;
// }
//
// arr[i] = status;
// }
// }
// return zuo(arr, n, m, 0, 0, 0);
//
// }
//
// public static int zuo(int[] arr, int n, int m, int i, int j, int status) {
// if (i == n) {
// return 0;
// }
// if (j == m) {
// return zuo(arr, n, m, i + 1, 0, status);
// }
// // 怎么判断已经无效了
// if ((arr[i] & status) != 0) {
// return -1;
// }
// // (i,j)
// int left = status(status, j - 1, m);
// int up = status(status, j, m);
// int right = status(arr[i], j + 1, m);
// int cur = status(arr[i], j, m);
// // 当前位置不安排新人了
// int p1 = -1;
// if (cur == 0) { // 原始的该位置无人
// int nextStatus = status ^ (up << j);
// p1 = zuo(arr, n, m, i, j + 1, nextStatus);
// } else { // 原始的该位置有人
// int nextStatus = (status | (1 << j));
// p1 = zuo(arr, n, m, i, j + 1, nextStatus);
// }
// // 当前位置安排新人
// int p2 = -1;
// if(left == 0 && up == 0 && right == 0 && cur == 0) {
// int nextStatus = (status | (1 << j));
// int next = zuo(arr, n, m, i, j + 1, nextStatus);
// if(next != -1) {
// p2 = 1 + next;
// }
// }
// return Math.max(p1, p2);
// }
// 为了测试,普通方法
// 普通的状态压缩动态规划
// 每一行用dfs的方法
// 体系学习班章节44 : 状态压缩的动态规划,贴瓷砖问题类似
public static int mostSeats1(int[][] map) {
int n = map.length;
int m = map[0].length;
int[] arr = new int[n];
for (int row = 0; row < n; row++) {
int status = 0;
for (int col = 0, i = m - 1; col < m; col++, i--) {
if (map[row][col] == 1) {
if (row > 0 && map[row - 1][col] == 1) {
return -1;
}
if (col > 0 && map[row][col - 1] == 1) {
return -1;
}
}
status |= map[row][col] << i;
}
arr[row] = status;
}
int[][] dp = new int[n][1 << m];
for (int i = 0; i < n; i++) {
Arrays.fill(dp[i], -2);
}
int ans = process1(arr, 0, 0, m, dp);
return ans == -1 ? 0 : ans;
}
public static int process1(int[] arr, int row, int pre, int m, int[][] dp) {
if (row == arr.length) {
return 0;
}
if (dp[row][pre] != -2) {
return dp[row][pre];
}
int cur = arr[row];
int ans = 0;
if ((cur & pre) != 0) {
ans = -1;
} else {
ans = dfs(arr, row, m - 1, pre, cur, m, dp);
}
dp[row][pre] = ans;
return ans;
}
public static int dfs(int[] arr, int row, int col, int pre, int seats, int m, int[][] dp) {
if (col == -1) {
return process1(arr, row + 1, seats, m, dp);
} else {
int p1 = dfs(arr, row, col - 1, pre, seats, m, dp);
int p2 = -1;
if ((pre & (1 << col)) == 0 && (seats & (1 << col)) == 0
&& (col == m - 1 || (seats & (1 << (col + 1))) == 0)
&& (col == 0 || (seats & (1 << (col - 1))) == 0)) {
int next2 = dfs(arr, row, col - 1, pre, seats | (1 << col), m, dp);
if (next2 != -1) {
p2 = 1 + next2;
}
}
return Math.max(p1, p2);
}
}
// 正式方法
// 轮廓线dp
public static int mostSeats2(int[][] map) {
int n = map.length;
int m = map[0].length;
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
int status = 0;
for (int j = 0; j < m; j++) {
if (map[i][j] == 1) {
if (i > 0 && map[i - 1][j] == 1) {
return -1;
}
if (j > 0 && map[i][j - 1] == 1) {
return -1;
}
}
status |= map[i][j] << j;
}
arr[i] = status;
}
int s = 1 << m;
int[][][] dp = new int[n][m][s];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
for (int k = 0; k < s; k++) {
dp[i][j][k] = -2;
}
}
}
int ans = process2(arr, n, m, 0, 0, 0, dp);
return ans == -1 ? 0 : ans;
}
// 20 * 20 * 2^20 -> 4 * 10^8
public static int process2(int[] arr, int n, int m, int i, int j, int status, int[][][] dp) {
if (j == m) {
return process2(arr, n, m, i + 1, 0, status, dp);
}
if (i == n) {
return 0;
}
if (dp[i][j][status] != -2) {
return dp[i][j][status];
}
int left = status(status, j - 1, m);
int up = status(status, j, m);
int cur = status(arr[i], j, m);
int right = status(arr[i], j + 1, m);
if (up == 1 && cur == 1) {
return -1;
}
int p1 = -1;
if (cur == 1) {
p1 = process2(arr, n, m, i, j + 1, status | (1 << j), dp);
} else {
p1 = process2(arr, n, m, i, j + 1, (status | (1 << j)) ^ (1 << j), dp);
}
int p2 = -1;
if (left == 0 && up == 0 && cur == 0 && right == 0) {
int next2 = process2(arr, n, m, i, j + 1, status | (1 << j), dp);
if (next2 != -1) {
p2 = 1 + next2;
}
}
int ans = Math.max(p1, p2);
dp[i][j][status] = ans;
return ans;
}
public static int status(int status, int i, int m) {
return (i < 0 || i == m || (status & (1 << i)) == 0) ? 0 : 1;
}
public static int[][] randomMatrix(int n, int m, double oneP) {
int[][] ans = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
ans[i][j] = Math.random() < oneP ? 1 : 0;
}
}
return ans;
}
public static void main(String[] args) {
int N = 10;
int M = 10;
// 产生1的概率
double oneP = 0.15;
int testTimes = 10000;
System.out.println("测试开始");
for (int i = 0; i < testTimes; i++) {
int n = (int) (Math.random() * N) + 1;
int m = (int) (Math.random() * M) + 1;
int[][] map = randomMatrix(n, m, oneP);
int ans1 = mostSeats1(map);
int ans2 = mostSeats2(map);
if (ans1 != ans2) {
for (int[] arr : map) {
for (int num : arr) {
System.out.print(num + " ");
}
System.out.println();
}
System.out.println(ans1);
System.out.println(ans2);
break;
}
}
System.out.println("测试结束");
int n = 20;
int[][] map = new int[n][n];
System.out.println("最大规模 : " + n + " * " + n);
long start = System.currentTimeMillis();
mostSeats2(map);
long end = System.currentTimeMillis();
System.out.println("运行时间 : " + (end - start) + " 毫秒");
}
}

@ -0,0 +1,83 @@
package class_2022_09_4_week;
// 给你两个整数 m 和 n 。构造一个 m x n 的网格,其中每个单元格最开始是白色
// 请你用 红、绿、蓝 三种颜色为每个单元格涂色。所有单元格都需要被涂色
// 涂色方案需要满足:不存在相邻两个单元格颜色相同的情况
// 返回网格涂色的方法数。因为答案可能非常大
// 返回 对 109 + 7 取余 的结果。
// 1 <= n <= 1000
// 1 <= m <= 5
// 测试链接 : https://leetcode.cn/problems/painting-a-grid-with-three-different-colors/
public class Code04_PaintingGridWithThreeDifferentColors {
// public static int zuo(int i, int j, int s, int n, int m) {
// if (i == n) {
// return 1;
// }
// if (j == m) {
// return zuo(i + 1, 0, s, n, m);
// }
//
// // j列
// int up = (s >> (j * 2)) & 3;
// int left = j == 0 ? 0 : ((s >> ((j - 1) * 2)) & 3);
// int ans = 0;
// if (up != 1 && left != 1) { // 当前格子就涂1这个颜色
// int exp = statu
// ans += zuo( i, j + 1, ?, n,m);
//
// }
// if (up != 2 && left != 2) {
//
// }
// if (up != 3 && left != 3) {
//
// }
// return ans;
// }
public static final int mod = 1000000007;
public static int colorTheGrid(int m, int n) {
int status = 1 << (m << 1);
int[][][] dp = new int[n][m][status];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
for (int s = 0; s < status; s++) {
dp[i][j][s] = -1;
}
}
}
return process(0, 0, 0, n, m, dp);
}
public static int process(int i, int j, int s, int n, int m, int[][][] dp) {
if (i == n) {
return 1;
}
if (j == m) {
return process(i + 1, 0, s, n, m, dp);
}
if (dp[i][j][s] != -1) {
return dp[i][j][s];
}
int up = (s >> (j * 2)) & 3;
int left = j == 0 ? 0 : ((s >> ((j - 1) << 1)) & 3);
int ans = 0;
if (up != 1 && left != 1) {
ans += process(i, j + 1,(s ^ (up << (j * 2))) | (1 << (j * 2)), n, m, dp);
ans %= mod;
}
if (up != 2 && left != 2) {
ans += process(i, j + 1, (s ^ (up << (j << 1))) | (2 << (j << 1)), n, m, dp);
ans %= mod;
}
if (up != 3 && left != 3) {
ans += process(i, j + 1, (s ^ (up << (j << 1))) | (3 << (j << 1)), n, m, dp);
ans %= mod;
}
dp[i][j][s] = ans;
return ans;
}
}

@ -0,0 +1,150 @@
package class_2022_09_4_week;
import java.util.HashMap;
import java.util.HashSet;
// 来自字节
// 给定正数N表示用户数量用户编号从0~N-1
// 给定正数M表示实验数量实验编号从0~M-1
// 给定长度为N的二维数组A
// A[i] = { a, b, c }表示用户i报名参加了a号、b号、c号实验
// 给定正数Q表示查询的条数
// 给定长度为Q的二维数组B
// B[i] = { e, f }表示第i条查询想知道e号、f号实验一共有多少人(去重统计)
// 返回每一条查询的结果数组
// 数据描述 :
// 1 <= N <= 10^5
// 1 <= M <= 10^2
// 1 <= Q <= 10^4
// 所有查询所列出的所有实验编号数量(也就是二维数组B行*列的规模) <= 10^5
public class Code05_EveryQueryUsers {
// 暴力方法
// 为了验证
public static int[] record1(int n, int m, int q, int[][] A, int[][] B) {
HashMap<Integer, HashSet<Integer>> expUsersMap = new HashMap<>();
for (int i = 0; i < m; i++) {
expUsersMap.put(i, new HashSet<>());
}
for (int i = 0; i < n; i++) {
for (int exp : A[i]) {
expUsersMap.get(exp).add(i);
}
}
int[] ans = new int[q];
HashSet<Integer> help = new HashSet<>();
for (int i = 0; i < q; i++) {
help.clear();
for (int exp : B[i]) {
for (int user : expUsersMap.get(exp)) {
help.add(user);
}
}
ans[i] = help.size();
}
return ans;
}
// 正式方法
public static int[] record2(int n, int m, int q, int[][] A, int[][] B) {
// n 一共有多少人
// 任何一个实验,需要几个整数,能表示所有人谁出现谁没出现?
int parts = (n + 31) / 32;
// m 0 ~ m -1
// [i] [.........]
int[][] bitMap = new int[m][parts];
for (int i = 0; i < n; i++) {
// i 人的编号 : a b c
for (int exp : A[i]) {
bitMap[exp][i / 32] |= 1 << (i % 32);
}
}
int[] ans = new int[q];
for (int i = 0; i < q; i++) {
// i号查询 a、c、e一共有多少去重的人
// a[0] | c[0] | e[0] -> 几个1
// a[1] | c[1] | e[1] -> 几个1
int all = 0;
for (int j = 0; j < parts; j++) {
int status = 0;
for (int exp : B[i]) {
status |= bitMap[exp][j];
}
all += countOnes(status);
}
ans[i] = all;
}
return ans;
}
// 大厂刷题班32节leetcode专题 : https://leetcode.com/problems/number-of-1-bits/
public static int countOnes(int n) {
n = (n & 0x55555555) + ((n >>> 1) & 0x55555555);
n = (n & 0x33333333) + ((n >>> 2) & 0x33333333);
n = (n & 0x0f0f0f0f) + ((n >>> 4) & 0x0f0f0f0f);
n = (n & 0x00ff00ff) + ((n >>> 8) & 0x00ff00ff);
n = (n & 0x0000ffff) + ((n >>> 16) & 0x0000ffff);
return n;
}
// 为了测试
public static int[][] randomMatrix(int n, int m, int v) {
int[][] ans = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
ans[i][j] = (int) (Math.random() * v);
}
}
return ans;
}
// 为了测试
public static void main(String[] args) {
int N = 100;
int M = 20;
int Q = 50;
int testTime = 5000;
System.out.println("功能测试开始");
for (int i = 0; i < testTime; i++) {
int n = (int) (Math.random() * N) + 1;
int m = (int) (Math.random() * M) + 1;
int[][] A = randomMatrix(n, (int) (Math.random() * m) + 1, m);
int q = (int) (Math.random() * Q) + 1;
int[][] B = randomMatrix(q, (int) (Math.random() * m) + 1, m);
int[] ans1 = record1(n, m, q, A, B);
int[] ans2 = record2(n, m, q, A, B);
boolean pass = true;
for (int j = 0; j < q; j++) {
if (ans1[j] != ans2[j]) {
pass = false;
break;
}
}
if (!pass) {
System.out.println("出错了!");
break;
}
}
System.out.println("功能测试结束");
System.out.println("性能测试开始");
int n = 100000;
int m = 100;
int[][] A = randomMatrix(n, m, m);
int q = 10000;
int c = 10;
int[][] B = randomMatrix(q, c, m);
System.out.println("用户数量 : " + n);
System.out.println("实验数量 : " + m);
System.out.println("用户参加的实验数量总和 : " + n * m);
System.out.println("查询条数 : " + q);
System.out.println("每条查询的实验数量 : " + c);
System.out.println("所有查询所列出的所有实验编号数量 : " + q * c);
long start = System.currentTimeMillis();
record2(n, m, q, A, B);
long end = System.currentTimeMillis();
System.out.println("运行时间 : " + (end - start) + " 毫秒");
System.out.println("性能测试结束");
}
}

@ -1985,6 +1985,85 @@ https://www.mashibing.com/question/detail/37485
第042节 2022年9月第4周流行算法题目解析
来自学员问题
智能机器人要坐专用电梯把货物送到指定地点
整栋楼只有一部电梯,并且由于容量限制智能机器人只能放下一件货物
给定K个货物每个货物都有所在楼层(from)和目的楼层(to)
假设电梯速度恒定为1相邻两个楼层之间的距离为1
例如电梯从10层去往19层的时间为9
机器人装卸货物的时间极快不计入
电梯初始地点为第1层机器人初始地点也是第1层
并且在运送完所有货物之后机器人和电梯都要回到1层
返回智能机器人用电梯将每个物品都送去目标楼层的最快时间
注意:如果智能机器人选了一件物品,则必须把这个物品送完,不能中途丢下
输入描述:
正数k表示货物数量1 <= k <= 16
from、to数组长度都是k1 <= from[i]、to[i] <= 10000
from[i]表示i号货物所在的楼层
to[i]表示i号货物要去往的楼层
返回最快的时间
来自华为
一个n*n的二维数组中只有0和1两种值
当你决定在某个位置操作一次
那么该位置的行和列整体都会变成1不管之前是什么状态
返回让所有值全变成1最少的操作次数
1 < n < 10没错原题就是说n < 10, 不会到10最多到9
来自华为
给定一个二维数组map代表一个餐厅其中只有0、1两种值
map[i][j] == 0 表示(i,j)位置是空座
map[i][j] == 1 表示(i,j)位置坐了人
根据防疫要求,任何人的上、下、左、右,四个相邻的方向都不能再坐人
但是为了餐厅利用的最大化,也许还能在不违反防疫要求的情况下,继续安排人吃饭
请返回还能安排的最大人数
如果一开始的状况已经不合法,直接返回-1
比如:
1 0 0 0
0 0 0 1
不违反防疫要求的情况下这个餐厅最多还能安排2人如下所示X是新安排的人
1 0 X 0
0 X 0 1
再比如:
1 0 0 0 0 1
0 0 0 0 0 0
0 1 0 0 0 1
0 0 0 0 0 0
不违反防疫要求的情况下这个餐厅最多还能安排7人如下所示X是新安排的人
1 0 0 X 0 1
0 0 X 0 X 0
0 1 0 X 0 1
X 0 X 0 X 0
数据范围 : 1 <= 矩阵的行、列 <= 20
给你两个整数 m 和 n 。构造一个 m x n 的网格,其中每个单元格最开始是白色
请你用 红、绿、蓝 三种颜色为每个单元格涂色。所有单元格都需要被涂色
涂色方案需要满足:不存在相邻两个单元格颜色相同的情况
返回网格涂色的方法数。因为答案可能非常大
返回 对 109 + 7 取余 的结果。
1 <= n <= 1000
1 <= m <= 5
测试链接 : https://leetcode.cn/problems/painting-a-grid-with-three-different-colors/
来自字节
给定正数N表示用户数量用户编号从0~N-1
给定正数M表示实验数量实验编号从0~M-1
给定长度为N的二维数组A
A[i] = { a, b, c }表示用户i报名参加了a号、b号、c号实验
给定正数Q表示查询的条数
给定长度为Q的二维数组B
B[i] = { e, f }表示第i条查询想知道e号、f号实验一共有多少人(去重统计)
返回每一条查询的结果数组
数据描述 :
1 <= N <= 10^5
1 <= M <= 10^2
1 <= Q <= 10^4
所有查询所列出的所有实验编号数量(也就是二维数组B行*列的规模) <= 10^5

Loading…
Cancel
Save