每日算法31_2020-12-07

来源:题库 - 力扣 (LeetCode) (leetcode-cn.com)。侵删。

题目一

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;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值