数学编程题通常都是找规律然后通过代码去检查这些规律,这些规律每个一天两天真是找不出来,我的建议是直接看题解记住,以下汇总笔者的刷题路径。
相关题目
782.变为棋盘
参考题解
class Solution {
public int movesToChessboard(int[][] board) {
if (!check(board)) {
return -1;
}
int[] col = new int[board.length];
for (int i = 0; i < board.length; i++) {
col[i] = board[i][0];
}
return getSwapCount(board[0]) + getSwapCount(col);
}
/**
* 检查合法性 分别检查行和列
*
* @param board 数组
* @return
*/
public boolean check(int[][] board) {
return checkFirstRow(board) &&
checkFirstCol(board) &&
checkRow(board) &&
checkCol(board);
}
public boolean checkFirstRow(int[][] board) {
int rowOneCnt = 0;
int rowZeroCnt = 0;
int[] first = board[0];
for (int num : first) {
if (num == 0) {
rowZeroCnt++;
} else {
rowOneCnt++;
}
}
return rowOneCnt == rowZeroCnt || Math.abs(rowOneCnt - rowZeroCnt) == 1;
}
public boolean checkFirstCol(int[][] board) {
int oneCnt = 0, zeroCnt = 0;
for (int i = 0; i < board.length; i++) {
if (board[i][0] == 0) {
zeroCnt++;
} else {
oneCnt++;
}
}
return oneCnt == zeroCnt || Math.abs(oneCnt - zeroCnt) == 1;
}
public boolean checkRow(int[][] board) {
//第一行当做哨兵 其他的行要么和第一行相等 要么和第一行相反
//如:第一行0110 后续的行只能是 0110、1001
int[] sentinel = board[0];
int sameCnt = 0, oppositeCnt = 0;
for (int[] cur : board) {
//相同
if (sentinel[0] == cur[0]) {
for (int i = 0; i < sentinel.length; i++) {
if (sentinel[i] != cur[i]) {
return false;
}
}
sameCnt++;
} else {
//相反
for (int i = 0; i < sentinel.length; i++) {
if (sentinel[i] + cur[i] != 1) {
return false;
}
}
oppositeCnt++;
}
}
return sameCnt == oppositeCnt || Math.abs(sameCnt - oppositeCnt) == 1;
}
public boolean checkCol(int[][] board) {
//第一列当做哨兵 其他的列要么和第一列相等 要么和第一列相反
//如:第一列0110 后续的列只能是 0110、1001
int sameCnt = 0, oppositeCnt = 0;
int[] sentinel = new int[board.length];
for (int j = 0; j < board.length; j++) {
sentinel[j] = board[j][0];
}
for (int j = 0; j < board.length; j++) {
if (board[0][j] == sentinel[0]) {
for (int i = 0; i < sentinel.length; i++) {
if (sentinel[i] != board[i][j]) {
return false;
}
}
sameCnt++;
} else {
for (int i = 0; i < sentinel.length; i++) {
if (sentinel[i] + board[i][j] != 1) {
return false;
}
}
oppositeCnt++;
}
}
return sameCnt == oppositeCnt || Math.abs(sameCnt - oppositeCnt) == 1;
}
private int getSwapCount(int[] sentinel) {
//假设都是10101010...
int preNum = 1;
int errorCnt = 0;
for (int i : sentinel) {
//统计有多少错位
if (i != preNum) {
errorCnt++;
}
preNum = preNum == 1 ? 0 : 1;
}
//数组是偶数个还是奇数个
if (sentinel.length % 2 == 0) {
//偶数个 可以是01010101 或者 10101010
return Math.min(sentinel.length - errorCnt, errorCnt) / 2;
} else {
//奇数个 取决于1多还是0多 1多则是1 0 1 0 1 0 1 0 1 、0多则是0 1 0 1 0 1 0 1 0
//并且错误的个数一定是偶数个
if (errorCnt % 2 == 0) {
return errorCnt / 2;
} else {
return (sentinel.length - errorCnt) >> 1;
}
}
}
}
667.优美的排列II
参考宫水三叶的题解,从首位开始按照「升序」间隔排列,次位开始按照「降序」间隔排列(即排列为 [1, n, 2, n - 1, 3, ...]
)时,相邻差值会从 n - 1
开始递减至 1
,共 n - 1
种,是这题的trick。这样的k+1
个数字可以构造k
个差值(与第一个数字是什么无关,比如4、5、6、7、8、9构造成4->9->5->8->6->7),然后只需要让剩余的数字在前面按照升序排列就行。
class Solution {
public int[] constructArray(int n, int k) {
int t=n-k-1;
int[]ans=new int[n];
for(int i=0;i<t;i++){
ans[i]=i+1;
}
for(int i=t,a=n-k,b=n;i<n;){
ans[i++]=a++;
if(i<n) ans[i++]=b--;
}
return ans;
}
}
672.灯泡开关Ⅱ
参考题解
class Solution {
public int flipLights(int n, int presses) {
if (presses == 0) {
return 1;
}
if (n == 1) {
return 2;
}
if (n == 2) {
return presses == 1 ? 3 : 4;
}
if (presses == 1) {
return 4;
}
return presses == 2 ? 7 : 8;
}
}