【LeetCode算法系列题解】第36~40题

CONTENTS

    • LeetCode 36. 有效的数独(中等)
    • LeetCode 37. 解数独(困难)
    • LeetCode 38. 外观数列(中等)
    • LeetCode 39. 组合总和(中等)
    • LeetCode 40. 组合总和 II(中等)

LeetCode 36. 有效的数独(中等)

【题目描述】

请你判断一个 9 x 9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。

  • 数字 1-9 在每一行只能出现一次。
  • 数字 1-9 在每一列只能出现一次。
  • 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次(请参考示例图)。

注意:

  • 一个有效的数独(部分已被填充)不一定是可解的。
  • 只需要根据以上规则,验证已经填入的数字是否有效即可。
  • 空白格用 '.' 表示。

【示例1】

在这里插入图片描述

输入:board = 
[["5","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
输出:true

【示例2】

输入:board = 
[["8","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
输出:false
解释:除了第一行的第一个数字从 5 改为 8 以外,空格内其他数字均与 示例1 相同。 但由于位于左上角的 3x3 宫内有两个 8 存在, 因此这个数独是无效的。

【提示】

b o a r d . l e n g t h = = 9 board.length == 9 board.length==9
b o a r d [ i ] . l e n g t h = = 9 board[i].length == 9 board[i].length==9
board[i][j] 是一位数字(1-9)或者 '.'

【分析】


直接按题意模拟即可。


【代码】

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        bool st[10];
        for (int i = 0; i < 9; i++)
        {
            memset(st, false, sizeof st);
            for (int j = 0; j < 9; j++)
                if (board[i][j] == '.') continue;
                else if (st[board[i][j] - '0']) return false;
                else st[board[i][j] - '0'] = true;
        }
        for (int i = 0; i < 9; i++)
        {
            memset(st, false, sizeof st);
            for (int j = 0; j < 9; j++)
                if (board[j][i] == '.') continue;
                else if (st[board[j][i] - '0']) return false;
                else st[board[j][i] - '0'] = true;
        }
        for (int i = 0; i < 9; i += 3)  // 枚举每个3*3方格的左上角坐标
            for (int j = 0; j < 9; j += 3)
            {
                memset(st, false, sizeof st);
                for (int x = i; x < i + 3; x++)  // 枚举每个3*3方格中每个点的坐标
                    for (int y = j; y < j + 3; y++)
                        if (board[x][y] == '.') continue;
                        else if (st[board[x][y] - '0']) return false;
                        else st[board[x][y] - '0'] = true;
            }
        return true;
    }
};

LeetCode 37. 解数独(困难)

【题目描述】

编写一个程序,通过填充空格来解决数独问题。
数独的解法需遵循如下规则:

  • 数字 1-9 在每一行只能出现一次。
  • 数字 1-9 在每一列只能出现一次。
  • 数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次(请参考示例图)。

数独部分空格内已填入了数字,空白格用 '.' 表示。

【示例1】

在这里插入图片描述

输入:board = 
输入:board = [["5","3",".",".","7",".",".",".","."],["6",".",".","1","9","5",".",".","."],[".","9","8",".",".",".",".","6","."],["8",".",".",".","6",".",".",".","3"],["4",".",".","8",".","3",".",".","1"],["7",".",".",".","2",".",".",".","6"],[".","6",".",".",".",".","2","8","."],[".",".",".","4","1","9",".",".","5"],[".",".",".",".","8",".",".","7","9"]]
输出:[["5","3","4","6","7","8","9","1","2"],["6","7","2","1","9","5","3","4","8"],["1","9","8","3","4","2","5","6","7"],["8","5","9","7","6","1","4","2","3"],["4","2","6","8","5","3","7","9","1"],["7","1","3","9","2","4","8","5","6"],["9","6","1","5","3","7","2","8","4"],["2","8","7","4","1","9","6","3","5"],["3","4","5","2","8","6","1","7","9"]]

【提示】

b o a r d . l e n g t h = = 9 board.length == 9 board.length==9
b o a r d [ i ] . l e n g t h = = 9 board[i].length == 9 board[i].length==9
board[i][j] 是一位数字(1-9)或者 '.'
题目数据保证输入数独仅有一个解

【分析】


类似 N 皇后问题,爆搜每个位置可以填入的数,我们需要使用三个数组:row[i][x]col[i][x]cell[i][j][x],分别表示第 i i i 行(列)是否已经存在数字 x x x 以及第 i , j i,j i,j(左上角坐标)个3*3小方格是否已经存在数字 x x x


【代码】

class Solution {
public:
    bool row[9][9], col[9][9], cell[3][3][9];

    void solveSudoku(vector<vector<char>>& board) {
        memset(row, false, sizeof row);
        memset(col, false, sizeof col);
        memset(cell, false, sizeof cell);
        for (int i = 0; i < 9; i++)
            for (int j = 0; j < 9; j++)
                if (board[i][j] == '.') continue;
                else
                {
                    int t = board[i][j] - '1';  // 将'1'-'9'映射为0-8
                    row[i][t] = col[j][t] = cell[i / 3][j / 3][t] = true;
                }
        dfs(board, 0, 0);  // 从第0行第0列开始搜索
    }

    bool dfs(vector<vector<char>>& board, int x, int y)
    {
        if (x == 9) return true;  // 搜完了所有位置,找到解
        if (y == 9) return dfs(board, x + 1, 0);  // 搜完了一行,x加一y清零
        if (board[x][y] != '.') return dfs(board, x, y + 1);  // 该位置已经有数直接跳过
        for (int i = 0; i < 9; i++)
            if (!row[x][i] && !col[y][i] && !cell[x / 3][y / 3][i])
            {
                board[x][y] = i + '1';
                row[x][i] = col[y][i] = cell[x / 3][y / 3][i] = true;
                if (dfs(board, x, y + 1)) return true;  // 注意不能写return dfs(board, x, y + 1);
                board[x][y] = '.';  // 还原现场
                row[x][i] = col[y][i] = cell[x / 3][y / 3][i] = false;
            }
        return false;  // 该位置已经用完了所有数,返回false
    }
};

LeetCode 38. 外观数列(中等)

【题目描述】

给定一个正整数 n,输出外观数列的第 n 项。
外观数列是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。
你可以将其视作是由递归公式定义的数字字符串序列:

  • countAndSay(1) = "1"
  • countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串。

前五项如下:

1.     1
2.     11
3.     21
4.     1211
5.     111221
第一项是数字 1 
描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 "11"
描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 "21"
描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 "1211"
描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 "111221"

描述一个数字字符串,首先要将字符串分割为最小数量的组,每个组都由连续的最多相同字符组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。

例如,数字字符串 "3322251" 的描述如下图:

在这里插入图片描述

【示例1】

输入:n = 1
输出:"1"
解释:这是一个基本样例。

【示例2】

输入:n = 4
输出:"1211"
解释:
countAndSay(1) = "1"
countAndSay(2) = 读 "1" = 一 个 1 = "11"
countAndSay(3) = 读 "11" = 二 个 1 = "21"
countAndSay(4) = 读 "21" = 一 个 2 + 一 个 1 = "12" + "11" = "1211"

【提示】

1 ≤ n ≤ 30 1\le n\le 30 1n30

【分析】


直接按题意模拟即可。


【代码】

class Solution {
public:
    string countAndSay(int n) {
        string s = "1";  // 初始化
        for (int i = 0; i < n - 1; i++)  // 需要变换n-1次
        {
            string t;
            for (int j = 0, k; j < s.size(); j = k)
            {
                k = j + 1;
                while (k < s.size() && s[k] == s[k - 1]) k++;  // 找到第一个不同的数
                t += to_string(k - j) + s[j];  // 一共k-j个s[j]
            }
            s = t;
        }
        return s;
    }
};

LeetCode 39. 组合总和(中等)

【题目描述】

给你一个无重复元素的整数数组 candidates 和一个目标整数 target,找出 candidates 中可以使数字和为目标数 target所有不同组合 ,并以列表形式返回。你可以按任意顺序返回这些组合。
candidates 中的同一个数字可以无限制重复被选取。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。

【示例1】

输入:candidates = [2,3,6,7], target = 7
输出:[[2,2,3],[7]]
解释:
2 和 3 可以形成一组候选,2 + 2 + 3 = 7 。注意 2 可以使用多次。
7 也是一个候选, 7 = 7 。
仅有这两种组合。

【示例2】

输入: candidates = [2,3,5], target = 8
输出: [[2,2,2,2],[2,3,3],[3,5]]

【示例3】

输入: candidates = [2], target = 1
输出: []

【提示】

1 ≤ c a n d i d a t e s . l e n g t h ≤ 30 1\le candidates.length\le 30 1candidates.length30
2 ≤ c a n d i d a t e s [ i ] ≤ 40 2\le candidates[i]\le 40 2candidates[i]40
candidates 的所有元素互不相同
1 ≤ t a r g e t ≤ 40 1\le target\le 40 1target40

【分析】


本题要求出所有的方案,因此考虑可以使用爆搜。枚举每个数选不同的数量,若当前组合方案的和超过 target 了则直接剪枝。此外,由于相同的组合调换顺序不属于新的组合,因此爆搜的时候还需要保证顺序关系保证一种组合固定以一种顺序出现一次,而不会重复。


【代码】

class Solution {
public:
    vector<vector<int>> res;
    vector<int> v;

    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        dfs(candidates, 0, target);
        return res;
    }

    // now表示从第几个数开始选,因为序列不能重复,例如[2,2,3]和[2,3,2]是一样的
    // target每次减去选中的数,减为0说明找到和恰好为target的序列
    void dfs(vector<int>& c, int now, int target)
    {
        if (target <= 0)  // 剪枝
        {
            if (target == 0) res.push_back(v);  // 找到一个合法序列
            return;
        }
        for (int i = now; i < c.size(); i++)  // 每次dfs都可以选一次now
        {
            v.push_back(c[i]);
            dfs(c, i, target - c[i]);
            v.pop_back();  // 还原现场
        }
    }
};

LeetCode 40. 组合总和 II(中等)

【题目描述】

给定一个候选人编号的集合 candidates 和一个目标数 target,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次
注意:解集不能包含重复的组合。

【示例1】

输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

【示例2】

输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]

【提示】

1 ≤ c a n d i d a t e s . l e n g t h ≤ 100 1\le candidates.length\le 100 1candidates.length100
1 ≤ c a n d i d a t e s [ i ] ≤ 50 1\le candidates[i]\le 50 1candidates[i]50
1 ≤ t a r g e t ≤ 30 1\le target\le 30 1target30

【分析】


与上一题基本一样,唯一区别在于每个元素只能选一次,因此每个数能选择的次数的上限是固定的,我们可以先将数组排好序,搜索的时候每次先求出每个数出现的次数,然后枚举每个数选择的次数即可。


【代码】

class Solution {
public:
    vector<vector<int>> res;
    vector<int> v;

    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        dfs(candidates, 0, target);
        return res;
    }

    void dfs(vector<int>& c, int now, int target)
    {
        if (target == 0) { res.push_back(v); return; }
        if (now == c.size()) return;  // 已经遍历完所有数
        int k = now + 1;  // 找到第一个不相同数的下标
        while (k < c.size() && c[k] == c[now]) k++;
        int cnt = k - now;  // 一共有k-now个数相同
        for (int i = 0; i <= cnt && c[now] * i <= target; i++)  // 枚举c[now]选几个
        {
            dfs(c, k, target - c[now] * i);  // 下一个位置是下一个不同的数,也就是k
            v.push_back(c[now]);  // 注意刚开始是选0个,因此先搜索完才选c[now]
        }
        for (int i = 0; i <= cnt && c[now] * i <= target; i++)
            v.pop_back();  // 还原现场
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/99285.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[深度学习]1. 深度学习知识点汇总

本文记录了我在学习深度学习的过程中遇到过的不懂的知识点&#xff0c;为了方便翻阅&#xff0c;故将其发表于此&#xff0c;随时更新&#xff0c;供大家参考。 深度学习常见知识点 1. 测试精度和训练精度 在深度学习中&#xff0c;测试精度和训练精度是两个重要的指标&#…

基于空洞卷积DCNN与长短期时间记忆模型LSTM的dcnn-lstm的回归预测模型

周末的时候有时间鼓捣的一个小实践&#xff0c;主要就是做的多因子回归预测的任务&#xff0c;关于时序数据建模和回归预测建模我的专栏和系列博文里面已经有了非常详细的介绍了&#xff0c;这里就不再多加赘述了&#xff0c;这里主要是一个模型融合的实践&#xff0c;这里的数…

面试题——网络IO模型

一、socket socket是在应用层和传输层中间的抽象层&#xff0c;它把传输层&#xff08;TCP/UDP&#xff09;的复杂操作抽象成一些简单的接口&#xff0c;供应用层调用实现进程在网络中的通信。Socket起源于UNIX&#xff0c;在Unix一切皆文件的思想下&#xff0c;进程间通信就被…

【Tkinter界面:练习-01】窗口-部件-布局

一、说明 python在用户界面开发中&#xff0c;其中有QT5&#xff0c;和Tkinter&#xff1b;对于实际项目&#xff0c;界面需要高大上&#xff0c;因此用QT5&#xff0c;对于开发人员的演示程序&#xff0c;或简单程序中&#xff0c;不建议QT5&#xff1b;用Tkinter已经足够。本…

VMware Aria Operations SSH 身份验证绕过漏洞 (CVE-2023-34039)

zhi.oscs1024.com​​​​​ 漏洞类型身份验证不当发现时间2023-08-30漏洞等级严重MPS编号MPS-d9wr-56qmCVE编号CVE-2023-34039漏洞影响广度广 漏洞危害 OSCS 描述VMware Aria Operations for Networks 是 VMware 公司提供的一款网络可视性和分析工具&#xff0c;用于优化网络…

USB fastboot

1 Samsung fastboot flashing unlock 2 bootloader增加解锁密码 diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c index e4d46e4..1b4b450 100755 --- a/app/aboot/aboot.c b/app/aboot/aboot.c -2613,6 2613,20 void cmd_oem_unlock(const char *arg, void *data,…

群晖DS923+扩展ECC 64G内存

1 有必要上64G吗&#xff1f; 如果你不运行大型应用以及安装的套件不多&#xff0c;并且不使用虚拟机&#xff0c;确实没有太大必要。 但是大内存除了这些用处&#xff0c;还会被系统作为缓存使用。在资源监控中查看内存结构&#xff0c;虽然内存利用率只有4%&#xff0c;但缓存…

matlab 计算点云协方差矩阵

目录 一、概述1、算法概述2、主要函数二、代码示例三、结果展示四、参数解析输入参数输出参数五、参考链接本文由CSDN点云侠原创,原文链接。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、概述

科研无人机平台P600进阶版,突破科研难题!

随着无人机技术日益成熟&#xff0c;无人机的应用领域不断扩大&#xff0c;对无人机研发的需求也在不断增加。然而&#xff0c;许多开发人员面临着无法从零开始构建无人机的时间和精力压力&#xff0c;同时也缺乏适合的软件平台来支持他们的开发工作。为了解决这个问题&#xf…

Django实现音乐网站 ⒂

使用Python Django框架制作一个音乐网站&#xff0c; 本篇主要是歌手详情页-基本信息、单曲列表功能开发实现内容。 目录 歌手基本信息 增加路由 显示视图 模板显示 推荐歌手跳转详情 歌手增加基本信息 表模型增加字段 数据表更新 基本信息增加内容渲染 歌手单曲列表…

详解排序算法(附带Java/Python/Js源码)

冒泡算法 依次比较两个相邻的子元素&#xff0c;如果他们的顺序错误就把他们交换过来&#xff0c;重复地进行此过程直到没有相邻元素需要交换&#xff0c;即完成整个冒泡&#xff0c;时间复杂度。 比较相邻的元素。如果第一个比第二个大&#xff0c;就交换它们两个&#xff1b;…

RSA算法与错误敏感攻击

参见《RSA 算法的错误敏感攻击研究与实践》 RSA 算法简介 RSA 算法原理&#xff1a; 1&#xff09; RSA 算法密钥产生过程 &#xff08;1&#xff09;系统随机产生两个大素数 p p p 和 q q q&#xff0c;对这两个数据保密&#xff1b; &#xff08;2&#xff09;计算 n p …

springboot集成es 插入和查询的简单使用

第一步&#xff1a;引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId><version>2.2.5.RELEASE</version></dependency>第二步&#xff1a;…

uniapp微信小程序使用stomp.js实现STOMP传输协议的实时聊天

简介&#xff1a; 原生微信小程序中使用 本来使用websocket&#xff0c;后端同事使用了stomp协议&#xff0c;导致前端也需要对应修改。 如何使用 1.yarn add stompjs 2.版本 “stompjs”: “^2.3.3” 3.在static/js中新建stomp.js和websocket.js&#xff0c;然后在需要使用…

Nginx详解 三:高级配置

文章目录 1. 网页的状态页2. Nginx第三方模块2.1 echo模块 3. 变量3.1 内置变量3.1.1 示例 3.2 自定义变量3.2.1 自定义访问日志3.2.2 自定义json 格式日志 3.4 Nginx压缩功能 4. HTTPS4.1 Nginx的HTTPS工作原理4.2 启用功能模块的配置过程 5、自定义图标 1. 网页的状态页 基于…

深度学习在自然语言处理中的十大应用领域

文章目录 1. 机器翻译2. 文本分类3. 命名实体识别4. 问答系统5. 文本生成6. 情感分析7. 语言生成与处理8. 信息检索与摘要9. 文本纠错与修复10. 智能对话系统总结 &#x1f389;欢迎来到AIGC人工智能专栏~深度学习在自然语言处理中的十大应用领域 ☆* o(≧▽≦)o *☆嗨~我是IT陈…

【Kali Linux高级渗透测试】深入剖析Kali Linux:高级渗透测试技术与实践

&#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff0c;喜爱音乐的一位博主。 &#x1f4d7;本文收录于恒川的日常汇报系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏C语言初阶、C…

NPM 常用命令(一)

目录 1、npm 1.1 简介 1.2 依赖性 1.3 安装方式 2、npm access 2.1 命令描述 2.2 详情 3、npm adduser 3.1 描述 4、npm audit 4.1 简介 4.2 审计签名 4.3 操作示例 4.4 配置 audit-level dry-run force json package-lock-only omit foreground-scripts …

Ubuntu 下安装Qt5.12.12无法输入中文解决方法

Ubuntu 下安装Qt5.12.12无法输入中文解决方法 一&#xff0c;环境&#xff1a; &#xff08;1&#xff09;VMware Workstation 15 Pro &#xff08;2&#xff09;Ubuntu 20.04 &#xff08;3&#xff09;Qt 5.12.12 64bits &#xff08;4&#xff09;Qt Creator 5.0.2 &#…

浅析Redis(1)

一.Redis的含义 Redis可以用来作数据库&#xff0c;缓存&#xff0c;流引擎&#xff0c;消息队列。redis只有在分布式系统中才能充分的发挥作用&#xff0c;如果是单机程序&#xff0c;直接通过变量来存储数据是更优的选择。那我们知道进程之间是有隔离性的&#xff0c;那么re…