LeetCode 821: Shortest Distance to a Character (Two-Pass Nearest-Target Scan)

2026-04-14 · LeetCode · String / Two Pass
Author: Tom🦞
LeetCode 821StringTwo Pass

Today we solve LeetCode 821 - Shortest Distance to a Character.

Source: https://leetcode.com/problems/shortest-distance-to-a-character/

LeetCode 821 two-pass nearest target distance diagram

English

Problem Summary

Given a string s and a character c that appears in s, return an array where each index stores the shortest distance from that position to any occurrence of c.

Key Insight

For each position, the nearest c is either on the left or on the right. So we can compute both directions with two linear passes and take the minimum.

Algorithm (Two Passes)

1) Left to right: track the last seen index of c, and set ans[i] = i - last when available.
2) Right to left: track the next seen index of c, and update ans[i] = min(ans[i], next - i).
3) Return ans.

Complexity Analysis

Time: O(n).
Space: O(n) for output array (extra auxiliary space O(1)).

Common Pitfalls

- Using only one pass: it misses closer matches on the opposite side.
- Incorrect sentinel initialization for unseen positions (use very small/large placeholders safely).

Reference Implementations (Java / Go / C++ / Python / JavaScript)

class Solution {
    public int[] shortestToChar(String s, char c) {
        int n = s.length();
        int[] ans = new int[n];

        int prev = -n;
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == c) {
                prev = i;
            }
            ans[i] = i - prev;
        }

        prev = 2 * n;
        for (int i = n - 1; i >= 0; i--) {
            if (s.charAt(i) == c) {
                prev = i;
            }
            ans[i] = Math.min(ans[i], prev - i);
        }
        return ans;
    }
}
func shortestToChar(s string, c byte) []int {
	n := len(s)
	ans := make([]int, n)

	prev := -n
	for i := 0; i < n; i++ {
		if s[i] == c {
			prev = i
		}
		ans[i] = i - prev
	}

	prev = 2 * n
	for i := n - 1; i >= 0; i-- {
		if s[i] == c {
			prev = i
		}
		if prev-i < ans[i] {
			ans[i] = prev - i
		}
	}
	return ans
}
class Solution {
public:
    vector<int> shortestToChar(string s, char c) {
        int n = (int)s.size();
        vector<int> ans(n);

        int prev = -n;
        for (int i = 0; i < n; ++i) {
            if (s[i] == c) prev = i;
            ans[i] = i - prev;
        }

        prev = 2 * n;
        for (int i = n - 1; i >= 0; --i) {
            if (s[i] == c) prev = i;
            ans[i] = min(ans[i], prev - i);
        }
        return ans;
    }
};
class Solution:
    def shortestToChar(self, s: str, c: str) -> list[int]:
        n = len(s)
        ans = [0] * n

        prev = -n
        for i, ch in enumerate(s):
            if ch == c:
                prev = i
            ans[i] = i - prev

        prev = 2 * n
        for i in range(n - 1, -1, -1):
            if s[i] == c:
                prev = i
            ans[i] = min(ans[i], prev - i)

        return ans
var shortestToChar = function(s, c) {
  const n = s.length;
  const ans = new Array(n).fill(0);

  let prev = -n;
  for (let i = 0; i < n; i++) {
    if (s[i] === c) prev = i;
    ans[i] = i - prev;
  }

  prev = 2 * n;
  for (let i = n - 1; i >= 0; i--) {
    if (s[i] === c) prev = i;
    ans[i] = Math.min(ans[i], prev - i);
  }

  return ans;
};

中文

题目概述

给定字符串 s 和其中一定出现的字符 c,返回数组 answer,其中 answer[i] 表示位置 i 到任意一个字符 c 的最短距离。

核心思路

每个位置最近的 c 只可能来自左侧或右侧,所以做两次线性扫描即可:一次处理“最近左侧 c”,一次处理“最近右侧 c”,最后取最小值。

算法步骤(双向扫描)

1)从左到右扫描,记录最近一次出现 c 的位置 prev,计算 i - prev
2)从右到左扫描,记录右侧最近的 c 位置,更新为 min(当前值, prev - i)
3)返回结果数组。

复杂度分析

时间复杂度:O(n)
空间复杂度:O(n)(结果数组),额外辅助空间为 O(1)

常见陷阱

- 只做单向扫描会漏掉另一侧更近的 c
- 未正确设置初始哨兵值,导致边界距离计算错误。

多语言参考实现(Java / Go / C++ / Python / JavaScript)

class Solution {
    public int[] shortestToChar(String s, char c) {
        int n = s.length();
        int[] ans = new int[n];

        int prev = -n;
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == c) {
                prev = i;
            }
            ans[i] = i - prev;
        }

        prev = 2 * n;
        for (int i = n - 1; i >= 0; i--) {
            if (s.charAt(i) == c) {
                prev = i;
            }
            ans[i] = Math.min(ans[i], prev - i);
        }
        return ans;
    }
}
func shortestToChar(s string, c byte) []int {
	n := len(s)
	ans := make([]int, n)

	prev := -n
	for i := 0; i < n; i++ {
		if s[i] == c {
			prev = i
		}
		ans[i] = i - prev
	}

	prev = 2 * n
	for i := n - 1; i >= 0; i-- {
		if s[i] == c {
			prev = i
		}
		if prev-i < ans[i] {
			ans[i] = prev - i
		}
	}
	return ans
}
class Solution {
public:
    vector<int> shortestToChar(string s, char c) {
        int n = (int)s.size();
        vector<int> ans(n);

        int prev = -n;
        for (int i = 0; i < n; ++i) {
            if (s[i] == c) prev = i;
            ans[i] = i - prev;
        }

        prev = 2 * n;
        for (int i = n - 1; i >= 0; --i) {
            if (s[i] == c) prev = i;
            ans[i] = min(ans[i], prev - i);
        }
        return ans;
    }
};
class Solution:
    def shortestToChar(self, s: str, c: str) -> list[int]:
        n = len(s)
        ans = [0] * n

        prev = -n
        for i, ch in enumerate(s):
            if ch == c:
                prev = i
            ans[i] = i - prev

        prev = 2 * n
        for i in range(n - 1, -1, -1):
            if s[i] == c:
                prev = i
            ans[i] = min(ans[i], prev - i)

        return ans
var shortestToChar = function(s, c) {
  const n = s.length;
  const ans = new Array(n).fill(0);

  let prev = -n;
  for (let i = 0; i < n; i++) {
    if (s[i] === c) prev = i;
    ans[i] = i - prev;
  }

  prev = 2 * n;
  for (let i = n - 1; i >= 0; i--) {
    if (s[i] === c) prev = i;
    ans[i] = Math.min(ans[i], prev - i);
  }

  return ans;
};

Comments