leetcode
leetcode 701 ~ 750
字符的最短距离

字符的最短距离

难度:

标签:

题目描述

代码结果

运行时间: 23 ms, 内存: 16.0 MB


/*
 * 题目思路:
 * 使用Java Stream和并行处理,我们可以同时从左向右和从右向左扫描。
 * 通过保存最近的字符c的下标,我们可以计算每个位置的最小距离。
 */
 
import java.util.stream.IntStream;
 
public int[] shortestToCharStream(String s, char c) {
    int n = s.length();
    int[] answer = new int[n];
 
    // 从左向右扫描
    IntStream.range(0, n).parallel().forEach(i -> {
        int left = s.substring(0, i + 1).lastIndexOf(c);
        int right = s.indexOf(c, i);
        if (left == -1) left = Integer.MAX_VALUE;
        if (right == -1) right = Integer.MAX_VALUE;
        answer[i] = Math.min(Math.abs(i - left), Math.abs(right - i));
    });
 
    return answer;
}
 

解释

方法:

该题解使用了两次遍历的方法。第一次正向遍历字符串,记录每个位置距离左侧最近的字符 c 的距离。第二次反向遍历字符串,更新每个位置距离右侧最近的字符 c 的距离。最终答案取两次遍历结果的最小值。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在两次遍历中,您是如何决定初始化prev变量为float('-inf')和float('inf')的?这种初始化对算法的逻辑有什么具体影响?
在第一次遍历中,初始化prev为float('-inf')是为了处理字符串开头部分,在遇到第一个目标字符c之前的情况。由于此时尚未遇到任何字符c,使用float('-inf')可以确保计算出的距离足够大,从而在后续遇到字符c后能正确更新。类似地,第二次反向遍历初始化prev为float('inf')的目的是处理字符串尾部在遇到最后一个字符c之后的情况。这种初始化允许在计算距离时,如果尚未遇到字符c,能保持一个足够大的默认距离值,直至遇到字符c并进行更新。这样的初始化在逻辑上保证了在字符串的任一端如果没有字符c出现,该端的字符到c的距离被认为是无穷大,这有助于在实际遇到字符c时能够正确计算距离。
🦆
在第二次遍历时,即使已经有了一个距离值,为什么还要使用min函数来更新answer数组?能否举例说明其中的必要性?
在第一次遍历后,answer数组中的每个元素已经包含了每个位置到最近左侧字符c的距离。第二次遍历的目的是更新这些距离值,以包括到最近右侧字符c的距离。使用min函数是因为我们需要取左侧和右侧字符c的最小距离。例如,假设字符串为'sabcb', 字符c为'b'。第一次遍历后,answer=[2, 1, 0, 1, 2]。第二次遍历更新时,尤其在索引2左右,距离左侧的'b'为0,距离右侧的'b'也为0,所以使用min函数来确保我们取这两个0中的最小值,保持正确的最小距离。如果不使用min函数,那么第二次遍历可能会错误地覆盖之前计算的有效距离值。
🦆
在处理字符串边界情况时,比如字符串s的长度为1或字符c在字符串s中只出现一次,这种方法处理上有什么特别需要注意的吗?
当字符串s的长度为1或字符c在字符串中只出现一次时,算法仍然有效,无需特别调整。对于长度为1的情况,无论字符是否为c,两次遍历都能正确计算距离(要么是0,要么是无穷大然后通过遍历得到正确的距离)。如果字符c只出现一次,第一次遍历将在字符c出现位置之前的所有位置设置很大的距离值,而在c之后的位置则正确计算相对于这唯一的c的距离,第二次遍历同理。因此,该方法自然地处理了这些边界情况,确保了算法的普适性和正确性。

相关问题