当前位置: 首页 > article >正文

Leetcode3276. 选择矩阵中单元格的最大得分

Every day a Leetcode

题目来源:3276. 选择矩阵中单元格的最大得分

解法1:回溯

每一行最多选1个数字,如果要选,就要保证前面没有选择过该数字,然后将得分累加,传入下一次递归,如果不选,那就是直接跳过当前这一行,得分不累加。

代码:

/*
 * @lc app=leetcode.cn id=3276 lang=cpp
 *
 * [3276] 选择矩阵中单元格的最大得分
 */

// @lc code=start
class Solution
{
private:
    int m, n;
    int ans = 0;

public:
    int maxScore(vector<vector<int>> &grid)
    {
        m = grid.size(), n = m ? grid[0].size() : 0;
        unordered_set<int> s;
        backtrace(0, 0, s, grid);
        return ans;
    }
    // 辅函数 - 回溯
    void backtrace(int level, int score, unordered_set<int> s, vector<vector<int>> &grid)
    {
        if (level == m)
        {
            ans = max(ans, score);
            return;
        }
        for (int j = 0; j < n; j++)
        {
            if (s.count(grid[level][j]) == 0)
            {
                s.insert(grid[level][j]);
                score += grid[level][j];
                backtrace(level + 1, score, s, grid);
                score -= grid[level][j];
                s.erase(grid[level][j]);
                backtrace(level + 1, score, s, grid);
            }
        }
    }
};
// @lc code=end

结果:超时

在这里插入图片描述

复杂度分析:

时间复杂度:O(m * n * 2m*n),其中 m 和 n 分别为二维矩阵 grid 的行数和列数。

空间复杂度:O(m * n + 2m),其中 m 和 n 分别为二维矩阵 grid 的行数和列数。

解法2:状压 DP

定义状态为 dp[i][j],表示在 [1,i] 中选数字,所选数字所处的行号不能在集合 j 中,每行至多一个数且没有相同元素时,所选元素之和的最大值。

讨论元素 i 选或不选:

  • 不选 i,问题变成在 [1,i−1] 中选数字,所选数字所处的行号不能在集合 j 中,每行至多一个数且没有相同元素时,所选元素之和的最大值,即 dp[i-1][j]。
  • 选 i,枚举选第 k 行的 i(提前预处理 i 所处的行号),问题变成在 [1,i−1] 中选数字(注意 i 只能选一次),所选数字所处的行号不能在集合 j∪{k} 中,每行至多一个数且没有相同元素时,所选元素之和的最大值,即 dp[i-1][j∪{k}]。

两种情况取最大值。

代码:

// 状压 DP

class Solution
{
public:
    int maxScore(vector<vector<int>> &grid)
    {
        int m = grid.size();
        unordered_map<int, int> pos;
        for (int i = 0; i < m; i++)
        {
            for (int &x : grid[i])
            {
                // 保存所有包含 x 的行号(压缩成二进制数)
                pos[x] |= 1 << i;
            }
        }

        vector<int> all_nums;
        for (auto &[x, _] : pos)
        {
            all_nums.push_back(x);
        }

        int u = 1 << m;
        vector<vector<int>> dp(all_nums.size() + 1, vector<int>(u));
        for (int i = 0; i < all_nums.size(); i++)
        {
            int x = all_nums[i];
            for (int j = 0; j < u; j++)
            {
                dp[i + 1][j] = dp[i][j]; // 不选 x
                for (int t = pos[x], lb; t; t ^= lb)
                {
                    lb = t & -t;       // lb = 1<<k,其中 k 是行号
                    if ((j & lb) == 0) // 没选过第 k 行的数
                    {
                        dp[i + 1][j] = max(dp[i + 1][j], dp[i][j | lb] + x); // 选第 k 行的 x
                    }
                }
            }
        }
        return dp.back()[0];
    }
};

结果:

在这里插入图片描述

复杂度分析:

时间复杂度:O(m * n * 2m),其中 m 和 n 分别为二维矩阵 grid 的行数和列数。

空间复杂度:O(m * n + 2m),其中 m 和 n 分别为二维矩阵 grid 的行数和列数。


http://www.kler.cn/a/303182.html

相关文章:

  • 网络原理-网络层和数据链路层
  • 给阿里云OSS绑定域名并启用SSL
  • SSE与WebSocket与MQTT
  • python习题练习
  • Javascript高级—常见算法
  • CentOS网络配置
  • CNN中的conv
  • ASP.net core 8.0网站发布
  • 房产销售系统|基于java和vue的房产销售系统(源码+数据库+文档)
  • 利用apache-pdfbox库修改pdf文件模板,进行信息替换
  • 【基础算法总结】二分查找
  • 在Python的Pandas库中,`df.iloc[::500]`是一个用于数据选择的索引器,它允许我们从DataFrame中选择特定的行和列。
  • golang学习笔记19——golang做服务发现与注册的深度剖析
  • 从安装ffmpeg开始,把一个视频按照每秒30帧fps剪切为图片
  • Vue组件:模板引用ref属性的使用
  • 微信小程序之轮播图组件封装
  • CTF常见编码及加解密(超全)第二篇
  • java程序员入行科目一之CRUD轻松入门教程(二)
  • layui监听table表单的多选框
  • 高级实时通信:基于 Python 的 WebSocket 实现与异步推送解决方案
  • 商务办公tips1:如何将网页转换为pdf
  • Python 数学建模——Vikor 多标准决策方法
  • 基于react native的锚点
  • 鼎捷新一代PLM 荣膺维科杯 “2023年度行业优秀产品奖”
  • 基于Service Worker实现WebRTC局域网大文件传输能力
  • C语言可变参数函数和可变参数宏