第一题:
输入一个字符串,字符串是有一系列数字和问号组成的。要求把问号的地方变成数字,输出这个数字最小是多少。对于这个数字的特征,主要有三点描述:
- 相邻位置上的数字不相同
- 没有前导0,即首位不能是0
- 该数能被3整除
思路:
一个很直观的思路就是,我们遍历0-9,从小到大遍历,把不符合上述三点要求的排除掉,就是答案!
代码实现
bool finded; // 该bool值用来判断是否找到符合要求的答案
string ans; // 用来保存最后的结果
// first为指针,遍历字符串, value用来存储各个位之和,str为要递归的字符串
void dfs(int first, int value, string& str) {
if (finded) return; // 如果找到,则返回
if (first == str.size()) { // 如果没找到,看指针是否走到末尾
if (value % 3 == 0) { // 此时各个位上的数字之和能够被3整除
finded = true; // 则置finded为TRUE
ans = str; // 保存结果
}
return;
}
if (str[first] != '?') { // 如果该位不是‘?’
if (first > 0 && str[first] == str[first - 1]) return; // 如果此时后一位与前一位相同, 那么该数字不合法,直接返回
dfs(first + 1, value + (str[first] - '0'), str); // 否则进行递归
}
else {
for (char ch = '0'; ch <= '9'; ++ch) { // 如果是'?'
if (first == 0 && ch == '0') continue; // 如果是第一个字符且遍历到'0',则跳过
if (first > 1 && ch == str[first - 1]) continue; // 如果和前一位相同,继续跳过
str[first] = ch; // 让该位为遍历到的字符
dfs(first + 1, value + str[first] - '0', str); // 进行递归
}
}
}
void solve() {
string str; cin >> str;
if (str.size() == 1) { // 当字符串的长度为1时
cout << 3 << endl; // 直接返回3
return;
}
dfs(0, 0, str);
cout << ans << endl;
}
至于滴滴笔试的第二个题,忘了具体题目考的什么了,然后从LeetCode上找了一个类似的题目来分享一下,顺便学一学差分数组和前缀和数组的这种思路方法:
首先这个题最直观的一个解法就是,我们可以遍历bookings这个数组,把各段预订的航班数加起来,那么就可以求出来最后的结果:
代码实现
class Solution {
public:
vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {
vector<int> res(n); // 创建结果数组
for (auto &b : bookings) { // 遍历bookings数组
for (int i = b[0] - 1; i < b[1]; i++) {
res[i] += b[2]; // 把每段的航班数加起来
}
}
return res; // 返回结果
}
};
时间复杂度:O(m * n)
这样做肯定会超时,那么还有什么方法可以进行优化呢?就是差分数组和前缀和数组。
- 比如数组:{1, 2,3, 4}
- 其差分数组就是:{1, 1, 1, 1}
- 也就是原数组中的后一位减前一位的差值,其中第一位没有前一位,那么就是它本身。
- 前缀和数组则是:{1,3, 6,10}
- 即前n项和,第一位就是1,第二位就是1+2=3,第三位就是1+2+3=6,第四位就是1 + 2 +3 + 4 = 10。
- 这个时候,如果我们给原数组中的第二位和第三位增加一个增量2,即原数组就变为:{1,2+2,3+2, 4} = {1, 4, 5, 4}
- 那么新数组的差分数组则是:{1,3,1, -1} 我们发现相比于原来的差分数组,发生变化的就只是第二位和第四位,也就是第三位的后一位。
- 因此,原来遍历求区间和的这个过程就可以转换为先求每个区间的差分数组,然后加起来,再求该差分数组的前缀和数组,即为最后结果!
代码实现:
class Solution {
public:
vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {
vector<int> nums(n + 1); // 构建差分数组
int left = 0, right = 0, inc = 0;
// left为左边界,right为右边界,Inc为增量
for (auto booking : bookings) {
left = booking[0] - 1;
right = booking[1] - 1;
inc = booking[2];
nums[left] += inc;
nums[right + 1] -= inc;
}
vector<int> res(n); // 求差分数组的前缀和
for (int i = 0; i < n; i++) {
if (i == 0) {
res[i] = nums[0];
} else {
res[i] = res[i - 1] + nums[i]; // 求前缀和数组的过程
}
}
return res;
}
};