持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第 15 天,点击查看活动详情
题目链接
题目描述
给你一个字符串 s 和一个字符 c ,且 c 是 s 中出现过的字符。
返回一个整数数组 answer ,其中 answer.length == s.length 且 answer[i] 是 s 中从下标 i 到离它 最近 的字符 c 的 距离 。
两个下标 i 和 j 之间的 距离 为 abs(i - j) ,其中 abs 是绝对值函数。
测试用例
用例1:
输入: s = "loveleetcode", c = "e"
输出: [3,2,1,0,1,0,0,1,2,2,1,0]
限制
1 <= s.length <= 10^4s[i]和c均为小写英文字母- 题目数据保证
c在s中至少出现一次
题目分析
题目给出了一个字符串 str,以及 str 中出现过的字符 c,需要我们求字符串中每个字符距离 c 的最短下标。需注意,c 出现的次数是不确定的,即 次数 >=1
首先,我们求出 c 在 str 中的全部下标位置,使用一个数组 arr 记录下来,此时,arr 中的数据是递增的。
对于 str 中的某个字符 n 的下标 i 有如下几种情况判断处理:
i <= arr[0],或者i >= arr[arr.length - 1]的时候,直接相减取绝对值即可- 当
arr[j] < i < arr[j + 1]的时候,将i分别与arr[j], arr[j + 1]相减,取其中一个最小值即可
代码实现
完整的代码实现如下
var shortestToChar = function (s, c) {
let arr = [];
for (let i = 0; i < s.length; i++) {
if (s.charAt(i) == c) {
arr.push(i);
}
}
let nums = [];
arr.push(Number.MAX_SAFE_INTEGER);
for (let i = 0, j = 0; i < s.length; i++) {
if (j == 0) {
nums.push(Math.abs(i - arr[j]))
} else {
nums.push(Math.min(Math.abs(i - arr[j]), Math.abs(i - arr[j - 1])))
}
if (i >= arr[j]) j++;
}
return nums;
};
优化
在字符 c 重复出现的次数超过 2 次的时候,两个坐标之间的数据,呈现一个 倒V;将这两个下标命名为 left, right,套用一个循环体,left++, right-- 的时候,对应的值 val++,直到 left > right 的时候,跳出循环体
var shortestToChar = function (s, c) {
let arr = [];
for (let i = 0; i < s.length; i++) {
if (s.charAt(i) == c) {
arr.push(i);
}
}
let nums = new Array(s.length).fill(0);
for (let j = 0; j < arr.length - 1; j++) {
setDiff(nums, arr[j], arr[j + 1]);
}
for (let i = 0; i <= arr[0]; i++) {
nums[arr[0] - i] = i;
}
for (let i = arr[arr.length - 1], k = 0; i < s.length; i++, k++) {
nums[i] = k;
}
function setDiff(arr, left, right) {
let val = 0;
for (; left <= right; left++, right--, val++) {
arr[left] = val;
arr[right] = val;
}
}
return nums;
};