算法部分
1.Acwing 入门组每日一题
题目:数独检查
数独是一种流行的单人游戏。目标是用数字填充9x9矩阵,使每列,每行和所有9个非重叠的3x3子矩阵包含从1到9的所有数字。每个9x9矩阵在游戏开始时都会有部分数字已经给出,通常有一个独特的解决方案。
给定完成的N2∗N2数独矩阵,你的任务是确定它是否是有效的解决方案。有效的解决方案必须满足以下条件:
每行包含从1到N2的每个数字,每个数字一次。
每列包含从1到N2的每个数字,每个数字一次。
将N2∗N2矩阵划分为N2个非重叠N∗N子矩阵。 每个子矩阵包含从1到N2的每个数字,每个数字一次。
你无需担心问题的唯一性,只需检查给定矩阵是否是有效的解决方案即可。
输入格式
第一行包含整数T,表示共有T组测试数据。
每组数据第一行包含整数N。
接下来N2行,每行包含N2个数字(均不超过1000),用来描述完整的数独矩阵。
输出格式
每组数据输出一个结果,每个结果占一行。
结果表示为“Case #x: y”,其中x是组别编号(从1开始),如果给定矩阵是有效方案则y是Yes,否则y是No。
数据范围
1≤T≤100,
3≤N≤6
输入样例:
3
3
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
3
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
3
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 999 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
输出样例:
Case #1: Yes
Case #2: No
Case #3: No
题解:
依次检查每行、每列、每个小九宫格是否满足条件,使用 bool 数组 记录元素的出现情况。
代码:
#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 50;
bool vis[MAXN][MAXN];
int g[MAXN][MAXN];
void check(int r, int c, bool &op, int cnt, int size){
for(int i = r; i < r + size; i ++)
for(int j = c; j < c + size; j ++){
if(vis[cnt][g[i][j]])
op = false;
vis[cnt][g[i][j]] = true;
}
}
int main(){
int n;
cin >> n;
for(int i = 1; i <= n; i ++){
bool op = true;
int size;
cin >> size;
for(int i = 0; i < size * size; i ++)
for(int j = 0; j < size *size; j ++){
cin >> g[i][j];
if(g[i][j] < 1 || g[i][j] > size * size)
op = false;
}
//检查行
memset(vis, false, sizeof(vis));
for(int i = 0; i < size * size && op; i ++)
for(int j = 0; j < size * size && op; j ++){
if(vis[i][g[i][j]])
op = false;
vis[i][g[i][j]] = true;
}
//检查列
memset(vis, false, sizeof(vis));
for(int i = 0; i < size * size && op; i ++)
for(int j = 0; j < size * size && op; j ++){
if(vis[i][g[j][i]])
op = false;
vis[i][g[j][i]] = true;
}
//检查 size * size 个子矩阵
int cnt = 0;
memset(vis, false, sizeof(vis));
for(int i = 0; i < size && op; i ++)
for(int j = 0; j < size && op; j ++)
check(i * size, j * size, op, cnt, size), cnt ++;
if(op)
cout << "Case #" << i << ": Yes" << endl;
else
cout << "Case #" << i << ": No" << endl;
}
return 0;
}
2.Acwing 提高组每日一题
题目:数独简单版
数独是一种传统益智游戏,你需要把一个 9×9 的数独补充完整,使得图中每行、每列、每个 3×3 的九宫格内数字 1∼9 均恰好出现一次。请编写一个程序填写数独。
输入格式
输入共 9 行,每行包含一个长度为 9 的字符串,用来表示数独矩阵。
其中的每个字符都是 1∼9 或 .(表示尚未填充)。
输出格式
输出补全后的数独矩阵。
数据保证有唯一解。
输入样例:
.2738…1.
.1…6735
…29
3.5692.8.
…
.6.1745.3
64…
9518…7.
.8…6534.
输出样例:
527389416
819426735
436751829
375692184
194538267
268174593
643217958
951843672
782965341
题解:
dfs深搜求解,注意剪枝,也就是考虑这一行、这一列以及小九宫格数字的出现情况,需要数组记录。此外,把二维坐标映射到一维,使用公式 r * 边长 + c 即可将二维坐标映射到一维,而且没有冲突。
#include <iostream>
using namespace std;
const int MAXN = 10;
char g[MAXN][MAXN];
bool hang[MAXN][MAXN], lie[MAXN][MAXN], sub[MAXN][MAXN];
void dfs(int le){
//递归出口
if(le == 81){
for(int i = 0; i < 9; i ++)
cout << g[i] << endl;
return ;
}
//从一维坐标得到行和列
int r = le / 9;
int c = le % 9;
//已经摆好了,则进行下一层递归
if(g[r][c] != '.'){
dfs(le + 1);
return;
}
//有1 - 9 种放法
for(int i = 1; i <= 9; i ++){
if(hang[r][i] || lie[c][i] || sub[(r / 3) * 3 + c / 3][i])
continue;
g[r][c] = i + '0';
hang[r][i] = true;
lie[c][i] = true;
sub[(r / 3) * 3 + c / 3][i] = true;
dfs(le + 1);
//回溯之后恢复现场
hang[r][i] = false;
lie[c][i] = false;
sub[(r / 3) * 3 + c / 3][i] = false;
g[r][c] = '.';
}
}
int main(){
for(int i = 0; i < 9; i ++)
cin >> g[i];
//预处理 行、列小九宫格信息
for(int i = 0; i < 9; i ++)
for(int j = 0; j < 9; j ++){
if(g[i][j] != '.'){
hang[i][g[i][j] - '0'] = true;
lie[j][g[i][j] - '0'] = true;
sub[(i / 3) * 3 + j / 3][g[i][j] - '0'] = true;
}
}
dfs(0);
return 0;
}
3.LeetCode 每日一题
题目:替换后的最长重复字符
给你一个仅由大写英文字母组成的字符串,你可以将任意位置上的字符替换成另外的字符,总共可最多替换 k 次。在执行上述操作后,找到包含重复字母的最长子串的长度。
注意:字符串长度 和 k 不会超过 104。
示例 1:
输入:s = “ABAB”, k = 2
输出:4
解释:用两个’A’替换为两个’B’,反之亦然。
示例 2:
输入:s = “AABABBA”, k = 1
输出:4
解释:
将中间的一个’A’替换为’B’,字符串变为 “AABBBBA”。
子串 “BBBB” 有最长重复字母, 答案为 4。
题解:
将题目抽象为维护一个区间,当满足条件就扩大这个区间,否则缩小区间,在这个头尾扩展的过程中维护最大值,一个区间满足能满足转变为同一字符的条件是 区间长度 <= K + 区间内最大的同一字符出现次数,因为只需要把其他字符都转变为那个出现次数最多的字符即可。
class Solution {
public:
int characterReplacement(string s, int k) {
int res = 0, le = 0, ri = 0, ans = 0;
vector<int> cnt(26, 0);
while(ri < s.length()){
cnt[s[ri] - 'A'] ++;
//更新历史最大单字符出现次数
res = max(res, cnt[s[ri] - 'A']);
//判断是否满足条件
if(ri - le + 1 - k > res){
//不满足,则需要移动头指针,同时将头指针对应的字符出现次数 -1
cnt[s[le] - 'A'] --;
++ le;
}
++ ri;
}
return ri - le;
}
};
4.春招冲刺 - 从前序与中序遍历序列构造二叉树
题目:
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
题解:
经典的数据结构题,做完本题可以尝试根据后序和中序遍历构造二叉树。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
//key: value of node | value : index in inorder traversal
unordered_map<int, int> map;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
int cur = 0;
for(int i = 0; i < inorder.size(); i ++)
map[inorder[i]] = i;
return dfs(preorder, cur, inorder, 0, preorder.size() - 1);
}
TreeNode *dfs(vector<int> &pre, int &cur, vector<int> &in, int le, int ri){
if(le > ri)
return nullptr;
//使用map能提高效率,mid为中序遍历对应的下标
int mid = map[pre[cur]];
// for(int i = le; i <= ri; i ++)
// if(pre[cur] == in[i]){
// mid = i;
// break;
// }
TreeNode *root = new TreeNode(pre[cur]);
++ cur;
//递归求左子树和右子树
root -> left = dfs(pre, cur, in, le, mid - 1);
root -> right = dfs(pre, cur, in, mid + 1, ri);
return root;
}
};
5.春招冲刺 - 阶乘后的零
题目:
给定一个整数 n,返回 n! 结果尾数中零的数量。
示例 1:
输入: 3
输出: 0
解释: 3! = 6, 尾数中没有零。
示例 2:
输入: 5
输出: 1
解释: 5! = 120, 尾数中有 1 个零.
说明: 你算法的时间复杂度应为 O(log n) 。
题解:
细细品下面的代码,作为校招面试题也不错哦 ><

class Solution {
public:
int trailingZeroes(int n) {
int ans = 0;
for(int i = 5; i <= n; i *= 5){
ans += n /i;
}
return ans;
}
};
书籍部分
图解TCP|IP 第2章 ✔
MYSQL必知必会 第9 - 12章 ✔
PS.
- 明天看一下markdown语法
- 有时间看一下闫氏dp分析法,做一下总结