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

news/2024/11/28 13:47:02/

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-8row[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);  // 下一个位置是下一个不同的数,也就是kv.push_back(c[now]);  // 注意刚开始是选0个,因此先搜索完才选c[now]}for (int i = 0; i <= cnt && c[now] * i <= target; i++)v.pop_back();  // 还原现场}
};

http://www.ppmy.cn/news/1078745.html

相关文章

Deepin 图形化部署 Hadoop Single Node Cluster

Deepin 图形化部署 Hadoop Single Node Cluster 升级操作系统和软件 快捷键 ctrlaltt 打开控制台窗口 更新 apt 源 sudo apt update更新 系统和软件 sudo apt -y dist-upgrade升级后建议重启 开启ssh服务 打开资源管理器 进入系统盘 找到 etc 目录 在系统盘的 etc 目录上 右键…

Docsify + Gitalk详细配置过程讲解

&#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是Zeeland&#xff0c;开源建设者与全栈领域优质创作者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 我的博客&#xff1a;Zeeland&#x1f4da; Github主页: Undertone0809 (Zeeland)&…

IDEA设置文件编码

IDEA设置文件编码 File->Settings->Editor->File Encodings 均设置为utf-8 新项目 设置 文件编码 点击New Projects Setup 再点击Settings for New Projects File->Settings->Editor->File Encodings 均设置为utf-8

ssm学生公寓管理系统的设计与实现

ssm学生公寓管理系统的设计与实现106 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归…

初出茅庐的小李博客之STM32F103C8T6音乐控制器实战教程【1】

STM32F103C8T6音乐控制器实战教程[1] USB简单介绍&#xff1a; "USB"代表通用串行总线&#xff08;Universal Serial Bus&#xff09;&#xff0c;是一种用于连接计算机及其外部设备的标准接口。USB接口允许各种设备&#xff08;如打印机、存储设备、键盘、鼠标、摄…

7. Hive解析JSON字符串、JSON数组

文章目录 Hive解析JSON字符串1. get_json_object局限性 2. json_tuple Hive解析JSON数组前置知识explode函数regexp_replace函数 1. 嵌套子查询解析JSON数组&#xff08;使用exploderegexp_replace&#xff09;2. 使用 lateral view 解析JSON数组 学习链接 Hive解析JSON字符串 …

【Electron将HTML项目打包成桌面应用exe文件】

目标&#xff1a;前端将静态页面文件夹所有页面打包成一个exe文件&#xff08;不包含其它文件&#xff09;可运行。 步骤 1、初始化 npm init此时项目多出一个package.json文件。 {"name": "my-electron-app","version": "1.0.0",…

Typescript的class语法[类]的操作和应用

TypeScript 是一种面向对象的编程语言&#xff0c;它扩展了 JavaScript&#xff0c;为其添加了类型系统和其他一些特性。TypeScript 的 class 语法可以让开发者更加方便地使用面向对象的编程方式。本文将详细介绍 TypeScript 的 class 语法的操作和应用&#xff0c;并提供代码案…