这次只有两题,也不是我不想放三题,我目前刷的那部分就剩这两题了,而且作为压轴,也不会简单。
看题目就吓人。
哦,原来是中等难度啊。
1、题目1
判断一个 9x9 的数独是否有效。只需要根据以下规则,验证已经填入的数字是否有效即可。
数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。
数独部分空格内已填入了数字,空白格用 ‘.’ 表示。
示例 1:
输入:
[
[“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:
输入:
[
[“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 存在, 因此这个数独是无效的。
说明:
一个有效的数独(部分已被填充)不一定是可解的。
只需要根据以上规则,验证已经填入的数字是否有效即可。
给定数独序列只包含数字 1-9 和字符 ‘.’ 。
给定数独永远是 9x9 形式的。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/valid-sudoku
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2、题目2
给定一个 n × n 的二维矩阵表示一个图像。
将图像顺时针旋转 90 度。
说明:
你必须在原地旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要使用另一个矩阵来旋转图像。
示例 1:
给定 matrix =
[
[1,2,3],
[4,5,6],
[7,8,9]
],
原地旋转输入矩阵,使其变为:
[
[7,4,1],
[8,5,2],
[9,6,3]
]
示例 2:
给定 matrix =
[
[ 5, 1, 9,11],
[ 2, 4, 8,10],
[13, 3, 6, 7],
[15,14,12,16]
],
原地旋转输入矩阵,使其变为:
[
[15,13, 2, 5],
[14, 3, 4, 1],
[12, 6, 8, 9],
[16, 7,10,11]
]
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/rotate-image
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
3、我的题解(1)
这题,我做的还是比较满意的。
怎么说呢,最近总是有一个解题方法在我眼前出现,用map键值对来记录遍历的数据,于是我就抓住了这个解法,自主实现!
还别说,真好用。我的好兄弟他去暴力破解了,果然中午崩溃的跟我说他放弃了。
来看一下我的思维导图:
#include<vector>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;
bool isValidSudoku(vector<vector<char> >& board)
{
char ai;
//创建键值对表及其初始化
map<char, int> ID_Num;
ID_Num['1'] = 0;
ID_Num['2'] = 0;
ID_Num['3'] = 0;
ID_Num['4'] = 0;
ID_Num['5'] = 0;
ID_Num['6'] = 0;
ID_Num['7'] = 0;
ID_Num['8'] = 0;
ID_Num['9'] = 0;
map<char, int>::iterator it;
//将横的先输入
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
ai = board[i].at(j);
if (ai >= 49 && ai <= 57)
{
ID_Num[ai]++;
}
}
//走过一轮,该遍历map了
for (it = ID_Num.begin(); it != ID_Num.end(); it++)
{
if (it->second == 1)
it->second = 0;
else if (it->second > 1)
return false;
}
}
//接下来竖着走
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
ai = board[j].at(i);
if (ai >= 49 && ai <= 57)
{
ID_Num[ai]++;
}
}
//走过一轮,该遍历map了
for (it = ID_Num.begin(); it != ID_Num.end(); it++)
{
if (it->second == 1)
it->second = 0;
else if (it->second > 1)
return false;
}
}
//接下来走方块
for (int i = 0; i < 9; i += 3)
{
for (int j = 0; j < 9; j++)
{
ai = board[i].at(j);
if (ai >= 49 && ai <= 57)
{
ID_Num[ai]++;
}
ai = board[i + 1].at(j);
if (ai >= 49 && ai <= 57)
{
ID_Num[ai]++;
}
ai = board[i + 2].at(j);
if (ai >= 49 && ai <= 57)
{
ID_Num[ai]++;
}
if (j == 2 || j == 5 || j == 8)
{
//走过一轮,该遍历map了
for (it = ID_Num.begin(); it != ID_Num.end(); it++)
{
if (it->second == 1)
it->second = 0;
else if (it->second > 1)
return false;
}
}
}
}
return true;
}
int main()
{
vector<vector<char> > vec1 = { {'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' }};
int b = isValidSudoku(vec1);
cout << b << endl;
};
//测试集我就放这里了
这里要提一点,用map的 at() 进行操作时,如果键值不存在,会自动插入一个键值。
其实里面很多操作都是重复的,可以单独提出来当函数。
4、我的题解(2)
本来呢,我是想用hashtable哈希表的,但是呢,弄了仨儿小时找不到资料,所以决定换条路走。
来看我的画图水平啊。
还挺形象生动吧。
#include<iostream>
#include<vector>
using namespace std;
void rotate(vector<vector<int>>& matrix)
{
int sz = matrix[0].size();
int cycle_num = sz/2; //圈数,sz为奇数则最后一圈不用转
// vector<int> glob(sz); //原来这个才是内鬼
vector<int> glob;
int j; //下面转圈的核心
//这里是循环主体
for (int i = 0; i < cycle_num; i++)
{
//将当前圈的首尾记录
int low = i;
int hight = sz - i - 1;
//将上面那一行先弄上去
// glob.insert(glob.begin(),matrix[i].at(i),matrix[low].at(hight));
int gn = hight+1; //对于处理内圈,这行不能写成size
while (gn)
{
glob.push_back(matrix[low][gn-1]);
gn--;
}
//抓住定量,转一圈
for (j = 0;low<hight;low++,j++)
{
//用左边那一列填上上面那一行
matrix[i].at(hight-j) = matrix[low].at(i);
//再用下面那一行实时填上左边那一列
matrix[low].at(i) = matrix[hight].at(low);
//然后把右边那一列一到下面
matrix[hight].at(low) = matrix[hight-j].at(hight);
//最后把通用容器里面的东西放到右边那一列
matrix[hight - j].at(hight) = glob.at(j);
}
//一圈之后,清空通用容器,准备接下一圈
glob.clear();
}
}
int main()
{
vector<vector<int>> vec1 = { {5, 1, 9, 11}, {2, 4, 8, 10}, {13, 3, 6, 7}, {5, 14, 12, 16} };
//vector<vector<int>> vec1 = { { 4, 8}, {3, 6} };
rotate(vec1);
return 0;
}
//测试集也给你放这里了,不过遍历打印自己弄
5、官方题解(1)
方法:一次迭代
如何确保行 / 列 / 子数独中没有重复项?
可以利用 value -> count 哈希映射来跟踪所有已经遇到的值。
现在,我们完成了这个算法的所有准备工作:
遍历数独。
检查看到每个单元格值是否已经在当前的行 / 列 / 子数独中出现过:
如果出现重复,返回 false。
如果没有,则保留此值以进行进一步跟踪。
返回 true。
class Solution {
public boolean isValidSudoku(char[][] board) {
// init data
HashMap<Integer, Integer> [] rows = new HashMap[9];
HashMap<Integer, Integer> [] columns = new HashMap[9];
HashMap<Integer, Integer> [] boxes = new HashMap[9];
for (int i = 0; i < 9; i++) {
rows[i] = new HashMap<Integer, Integer>();
columns[i] = new HashMap<Integer, Integer>();
boxes[i] = new HashMap<Integer, Integer>();
}
// validate a board
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
char num = board[i][j];
if (num != '.') {
int n = (int)num;
int box_index = (i / 3 ) * 3 + j / 3;
// keep the current cell value
rows[i].put(n, rows[i].getOrDefault(n, 0) + 1);
columns[j].put(n, columns[j].getOrDefault(n, 0) + 1);
boxes[box_index].put(n, boxes[box_index].getOrDefault(n, 0) + 1);
// check if this value has been already seen before
if (rows[i].get(n) > 1 || columns[j].get(n) > 1 || boxes[box_index].get(n) > 1)
return false;
}
}
}
return true;
}
}
> 作者:LeetCode
> 链接:https://leetcode-cn.com/problems/valid-sudoku/solution/you-xiao-de-shu-du-by-leetcode/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
时间复杂度:O(1),因为我们只对 81 个单元格进行了一次迭代。
空间复杂度:O(1)。
方法是很不错的
然后评论区里又有大佬说直接用数组不香吗?
我觉得吧,至少我掌握了用映射表这个方法,而且如果这个数组大起来的话,孰优孰劣真不好说哦,数组坑定得淘汰了。
6、官方题解(2)
还真别说,这个图画的真不错。
那这个方法就不说了,跟我的一样。来看另一个,大佬们都说妙的。
方法 1 :转置加翻转
最直接的想法是先转置矩阵,然后翻转每一行。这个简单的方法已经能达到最优的时间复杂度O(N^2)
反正我是没直接想到。
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
// transpose matrix
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
int tmp = matrix[j][i];
matrix[j][i] = matrix[i][j];
matrix[i][j] = tmp;
}
}
// reverse each row
for (int i = 0; i < n; i++) {
for (int j = 0; j < n / 2; j++) {
int tmp = matrix[i][j];
matrix[i][j] = matrix[i][n - j - 1];
matrix[i][n - j - 1] = tmp;
}
}
}
}
> 作者:LeetCode
> 链接:https://leetcode-cn.com/problems/rotate-image/solution/xuan-zhuan-tu-xiang-by-leetcode/
> 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
7、总结
这两题做完,映射表的使用是得刻骨铭心了。
哈希散列表嘛,还得再看看。
不过数组这一套做下来,我深刻认识到,在写代码之前,得把思维导图画出来!!!