阿里暑期实习笔试题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
阿⾥暑期实习笔试题
阿⾥暑期实习笔试题
阿⾥暑期实习的笔试,3⽉6⽇的第⼀场据说⽐较难,两道 leetcode hard题。
3.9 更新
找到问题了,问题出在auto&& [stop, step] = q.front(); q.pop();这两句上,我们使⽤的是⼀个引⽤,但是后来这个元素被 pop 释放掉了,所以会报内存错误。
使⽤auto& [stop, step]也会出错,因为也是引⽤类型;只有使⽤auto [stop, step]做拷贝赋值才不会引起内存错误。
第⼀题感觉思路还是很直观的,注意数据的溢出问题就⾏了,1E9 * 2不会溢出,1E9 * 3就会溢出了。
我这⾥没有把数据类型提升到 int64_t,不然的话可以只做⼀次取余,毕竟 int64_t 之下1E9 * 5也溢出不了。
题⽬描述
You have a grid of size n x 3 and you want to paint each cell of the grid with exactly one of the three colors: Red, Yellow, or Green while making sure that no two adjacent cells have the same color (i.e., no two cells that share vertical or horizontal sides have the same color). Given n the number of rows of the grid, return the number of ways you can paint this grid. As the answer may grow large, the answer must be computed modulo 109 + 7.
Example 1:
Input: n = 1
Output: 12
Explanation: There are 12 possible way to paint the grid as shown.
Example 2:
Input: n = 2
Output: 54
Example 3:
Input: n = 3
Output: 246
Example 4:
Input: n = 7
Output: 106494
Example 5:
Input: n = 5000
Output: 30228214
Constraints:
n == grid.length
grid[i].length == 3
1 <= n <= 5000
解题思路
这是⼀道显⽽易见的 DP 题⽬,下⼀层的涂⾊⽅案仅依赖于上⼀层,有点类似于那道矩形覆盖题:⽤2x1的⼩矩形⽆重叠地覆盖2xn的⼤矩形(斐波那契数列嘛)。
需要注意的是,对于上⼀层的涂⾊可以分为两类,各⾃对应不同的下⼀层涂⾊⽅案:
【红绿红】这种两侧颜⾊相同的,可以推出3种两侧相同的⽅案、2种两侧颜⾊不同的⽅案;
【红绿黄】这种两侧颜⾊不同的,可以推出2种两侧相同的⽅案、2种两侧颜⾊不同的⽅案;
然后就是具体的实现问题了,是保存每⼀步的状态还是压缩状态,是线性推导还是快速矩阵幂(可以达到对数时间复杂度)。
参考代码
直接使⽤简单的不保存状态的线性时间 DP ⽅案:
/*
* @lc app=leetcode id=1411 lang=cpp
*
* [1411] Number of Ways to Paint N × 3 Grid
*/
// @lc code=start
class Solution {
public:
int numOfWays(int n) {
assert(n >= 1);
constexpr int MOD = 1E9 + 7;
int same = 6, diff = 6; // 6 同 6 异
for (int i = 2; i <= n; i++) {
int s = same, d = diff;
same = (((s+s)%MOD + s)%MOD + (d+d)%MOD) % MOD;
diff = ((s+s)%MOD + (d+d)%MOD) % MOD;
} // 同 -> 3同2异;异 -> 2同2异
return (same + diff) % MOD;
}
};
// @lc code=end
第⼆题就不那么好想好写了,想到思路做试验再改正可能时间就来不及了。
⽽且⼀旦遇到heap-use-after-free之类的奇怪bug基本也就完蛋了。
题⽬描述
You are given an array routes representing bus routes where routes[i] is a bus route that the ith bus repeats forever.
For example, if routes[0] = [1, 5, 7], this means that the 0th bus travels in the sequence 1 -> 5 -> 7 -> 1 -> 5 -> 7 -> 1 -> ... forever.
You will start at the bus stop source (You are not on any bus initially), and you want to go to the bus stop target. You can travel between bus stops by buses only.
Return the least number of buses you must take to travel from source to target. Return -1 if it is not possible.
Example 1:
Input: routes = [[1,2,7],[3,6,7]], source = 1, target = 6
Output: 2
Explanation: The best strategy is take the first bus to the bus stop 7, then take the second bus to the bus stop 6.
Example 2:
Input: routes = [[7,12],[4,5,15],[6],[15,19],[9,12,13]], source = 15, target = 12
Output: -1
Constraints:
1 <= routes.length <= 500.
1 <= routes[i].length <= 105
All the values of routes[i] are unique.
sum(routes[i].length) <= 105
0 <= routes[i][j] < 106
0 <= source, target < 106
解题思路
看成⼀个图的问题,使⽤ BFS 解决。
图中有两类结点,分别是 bus 和 stop,可以看作是⼀个⼆部图 —— 左边是 bus 右边是 stop。
现在要解决的是从⼀个stop到另⼀个 stop 需要经过⼏个 bus。
我们⾸先先把图的另⼀半建⽴,然后再⼀边 BFS ⼀边计步就可以了。
参考代码
AC 代码:
/*
* @lc app=leetcode id=815 lang=cpp
*
* [815] Bus Routes
*/
// @lc code=start
class Solution {
public:
// 公交换乘问题
int numBusesToDestination(vector<vector<int>>& routes, int S, int T) {
if (S == T) return 0;
unordered_map<int, vector<int>> stop2bus;
for (int i = 0; i < routes.size(); ++i) {
for (int stop : routes[i]) {
stop2bus[stop].push_back(i);
}
}
vector<bool> visited(routes.size(), false);
queue<int> q;
q.push(S);
int buses = 0;
while (!q.empty()) {
int size = q.size();
++buses;
while (size--) {
int curr = q.front(); q.pop();
for (int bus : stop2bus[curr]) {
if (visited[bus]) continue;
visited[bus] = true;
for (int stop : routes[bus]) {
if (stop == T) return buses;
if (stop == curr) continue;
q.push(stop);
}
}
}
}
return -1;
}
};
// @lc code=end
下⾯⼏乎完全相同的代码,却会报Runtime Error : AddressSanitizer: heap-use-after-free也是奇怪。
上⼀次遇到这种问题,也是⽤unorder_map的时候。
/*
* @lc app=leetcode id=815 lang=cpp
*
* [815] Bus Routes
*/
// @lc code=start
class Solution {
public:
// 公交换乘问题
int numBusesToDestination(vector<vector<int>>& routes, int source, int target) { if (source == target) return 0;
size_t nbus = routes.size();
unordered_map<int, vector<int>> buses; // stop -> routes
for (int i = 0; i < nbus; i++) {
for (int stop: routes[i]) {
buses[stop].push_back(i);
}
}
queue<pair<int, int>> q; // 存放站台
vector<bool> vis(nbus, false); // 这班车坐过了
q.push({source, 0}); // 地点、坐车⼏次
while (!q.empty()) {
auto&& [stop, step] = q.front();
q.pop();
// if (stop == target) return step;
for (int b : buses[stop]) {
if (vis[b]) continue;
vis[b] = true;
for (int s : routes[b]) {
if (s == stop) continue;
if (s == target) return step+1;
q.push({s, step+1});
}
}
}
return -1;
}
};
// @lc code=end。