题目一
861. 翻转矩阵后的得分
有一个二维矩阵 A 其中每个元素的值为 0 或 1 。
移动是指选择任一行或列,并转换该行或列中的每一个值:将所有 0 都更改为 1,将所有 1 都更改为 0。
在做出任意次数的移动后,将该矩阵的每一行都按照二进制数来解释,矩阵的得分就是这些数字的总和。
返回尽可能高的分数。
示例:
输入:[[0,0,1,1],[1,0,1,0],[1,1,0,0]]
输出:39
解释:
转换为 [[1,1,1,1],[1,0,0,1],[1,1,1,1]]
0b1111 + 0b1001 + 0b1111 = 15 + 9 + 15 = 39
提示:
1 <= A.length <= 20
1 <= A[0].length <= 20
A[i][j]
是 0 或 1
我的答案
class Solution {
/*
0 0 1 1
1 0 1 0
1 1 0 0
1 1 0 0
1 0 1 0
1 1 0 0
1 1 1 1
1 0 0 1
1 1 1 1
0 1 1
1 1 1
0 1 0
1 0 0
1 1 1
1 0 1
1 1 0 6
1 0 1 5
1 1 1 7
*/
public int matrixScore(int[][] A) {
// 1.反转行使得,第一列都为1
for(int[] a : A){
if(a[0] != 1){
lineFlip(a);
}
}
// 从第二列开始,判断列中0和1的数量
// 0的数量大于1的数据就要进行翻转
for(int i = 1; i< A[0].length; i++){
int zeros = 0; // 用于记录0的个数
int ones = 0; // 用于记录1的个数
boolean flip = false;
for(int[] a : A){
if(a[i] == 0){
if(++zeros > A.length/2){
flip = true; // 要反转
break;
}
}else{
if(++ones > A.length/2) break;
}
}
// System.out.println(zeros + "--" + ones + ": " + flip);
if(flip) columnFlip(A, i);
}
// System.out.println(Arrays.deepToString(A));
int ret = 0;
for(int[] a : A){
StringBuilder binaryStr = new StringBuilder();
for(int num : a){
binaryStr.append(num);
}
ret += Integer.parseInt(binaryStr.toString(), 2);
}
return ret;
}
// 翻转行
public void lineFlip(int[] line){
for(int i = 0; i < line.length; i++){
if(line[i] == 0) line[i] = 1;
else line[i] = 0;
}
}
// 翻转列
public void columnFlip(int[][] A, int i){
for(int[] a : A){
if(a[i] == 0) a[i] = 1;
else a[i] = 0;
}
}
}
还是只能写这样暴力的算法T T…。可以优化的地方还有很多。
官方答案方法一:贪心
class Solution {
public int matrixScore(int[][] A) {
int m = A.length, n = A[0].length;
int ret = m * (1 << (n - 1));
for (int j = 1; j < n; j++) {
int nOnes = 0;
for (int i = 0; i < m; i++) {
if (A[i][0] == 1) {
nOnes += A[i][j];
} else {
nOnes += (1 - A[i][j]); // 如果这一行进行了行反转,则该元素的实际取值为 1 - A[i][j]
}
}
int k = Math.max(nOnes, m - nOnes);
ret += k * (1 << (n - j - 1));
}
return ret;
}
}
复杂度分析
- 时间复杂度:O(mn),其中 m为矩阵行数,n为矩阵列数。
- 空间复杂度:O(1)。
注:<<
表示左移移,不分正负数,低位补0
比如运算’-16<<2’的结果,首先 你要将-16转换为二进制数
-16的二进制原码为1001 0000
-16的二进制反码为1110 1111
-16的二进制补码为1111 0000
左移两位后的补码为1100 0000
左移两位后的反码为1011 1111
左移两位后的原码为1100 0000
由于不太好理解<<
运算,因此可以参考https://leetcode-cn.com/problems/score-after-flipping-matrix/solution/fan-zhuan-ju-zhen-hou-de-de-fen-by-leetc-cxma/695943的答案
class Solution {
public int matrixScore(int[][] A) {
// 1. 也是先将第一列全反转成1
for(int[] a : A) {
if(a[0] == 0) {
for(int i = 0; i < a.length; i++) {
a[i] = a[i] == 0 ? 1 : 0;
}
}
}
int res = 0;
for(int i = 0; i < A[0].length; i++) {
int count = 0; // 用于统计每列的1的个数
for(int j = 0; j < A.length; j++) {
if(A[j][i] == 1) count++;
}
if(count <= A.length/2) count = A.length-count; // 记录0的个数
res += count * Math.pow(2, A[0].length-i-1); // 计算每个二进制位上对应数的十进制
// 加到结果上
/*
比如,对于这样的一列i=1,1 1 0,A.length/2=4/2=2
那么 count=2, 2<=2,count=4-2=2
res += 2*Math.pow(2, 3-1-1)=2*2=4,很明显不用翻转,110即为4
那么对于i=2, 0 1 0,A.length/2=4/2=2
count=1 1<=2 count=4-1=3
res += 3*Math.pow(2, 3-2-1)=3 很明显要反转成101,即为3
*/
}
return res;
}
}
题目二
1221. 分割平衡字符串
在一个「平衡字符串」中,‘L’ 和 ‘R’ 字符的数量是相同的。
给出一个平衡字符串 s,请你将它分割成尽可能多的平衡字符串。
返回可以通过分割得到的平衡字符串的最大数量。
示例 1:
输入:s = “RLRRLLRLRL”
输出:4
解释:s 可以分割为 “RL”, “RRLL”, “RL”, “RL”, 每个子字符串中都包含相同数量的 ‘L’ 和 ‘R’。
示例 2:
输入:s = “RLLLLRRRLR”
输出:3
解释:s 可以分割为 “RL”, “LLLRRR”, “LR”, 每个子字符串中都包含相同数量的 ‘L’ 和 ‘R’。
示例 3:
输入:s = “LLLLRRRR”
输出:1
解释:s 只能保持原样 “LLLLRRRR”.
提示:
1 <= s.length <= 1000
s[i] = ‘L’ 或 ‘R’
分割得到的每个字符串都必须是平衡字符串。
我的答案
class Solution {
public int balancedStringSplit(String s) {
int ret = 0;
int r = 0; // 记录R的数量
int l = 0; // 记录L的数量
for(char c : s.toCharArray()){
if(c == 'R'){
r++;
}else if(c == 'L'){
l++;
}
if(r == l){ // 只要L和R的数量相等了就ret++
ret++;
r = 0; // 并将二者归零
l = 0;
}
}
return ret;
}
}