8月3日 415. 字符串相加(简单)
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和。
注意:
1 | num1 和num2 的长度都小于 5100. |
题解:
两个数字位数不同时,在指针当前下标处于负数的时候返回 0,等价于对位数较短的数字进行了补零操作,这样就可以除去两个数字位数不同情况的处理。
1 | string addStrings(string num1, string num2){ |
时间复杂度:O(max{n1,n2})
空间复杂度:O(1)
8月4日 207. 课程表(中等)
你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
示例 1:
1 | 输入: 2, [[1,0]] |
示例 2:
1 | 输入: 2, [[1,0],[0,1]] |
提示:
1 | 输入的先决条件是由 边缘列表 表示的图形,而不是 邻接矩阵 。详情请参见图的表示法。 |
题解:
- 有向图的dfs遍历。
visited[i]
表示第i和节点的状态,0表示没有被访问过,1表示正在被访问,2表示访问结束的节点。circle
表示有向图有环。使用dfs遍历有向图:
- 当正在访问的节点(visited[i]=1)又被访问时,说明有向图存在环,返回false。
- 全部节点访问完毕,返回true时间复杂度:O(m+n)。m是有向图的边,n是有向图的节点。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32void dfs(int u, vector<vector<int> > &graph, vector<int> &visited){
visited[u] = 1;//正在访问该节点
for(int v:graph[u]){
if(visited[v]==0){
dfs(v, graph, visited);
if(circle)
return;
}else if(visited[v]==1){
circle = true;
return;
}
}
visited[u] = 2;
}
bool canFinish(int numCourses, vector<vector<int> >& prerequisites) {
if(prerequisites.empty())
return true;
vector<vector<int> > graph(numCourses);
for (auto course : prerequisites)
{//build graph
graph[course[1]].push_back(course[0]);
}
vector<int> visited(numCourses);
for (int i = 0; i < numCourses && !circle; i++)
{
if(!visited[i])
dfs(i, graph, visited);
}
return !circle;
}
空间复杂度:O(m+n)
- bfs入度为0的点
拓扑排序中,起点都是入度为0的点。把所有入度为0的节点放入队列,依次访问队列中的节点。访问的时候把所有从该节点出去的边都删掉,即该节点出发连接的边的入度都减1。再把入度减到0的点加入队列。时间复杂度:O(m+n)。m是有向图的边,n是有向图的节点。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32bool canFinish(int numCourses, vector<vector<int> >& prerequisites) {
if(prerequisites.empty())
return true;
vector<vector<int> > graph(numCourses);
vector<int> inDegree(numCourses, 0);
for (auto course : prerequisites)
{//build graph
graph[course[1]].push_back(course[0]);
inDegree[course[0]]++;
}
queue<int> que;
for (int i = 0; i < numCourses;i++)
{
if(inDegree[i]==0)
que.push(i);
}
int visited = 0;
while (!que.empty())
{
visited++;
int u = que.front();
que.pop();
for(int v:graph[u]){
inDegree[v]--;
if(inDegree[v]==0)
que.push(v);
}
}
return visited == numCourses;
}
空间复杂度:O(m+n)
真题
模版匹配
前面给一个词做模版,看后面的多个词是否能和前面的模版匹配。
示例1:
1 | 输入:pattern = "noon", str = "big star star big" |
示例2:
1 | 输入:pattern = "noon", str = "big star star not" |
题解:
1 | bool testMatch(string pattern, string str) { |
找到最小的排列组合数
找到比原数字位数排列组合后,比原数字大的,最小的数。没有就输出-1
1 | //80% 比如 2231就不对了 |
1477. 找两个和为目标值且不重叠的子数组
给你一个整数数组 arr 和一个整数值 target。
请你在 arr 中找两个互不重叠的子数组 且它们的和都等于 target。可能会有多种方案,请你返回满足要求的两个子数组长度和的 最小值 。
请返回满足要求的最小长度和,如果无法找到这样的两个子数组,请返回 -1 。
题解:dp[i]
表示i后面和等T的最小子数组长度
1 | int minSumOfLengths(vector<int>& arr, int target){ |
16进制和10进制的互转
1 | string convert_10_to_16(int num) |
8月10日 696. 计数二进制子串
给定一个字符串 s,计算具有相同数量0和1的非空(连续)子字符串的数量,并且这些子字符串中的所有0和所有1都是组合在一起的。
重复出现的子串要计算它们出现的次数。
示例 1 :
1 | 输入: "00110011" |
示例 2 :
1 | 输入: "10101" |
注意:
1 | s.length 在1到50,000之间。 |
题解:
把每个相同的字符分组,比如“00111011” 就可以分为subs={2,3,1,2},表示2个0,3个1,1个0,2个1。每一对相邻的能有min{subs[i],subs[i+1]}个字串。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18int countBinarySubstrings(string s) {
vector<int> subs;
int i = 0;
while(i<s.size()){
int mark = i;
char cur = s[i];
while(i<s.size() && s[i]==cur)
i++;
subs.push_back(i-mark);
}
int res = 0;
for(int i = 0;i<subs.size()-1;i++){
res += min(subs[i],subs[i+1]);
}
return res;
}时间复杂度:O(n)
空间复杂度:O(n)优化。空间复杂度优化到O(1)。也只用到subs的上一个状态量,所以可以不用保存整个subs数组。
1
(代码略)
8月11日 130. 被围绕的区域(中等)
给定一个二维的矩阵,包含 ‘X’ 和 ‘O’(字母 O)。
找到所有被 ‘X’ 围绕的区域,并将这些区域里所有的 ‘O’ 用 ‘X’ 填充。
示例:
1 | X X X X |
解释:
被围绕的区间不会存在于边界上,换句话说,任何边界上的 ‘O’ 都不会被填充为 ‘X’。 任何不在边界上,或不与边界上的 ‘O’ 相连的 ‘O’ 最终都会被填充为 ‘X’。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。
题解:
dfs。也可以用bfs,但是需要自己用队列实现,还是递归方便一点。
1 | vector<vector<int> > dirs = {{1,0},{-1,0},{0,1},{0,-1}}; |
时间复杂度:O(mn)
空间复杂度:O(mn)
8月12日 133. 克隆图(中等)
给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。
1 | class Node { |
题解:
bfs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33Node* cloneGraph(Node* node) {
if (node == nullptr) {
return node;
}
unordered_map<Node*, Node*> visited;
// 将题目给定的节点添加到队列
queue<Node*> que;
que.push(node);
// 克隆第一个节点并存储到哈希表中
visited[node] = new Node(node->val);
// 广度优先搜索
while (!que.empty()) {
// 取出队列的头节点
auto curNode = que.front();
que.pop();
// 遍历该节点的邻居
for (auto& neighbor: curNode->neighbors) {
if (visited.find(neighbor) == visited.end()) {
// 如果没有被访问过,就克隆并存储在哈希表中
visited[neighbor] = new Node(neighbor->val);
// 将邻居节点加入队列中
que.push(neighbor);
}
// 更新当前节点的邻居列表
visited[curNode]->neighbors.emplace_back(visited[neighbor]);
}
}
return visited[node];
}时间复杂度:O(n)
空间复杂度:O(n)dfs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19unordered_map<Node*, Node*> visited;
Node* cloneGraph(Node* node) {
if (node == nullptr) {
return node;
}
if(visited.find(node) != visited.end())
return visited[node];
Node *cloneNode = new Node(node->val);
visited[node] = cloneNode;
for(auto &neighbor:node->neighbors){
cloneNode->neighbors.push_back(cloneGraph(neighbor));
}
return visited[node];
}时间复杂度:O(n)
空间复杂度:O(n)
8月13日 43. 字符串相乘(中等)
给定两个以字符串形式表示的非负整数 num1 和 num2,返回 num1 和 num2 的乘积,它们的乘积也表示为字符串形式。
示例 1:
1 | 输入: num1 = "2", num2 = "3" |
示例 2:
1 | 输入: num1 = "123", num2 = "456" |
说明:
1 | num1 和 num2 的长度小于110。 |
题解:
大数相乘问题。
1 | string multiply(string num1, string num2){ |
时间复杂度:O(m*n)
空间复杂度:O(m+n)
8月19日 647. 回文子串(中等)
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。
具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。
示例 1:
1 | 输入:"abc" |
示例 2:
1 | 输入:"aaa" |
题解:
枚举每一个字串,再判断是不是回文。
1 | bool isPalindrome(string str){ |
时间复杂度:O(n^2)
空间复杂度:O(1)
8月20日 529. 扫雷游戏(中等)
让我们一起来玩扫雷游戏!
给定一个代表游戏板的二维字符矩阵。 ‘M’ 代表一个未挖出的地雷,’E’ 代表一个未挖出的空方块,’B’ 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的已挖出的空白方块,数字(’1’ 到 ‘8’)表示有多少地雷与这块已挖出的方块相邻,’X’ 则表示一个已挖出的地雷。
现在给出在所有未挖出的方块中(’M’或者’E’)的下一个点击位置(行和列索引),根据以下规则,返回相应位置被点击后对应的面板:
如果一个地雷(’M’)被挖出,游戏就结束了- 把它改为 ‘X’。
如果一个没有相邻地雷的空方块(’E’)被挖出,修改它为(’B’),并且所有和其相邻的未挖出方块都应该被递归地揭露。
如果一个至少与一个地雷相邻的空方块(’E’)被挖出,修改它为数字(’1’到’8’),表示相邻地雷的数量。
如果在此次点击中,若无更多方块可被揭露,则返回面板。
示例 1:
1 | 输入: |
示例 2:
1 | 输入: |
题解:
dfs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49vector<vector<int> > dirs = {{0,1},{0,-1},{1,0},{-1,0},{1,1},{-1,-1},{1,-1},{-1,1}};
void dfs(vector<vector<char> > &res, int row, int col, vector<vector<bool> > &hasVisited){
if(hasVisited[row][col])
return;
//处理当前格子
int boom = 0;
for(auto d:dirs){
int next_i=row+d[0];
int next_j=col+d[1];
if(next_i < 0 || next_i >= res.size() || next_j < 0 || next_j >= res[0].size())
continue;
if(res[next_i][next_j]=='M')
boom++;
}
hasVisited[row][col] = true;
if(boom==0)
res[row][col] = 'B';
else{
res[row][col] = to_string(boom)[0];
// res[cur_i][cur_j] = boom + '0';
return;
}
//处理下一个格子
for(auto d:dirs){
int next_i=row+d[0];
int next_j=col+d[1];
if(next_i < 0 || next_i >= res.size() || next_j < 0 || next_j >= res[0].size())
continue;
dfs(res,next_i,next_j,hasVisited);
}
}
vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
if(board.empty())
return board;
int row = click[0],col=click[1];
vector<vector<char> > res = board;
if(board[row][col]=='M'){
res[row][col] = 'X';
return res;
}
vector<vector<bool> > hasVisited(board.size(), vector<bool>(board[0].size(),false));
dfs(res,row,col,hasVisited);
return res;
}时间复杂度:O(mn)
空间复杂度:O(mn)bfs。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58vector<vector<int> > dirs = {{0,1},{0,-1},{1,0},{-1,0},{1,1},{-1,-1},{1,-1},{-1,1}};
void bfs(vector<vector<char> > &res, int row, int col, vector<vector<bool> > &hasVisited){
queue<vector<int> > que;
que.push({row,col});
hasVisited[row][col] = true;
while(!que.empty()){
int sizeq = que.size();
while(sizeq-->0){
int cur_i = que.front()[0];
int cur_j = que.front()[1];
que.pop();
int boom = 0;
for(auto d:dirs){
int next_i=cur_i+d[0];
int next_j=cur_j+d[1];
if(next_i < 0 || next_i >= res.size() || next_j < 0 || next_j >= res[0].size())
continue;
if(res[next_i][next_j]=='M')
boom++;
}
if(boom==0){
//处理当前格子
res[cur_i][cur_j] = 'B';
//下一个格子
for(auto d:dirs){
int next_i=cur_i+d[0];
int next_j=cur_j+d[1];
if(next_i < 0 || next_i >= res.size() || next_j < 0 || next_j >= res[0].size()
|| hasVisited[next_i][next_j])
continue;
if(res[next_i][next_j]=='E'){
que.push({next_i,next_j});
hasVisited[next_i][next_j] = true;
}
}
}
else
res[cur_i][cur_j] = to_string(boom)[0];
}
}
}
vector<vector<char> > updateBoard(vector<vector<char> >& board, vector<int>& click) {
if(board.empty())
return board;
int row = click[0],col=click[1];
vector<vector<char> > res = board;
if(board[row][col]=='M'){
res[row][col] = 'X';
return res;
}
vector<vector<bool> > hasVisited(board.size(), vector<bool>(board[0].size(),false));
bfs(res,row,col,hasVisited);
return res;
}时间复杂度:O(mn)
空间复杂度:O(mn)
元素平衡
A,B,C,D四个数,每次可以任意减少2个单位然后增加1各单位,问当四个数相等时,最大和为多少。
题解:
笔试真题。
1 | int main(){ |