每日一题做题记录,参考官方和三叶的题解 |
题目要求
思路一:两次遍历
算是个直接模拟的思路,从左到右遍历获得到左边最近目标字符的距离,从右到左遍历得到右边最近目标字符距离,有点像双指针的感觉。
两种语言的初始指针指向不太一样。
Java
- 初始化结果数组为 n + 1 n+1 n+1(大于最远距离),用于在从右向左遍历(第二圈)时找到更小值,因为第一圈遍历时,第一个目标字符前元素的结果为默认值;
- 遍历时将指针指在 − 1 -1 −1位置,找到第一个目标字符后开始更新后面元素的距离。
class Solution {
public int[] shortestToChar(String s, char c) {
int n = s.length();
int[] res = new int[n];
Arrays.fill(res, n + 1);
// 从左到右,到左边c的距离
for(int i = 0, j = -1; i < n; i++) {
if(s.charAt(i) == c)
j = i;
if(j != -1)
res[i] = i - j;
}
// 从右到左,到右边c的距离
for(int i = n - 1, j = -1; i > -1; i--) {
if(s.charAt(i) == c)
j = i;
if(j != -1)
res[i] = Math.min(res[i], j - i);
}
return res;
}
}
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
C++
- 无需初始化数组,在第一圈遍历时可更新所有元素;
- 从左向右遍历时,指针指向 − n -n −n,以此更新第一个目标字符前的元素,结果将大于最大距离 n − 1 n-1 n−1;
- 从右向左遍历时,指针指向 2 n 2n 2n,以此更新一个目标字符前元素,但计算结果都不会取到,因为其结果将一定大于当前结果数组内所存值。
class Solution {
public:
vector<int> shortestToChar(string s, char c) {
int n = s.size();
vector<int> res(n);
// 从左到右,到左边c的距离
for(int i = 0, j = -n; i < n; i++) {
if(s[i] == c)
j = i;
res[i] = i - j;
}
// 从右到左,到右边c的距离
for(int i = n - 1, j = 2 * n; i > -1; i--) {
if(s[i] == c)
j = i;
res[i] = min(res[i], j - i);
}
return res;
}
};
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
思路二:BFS
- 需要一个队列容器用来存下一个待处理节点,一个结果数组存距离,将所有距离初始化为 − 1 -1 −1;
- 找出所有目标字符,将其相应距离置 0 0 0,并将相应下标入队;
- 依次处理队列内节点:
- 分别更新其左、右节点(即前一个和后一个,下标减一和加一);
- 若未更新过(距离为初始值 − 1 -1 −1),则当前节点在其最短距离路径上,更新结果为当前节点距离 + 1 +1 +1;
- 若更新过,则之前有距离更近的节点。
Java
class Solution {
public int[] shortestToChar(String s, char c) {
int n = s.length();
int[] res = new int[n];
Arrays.fill(res, -1);
Deque<Integer> que = new ArrayDeque<>();
// 初始化目标字符距离为0
for(int i = 0; i < n; i++) {
if(s.charAt(i) == c) {
que.addLast(i);
res[i] = 0;
}
}
// 更新左右两个节点距离
int[] lr = {-1, 1};
while(!que.isEmpty()) {
int cur = que.pollFirst();
for(int t : lr) {
int tmp = t + cur;
if(tmp > -1 && tmp < n && res[tmp] == -1) {
res[tmp] = res[cur] + 1;
que.addLast(tmp);
}
}
}
return res;
}
}
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n),队列大小
C++
class Solution {
public:
vector<int> shortestToChar(string s, char c) {
int n = s.size();
vector<int> res(n, -1);
queue<int> que;
// 初始化目标字符距离为0
for(int i = 0; i < n; i++) {
if(s[i] == c) {
que.emplace(i);
res[i] = 0;
}
}
// 更新左右两个节点距离
int lr[2] = {-1, 1};
while(!que.empty()) {
int cur = que.front();
que.pop();
for(int t : lr) {
int tmp = t + cur;
if(tmp > -1 && tmp < n && res[tmp] == -1) {
res[tmp] = res[cur] + 1;
que.emplace(tmp);
}
}
}
return res;
}
};
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n),队列大小
总结
是个快乐简单题,能稍微动动脑子的模拟题。
用BFS是真的完全没想到,虽然需要额外空间复杂度,但是思路很巧妙,受教了。
欢迎指正与讨论! |