Open azl397985856 opened 2 years ago
遍历字符串,对每一个字符元素,使用左右指针思想,分别向左和向右寻找最近的字符c,使用Math.min()进行对比,找到最短距离,把值放进数组中,再对下一个字符元素进行相同操作,直到遍历结束。
/**
* @param {string} s
* @param {character} c
* @return {number[]}
*/
var shortestToChar = function(s, c) {
let ans = [];
for(let i = 0; i < s.length; i++) {
if(s[i] === c) {
ans.push(0);
continue;
}
let left = i;
let right = i;
let shortest = Number.MAX_VALUE;
while(left >= 0) {
if(s[left] === c) {
shortest = Math.min(shortest, i - left);
break;
}
left--;
}
while(right <= s.length - 1) {
if (s[right] === c) {
shortest = Math.min(shortest, right - i);
break;
}
right++;
}
ans.push(shortest);
}
return ans;
};
两遍循环,先从左到右遍历s, 找到值左边第一个c的距离。再从右到左遍历,找到值右边第一个c的距离。取两个值中的最小值。
var shortestToChar = function(s, c) {
let res = [];
let cIndex = -Infinity;
for (let i = 0; i < s.length; i++) {
if (s[i] === c) cIndex = i;
res[i] = i - cIndex;
}
let rcIndex = Infinity;
for (let i = s.length - 1; i >= 0; i--) {
if (s[i] === c) rcIndex = i;
res[i] = Math.min(res[i], rcIndex - i);
}
return res;
};
借鉴了滑动窗口算法,找到第一个和第二个出现字符的位置。
比较下标-头的距离和尾巴-下标的距离,填入数组。
当下标到达尾巴的时候,说明已经
当S字符串只有一个符合的c的时候,从符合位置点往两边填充距离。
class Solution {
public int[] shortestToChar(String s, char c) {
//存储结果
int[] result = new int[s.length()];
//判断滑动窗口
int head = s.indexOf(c);
int tail = s.indexOf(c, head + 1);
//说明没有窗口,直接填充两边值即可
if(tail==-1){
int absLength = 0;
int lP = head;
int rP = head;
//从唯一的下标开始往两边扩展
while(lP>=0||rP<s.length()){
if(lP>=0){
result[lP]=absLength;
lP--;
}
if(rP<s.length()){
result[rP]=absLength;
rP++;
}
absLength++;
}
return result;
}
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
result[i] = Math.min(Math.abs(head - i), Math.abs(tail - i));
//遍历到了尾巴,尾巴变头,找下一个尾巴。
if (i == tail) {
head = tail;
//如果尾巴没了,tail = -1 tail-i的绝对值永远大于head-i的绝对值,永远是head-i
tail = s.indexOf(c, tail + 1);
}
}
return result;
}
}
时间复杂度:O(n)
空间复杂度:O(n)
维护两个指针,一个代表着离左边的c的位置,一个代表着离右边的c的位置
遍历数组:
class Solution {
public:
vector<int> shortestToChar(string s, char c) {
int c_l = -1, c_r = -1;
int i = 0, j = 0;
vector<int> ret_vec;
while (j < s.size()) {
for (i ; i < s.size(); i++) {
if (s[i] == c) {
c_l = c_r;
c_r = i;
if (c_l == -1) { // 第一个c
c_l = c_r;
}
i++;
break;
}
if (i == s.size()-1) { // 最后一个c
c_l = c_r;
}
}
for (j ; j < i; j++) {
ret_vec.emplace_back(min(abs(j - c_l) , abs(j-c_r)));
}
cout << c_l << c_r << i << j <<endl;
}
return ret_vec;
}
};
时间: o(n)
空间: o(1)
两次遍历字符串,取其中较短的距离作为返回值
class Solution:
def find_smallest_dist(self, s:str, c:str) -> List[int]:
nearest_dist = len(s)
result = [0]*len(s)
for i in range(len(s)):
nearest_dist = 0 if s[i] == c else nearest_dist + 1
result[i] = nearest_dist
nearest_dist = len(s)
for i in range(len(s)-1, -1, -1):
nearest_dist = 0 if s[i] == c else nearest_dist + 1
result[i] = min(nearest_dist, result[i])
return result
空间复杂度:O(N)
时间复杂度:O(N)
var shortestToChar = function (s, c) {
let arrStr = s.split('');
let result = [];
let index = null;
for (let i = 0; i < arrStr.length; i++) {
if (arrStr[i] !== c && index === null) {
result[i] = null;
} else if (arrStr[i] === c) {
result[i] = 0;
index = i;
} else {
result[i] = i - index;
}
}
index = null;
for (let i = arrStr.length - 1; i >= 0; i--) {
if (arrStr[i] === c) {
index = i;
} else if (index !== null && result[i] && index - i < result[i]) {
result[i] = index - i;
} else if (!result[i]) {
result[i] = index - i;
}
}
return result;
};
复杂度分析 - 时间复杂度:O(N) - 空间复杂度:O(N)
/**
* @param {string} S
* @param {character} C
* @return {number[]}
*/
var shortestToChar = function (S, C) {
const res = Array(S.length).fill(0);
for (let i = 0; i < S.length; i++) {
if (S[i] === C) continue;
// 定义两个指针 l, r 分别向左、右两个方向寻找目标字符 C,取最短距离
let l = i,
r = i,
shortest = Infinity;
while (l >= 0) {
if (S[l] === C) {
shortest = Math.min(shortest, i - l);
break;
}
l--;
}
while (r < S.length) {
if (S[r] === C) {
shortest = Math.min(shortest, r - i);
break;
}
r++;
}
res[i] = shortest;
}
return res;
};
class Solution:
def shortestToChar(self, S:str, C:str)-> List[int]:
n = len(S)
result = [0 for _ in range(n)]
m,p = 0,0
for i in range(n):
if S[i]==C:
if m == 0:
m = i
p = i
v = 0
while p+1<n and S[p+1]!=C:
p += 1
v += 1
result[p] = v
q = p
v = 0
while q>i and p+1<n and S[p+1] == C:
v += 1
result[q] = min(result[q],v)
q -= 1
v = 0
while m-1>=0 and S[0]!=C:
m -= 1
v += 1
result[m] = v
return result
time: O(n^2) space: O(n)
先遍历一次字符串s,获得字符串s种所有c的小标,并存在cIndexs数组;
双层循环,外层遍历字符串s,内层遍历cIndexs数组,即将字符串s种每一个字字符的小标与所有的字符c小标分别求绝对值,所得值中最小的即为所求目标,存入结果answer数组。
暂没有其他思路,就暴力求解了。😥
class Solution {
public int[] shortestToChar(String s, char c) {
int n = s.length();
int[] answer = new int[n];
int[] cIndexs = new int[n];
int cNum = 0;
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) == c){
cIndexs[cNum++] = i;
}
}
for(int i = 0; i < s.length(); i++){
int minDistance = n;
for(int j = 0; j < cNum; j++){
int distance = Math.abs(i - cIndexs[j]);
if(distance < minDistance){
minDistance = distance;
}
}
answer[i] = minDistance;
}
return answer;
}
}
复杂度分析
Deque q for the index of character c. For each index i in s check whether abs(i - q[0])>abs(i - q[1]) and q has more than 1 element. If it is, pop the most front element from the q.
class Solution:
def shortestToChar(self, s: str, c: str) -> List[int]:
position = collections.deque()
for i in range(len(s)):
if s[i] == c:
position.append(i)
ans = []
for i in range(len(s)):
if len(position)>1 and abs(i-position[0])>abs(i-position[1]):
position.popleft()
ans.append(abs(i-position[0]))
return ans
Time: O(N) Space: O(N)
两次遍历
记录上一个字符c出现的位置,从头走一遍,计算距离,再从尾部走一遍,更新距离为两次计算中的较小值。
def shortestToChar(self, s, c):
last=-10000
ans=[]
for i in range(len(s)):
if s[i]==c:
last=i
ans.append(i-last)
last=10000
for i in range(len(s)-1,-1,-1):
if s[i]==c:
last=i
ans[i]=min(ans[i],last-i)
return ans
时间 O(N) 空间 O(N)
prev
,那么答案就是i-prev
prev
,那么答案就是prev-i
<?php
class Solution {
/**
* @param String $s
* @param String $c
* @return Integer[]
*/
function shortestToChar($s, $c) {
$ans = [];
$len = mb_strlen($s);
// 计算左边
$prev = PHP_INT_MIN / 2;
for ($i = 0; $i < $len; $i++) {
if ($s[$i] == $c) {
$prev = $i;
}
$ans[] = $i - $prev;
}
// 计算右边
$prev = PHP_INT_MAX / 2;
for ($j = $len - 1; $j >= 0; $j--) {
if ($s[$j] == $c) {
$prev = $j;
}
$ans[$j] = min($ans[$j], $prev - $j);
}
return $ans;
}
}
时间复杂度: O(N),N是字符串的长度,我们需要遍历两次 空间复杂度: O(N),ans的长度
使用的是暴力解法没有使用官方的前后遍历所以时间复杂度和空间复杂度比较高
class Solution {
public:
vector<int> shortestToChar(string s, char c) {
vector<int> result;
vector<int > index;
int len = s.length();
for(int i = 0; i< len; i++)
{
if(s.at(i) == c)//将字符串转换成字符在进行比较
{
index.push_back(i);
}
}
int len_index = index.size();
for(int i = 0; i < len; i++)
{
int dis_min = len;//初始化为len
for(int j =0; j<len_index; j++)
{
dis_min = min(abs(i-index[j]),dis_min);
}
result.push_back(dis_min);
}
return result;
}
};
左右遍历数组
class Solution {
public int[] shortestToChar(String s, char c) {
int len = s.length();
int[] res = new int[len];
int pre = Integer.MIN_VALUE / 2;
for (int i = 0; i < len; i++) {
if (s.charAt(i) == c) {
pre = i;
}
res[i] = i - pre;
}
pre = Integer.MAX_VALUE / 2;
for (int i = len - 1; i >= 0; i--) {
if (s.charAt(i) == c) {
pre = i;
}
res[i] = Math.min(res[i], pre - i);
}
return res;
}
}
先从后往前遍历一遍, 再从前往后遍历一遍,查漏补缺以及比较出最近的值
class Solution {
public:
vector<int> shortestToChar(string s, char c) {
int length = s.length();
vector<int> resultVector(length, -1);
int preIndex = -1;
for (int i = length - 1; i >= 0; i--) {
if (s.at(i) == c) {
preIndex = i;
resultVector[i] = 0;
}
if (preIndex != -1) {
resultVector[i] = preIndex - i;
}
}
preIndex = -1;
for (int i = 0; i < length; i++) {
if (s.at(i) == c) {
preIndex = i;
} else if (resultVector.at(i) == -1 && preIndex != -1) {
resultVector[i] = i - preIndex;
} else if (resultVector.at(i) != -1 && preIndex != -1) {
resultVector[i] = std::min(i - preIndex, resultVector[i]);
}
}
return resultVector;
}
};
复杂度分析
class Solution:
def shortestToChar(self, s: str, c: str) -> List[int]:
result = [];
for i in range(len(s)):
if (s[i] == c):
result.append(0)
continue
for left in range(i, -1, -1):
dist1 = 0
if (s[left] == c):
dist1 = i - left
break
for right in range(i, len(s)):
dist2 = 0
if (s[right] == c):
dist2 = right - i
break
if (dist1 == 0):
result.append(dist2)
if (dist2 == 0):
result.append(dist1)
if (dist1 <= dist2 and dist1 != 0):
result.append(dist1)
if (dist1 > dist2 and dist2 != 0):
result.append(dist2)
return result;
Time Complexity: O(N) Space Complexity: O(N)
字符的最短距离 https://leetcode-cn.com/problems/shortest-distance-to-a-character/
找到 s 中所有与 c 相同的字符,并将其索引存放到一个数组中。将数组中的元素索引依次与相同字符的索引做差,并比较得出最小值。值得注意的是,当 s 中与 c 相同的字符只有一个时,无需比较,直接做差即可。
var shortestToChar = function(s, c) {
var curr = [];
var res = [];
for (let i = 0; i < s.length; i++) {
if (s[i] == c) {
curr.push(i);
}
}
if (curr.length == 1) {
for (let i = 0; i < s.length; i++) {
res[i] = Math.abs(i - curr[0]);
}
return res;
}
for (let i = 0; i < s.length; i++) {
let j = 0;
let data = Math.abs(curr[j] - i);
while (curr && (j < curr.length - 1)) {
data = Math.min(data, (Math.abs(curr[j + 1] - i)));
j++;
res[i] = data;
}
}
return res;
};
var shortestToChar = function(s, c) {
var curr = [];
var res = [];
for (let i = 0; i < s.length; i++) {
if (s[i] == c) {
curr.push(i);
}
}
for (let i = 0; i < s.length; i++) {
if (s[i] == c) {
res[i] = 0;
continue;
}
for (const j of curr) {
const dist = Math.abs(j - i);
if (dist >= res[i]) break; // 小小剪枝,跟上次存的比较,j是不断增大的,目的就是为了找最小值,设置阈值
res[i] = dist;
}
}
return res;
};
时间复杂度
O(n n) 前面for循环是n,后面for循环嵌套while,while内最大是n,时间复杂度就是nn,前面的n可以忽略不记
空间复杂度
O(n) res 和 curr
两遍循环,先从左到右遍历s,找到左边第一个c的距离。再从右到左遍历,找到值右边第一个c的距离。最后,取两个值中的最小值。
var shortestToChar = function(s, c) {
let res = [];
let lcIndex = -Infinity;
for (let i = 0; i < s.length; i++) {
if (s[i] === c) lcIndex = i;
res[i] = i - lcIndex;
}
let rcIndex = Infinity;
for (let i = s.length - 1; i >= 0; i--) {
if (s[i] === c) rcIndex = i;
res[i] = Math.min(res[i], rcIndex - i);
}
return res;
};
将 c 看做分界线,将 s 划分为一个个窗口,然后对每个窗口进行遍历,每个窗口分别计算每个字符距离窗口左右边界的距离,并比较得到最小值。
var shortestToChar = function(s, c) {
let res = [];
let l = 0;
if (s[0] === c) {
l = 0;
} else {
l = Infinity;
}
r = s.indexOf(c, 1);
for (let i = 0; i < s.length; i++) {
res[i] = Math.min(Math.abs(i - l), Math.abs(r - i));
if (i === r) {
l = r;
r = s.indexOf(c, l + 1);
}
}
return res;
};
思路: 首先先从左向右遍历一遍,将ans数组中的所有元素标志成对应位。 再从右往左遍历一遍,再比较大小,将ans对应位置中更小的数放入对应ans。
代码: class Solution { public int[] shortestToChar(String S, char C) { int N = S.length(); int[] ans = new int[N]; int prev = Integer.MIN_VALUE / 2;
for (int i = 0; i < N; ++i) {
if (S.charAt(i) == C) prev = i;
ans[i] = i - prev;
}
prev = Integer.MAX_VALUE / 2;
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;
}
}
时间复杂度:O(n) 空间复杂度:O(n)
两头遍历,取较小值
var shortestToChar = function(s, c) {
let len = s.length
let left = []
let right = []
for (let i = 0;i <len;i++) {
if (s.indexOf(c,i)==-1) {
left.push(Infinity)
} else {
left.push(s.indexOf(c,i)-i)
}
}
for (let i = len-1;i >= 0;i--) {
if (s.lastIndexOf(c,i)==-1) {
right.unshift(Infinity)
} else {
right.unshift(i-s.lastIndexOf(c,i))
}
}
for (let i = 0;i < len;i++) {
left[i] = Math.min(left[i],right[i])
}
return left
};
时间复杂度: O(n)
空间复杂度: O(n)
对给你一个字符串 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]
解释:字符 'e' 出现在下标 3、5、6 和 11 处(下标从 0 开始计数)。
距下标 0 最近的 'e' 出现在下标 3 ,所以距离为 abs(0 - 3) = 3 。
距下标 1 最近的 'e' 出现在下标 3 ,所以距离为 abs(1 - 3) = 2 。
对于下标 4 ,出现在下标 3 和下标 5 处的 'e' 都离它最近,但距离是一样的 abs(4 - 3) == abs(4 - 5) = 1 。
距下标 8 最近的 'e' 出现在下标 6 ,所以距离为 abs(8 - 6) = 2 。
示例 2:
输入:s = "aaab", c = "b"
输出:[3,2,1,0]
提示:
1 <= s.length <= 104
s[i] 和 c 均为小写英文字母
题目数据保证 c 在 s 中至少出现一次
-
class Solution:
def shortestToChar(self, s: str, c: str) -> List[int]:
prev1, prev2 = 2*len(s), 2*len(s)
ans1,ans2 = [len(s)]*len(s), [len(s)]*len(s)
j = len(s)-1
for i in range(len(s)):
if s[i] == c:
prev1 = i
ans1[i] = abs(i - prev1)
if s[j] == c:
prev2 = j
ans2[j] = abs(j - prev2)
j -= 1
for i in range(len(s)):
ans1[i] = min(ans1[i],ans2[i])
return ans1
min
思路: 对于每一个等于c的字符,在其两侧分别计算距离,而对于每个字符,距离取最小值 优化方向: 将等于c的字符分为首个,中间,末尾,分别控制不同的区域 代码: ''' class Solution: def shortestToChar(self, s: str, c: str) -> List[int]: l = len(s) ans = [l for i in range(l)] for i in range(l): if s[i] == c: for j in range(l): ans[j]=min(ans[j],abs(i-j)) return ans '''
将两边遍历的结果存入数组,留下较小的值
class Solution {
public:
vector<int> shortestToChar(string s, char c) {
vector<int> ans(s.size(), 0);
int left = INT_MAX;
int right = INT_MAX;
for(int i = 0; i < s.size(); i ++) {
if (s[i] == c) {
left = i;
}
ans[i] = i - left;
}
for(int i = s.size() - 1; i >= 0; i --) {
if (s[i] == c) {
right = i;
}
ans[i] = min(abs(ans[i]), right - i);
}
return ans;
}
};
时间复杂度:O(n) 空间复杂度:O(n)
使用双指针,然后遍历字符串
class Solution {
public int[] shortestToChar(String S, char C) {
int N = S.length();
int[] result=new int[N];
int indexNext=S.indexOf(C);//双指针,indexNext表示下一个C的下标,
int index=indexNext;//index表示前一个C的坐标
// 通过这里的赋值使在只有左边有C字符的时候(此时index = indexNext)的时候
//index也在当前字符的右边,否则在左右都有C字符的时候,当前字符必在index和indexNext的中间。
for(int i = 0; i < S.length(); i++){
if(S.charAt(i) == C){//每当遍历到C就更新index和indexNext
result[i] = 0;
index = i;
indexNext = S.indexOf(C, i+1);
//这里如果当前是最后一个C时,此时indexNext为-1,这也保证了上面的情况
}else{
result[i] = Math.min(Math.abs(index - i), Math.abs(indexNext - i));
}
}
return result;
}
}
时间复杂度:O(n)
class Solution:
def shortestToChar(self, s: str, c: str) -> List[int]:
c_pos, ans = [], []
for idx, i in enumerate(s):
if i == c:
c_pos.append(idx)
p = 0
for i in range(len(s)):
if i < c_pos[0]:
ans.append(c_pos[0] - i)
elif i > c_pos[-1]:
ans.append(i - c_pos[-1])
elif i == c_pos[p]:
ans.append(0)
p += 1
else:
ans.append(min(c_pos[p] - i, i - c_pos[p-1]))
return ans
复杂度分析
class demo:
def test(self, S:str, C:str) -> List[int]:
sums = -1
zero_sums = [0]*len(S)
for i in range(len(S)):
if S[i] == C:
sums = 0
else:
sums += 1
zero_sums[i] = sums
sums = -1
for j in range(len(S)-1, -1, -1):
if S[j] == C:
sums = 0
else:
sums +=1
zero_sums[j] = min(sums, zero_sums[j])
return sums
1、首先找到字符在数组中的下标数组; 2、先处理第一个字符之前的,以及最后一个字符之后; 3、如果当前元素等于目标字符,在数组中 push 0; 4、处理两个字符中间的距离问题;
function beelineOfCharacter(targetString, targetCharacter) {
// 判断目标字符是否处在数组字符串的末尾
const isEnd = targetString[targetString.length - 1] === targetCharacter;
console.log(isEnd);
// 寻找目标字符在数组当中的位置
let targetCharIndex = [];
for (let i = 0; i < targetString.length; i++) {
if (targetString[i] === targetCharacter) {
targetCharIndex.push(i);
}
}
console.log(targetCharIndex, 'targetCharIndex');
let finalArray = [];
for (let j = 0; j < targetString.length; j ++) {
const item = targetString[j];
console.log(targetString[j], '1111');
// 等于目标元素就push0
if (item === targetCharacter) {
finalArray.push(0);
}
// 处理第一个目标字符之前的元素
const firstCharIndex = targetCharIndex[0];
if (j < firstCharIndex) {
const tempArray = numberToIndex(firstCharIndex);
finalArray.concat(tempArray);
}
}
}
function numberToIndex(number) {
let indexArray = [];
for (let i = 0; i < number; i++) {
indexArray.unshift(i);
}
indexArray.pop()
return indexArray;
}
beelineOfCharacter('acd', 'c')
复杂度分析
使用不定长滑动窗口,边界字符为c,left和right维护窗口`
var shortestToChar = function(s, c) {
let res = [];
let left = -Infinity;
let right = s.indexOf(c);
for(let i = 0; i < s.length; i++){
res.push(Math.min(Math.abs(i - left), Math.abs(i -right)));
if(i === right){
left = right;
right = s.indexOf(c, right + 1);
}
}
return res;
};
时间复杂度:O(n) 空间复杂度:O(1)
今天也是抄答案的一天呢
vector<int> shortestToChar(string s, char c) {
vector<int> ans(s.size(),-1);
int len=s.size();
int p=-1;
for(int i=0;i<len;i++){
if(s[i]==c){
p=i;
ans[i]=0;
}
else if(p!=-1) ans[i]=i-p;
}
p=-1;
for(int i=len-1;i>=0;--i){
if(s[i]==c) p=i;
if(p!=-1) ans[i]=min(ans[i],p-i);
if(ans[i]==-1) ans[i]=p-i;
}
return ans;
}
public int[] shortestDistance(String s, char c) { int[] arr = new int[s.length()]; int distance = Integer.MIN_VALUE; for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == c) { distance = i; } arr[i] = i - distance; }
distance = Integer.MAX_VALUE;
for (int j = s.length() - 1; j >= 0; j--) {
if (s.charAt(j) == c) {
distance = j;
}
arr[j] = Math.min(arr[j], distance - j);
}
return arr;
Day2
1、遍历数组
2、对于每个字符都分别向左和右查找c
3、对比左和右的长度,取最小值填入数组中
var shortestToChar = function(s, c) {
var answer=Array(s.length).fill(0);//将数组中填满0
for(let i=0;i<s.length;i++){
if (s[i] === c) continue;//若该位置与字符相同,则不用管
let short=Infinity
for(let j=i;j<s.length;j++){
if(s[j]===c){
short=Math.min(short,j-i)
break
}
}
for(let k=i;k>-1;k--){
if(s[k]===c){
short=Math.min(short,i-k)
break
}
}
answer[i]=short
}
return answer
};
时间复杂度:O(n2)
空间复杂度:O(n)
https://leetcode-cn.com/problems/shortest-distance-to-a-character/
给你一个字符串 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]
解释:字符 'e' 出现在下标 3、5、6 和 11 处(下标从 0 开始计数)。
距下标 0 最近的 'e' 出现在下标 3 ,所以距离为 abs(0 - 3) = 3 。
距下标 1 最近的 'e' 出现在下标 3 ,所以距离为 abs(1 - 3) = 2 。
对于下标 4 ,出现在下标 3 和下标 5 处的 'e' 都离它最近,但距离是一样的 abs(4 - 3) == abs(4 - 5) = 1 。
距下标 8 最近的 'e' 出现在下标 6 ,所以距离为 abs(8 - 6) = 2 。
示例 2:
输入:s = "aaab", c = "b"
输出:[3,2,1,0]
提示:
1 <= s.length <= 104
s[i] 和 c 均为小写英文字母
题目数据保证 c 在 s 中至少出现一次
(本题参考了其他人的代码)
JavaScript Code:
/**
* @param {string} s
* @param {character} c
* @return {number[]}
*/
var shortestToChar = function(s, c) {
let num = [];
num.length === s.length;
let indexNext=s.indexOf(c);//indexNext表示下一个c的下标,
let index=indexNext;//index表示前一个c的坐标
//index也在当前字符的右边,否则在左右都有C字符的时候,当前字符必在index和indexNext的中间。
for(let i = 0; i < s.length; i++){
if(s[i] == c){//每当遍历到C就更新index和indexNext
num[i] = 0;
index = i;
indexNext = s.indexOf(c, i+1);
}else{
num[i] = Math.min(Math.abs(index - i), Math.abs(indexNext - i));
}
}
return num;
};
复杂度分析
令 n 为数组长度。
两边都遍历,最后留下较小的值
c++
class Solution
{
public:
vector<int> shortestToChar(string s, char c)
{
vector<int> ans(s.size(), 0);
int left = INT_MAX;
int right = INT_MAX;
for(int i = 0; i < s.size(); i ++)
{
if (s[i] == c)
{
left = i;
}
ans[i] = i - left;
}
for(int i = s.size() - 1; i >= 0; i --)
{
if (s[i] == c)
{
right = i;
}
ans[i] = min(abs(ans[i]), right - i);
}
return ans;
}
};
分别记录两个数组:
class Solution:
def shortestToChar(self, s: str, c: str) -> List[int]:
occurrence = deque()
for idx, i in enumerate(s):
if i == c:
occurrence.append(idx)
# print(occurrence)
occ_1, occ_2 = copy.deepcopy(occurrence), copy.deepcopy(occurrence)
dis_right = [] # 当前距离右边最近的c的距离
right_pos = occurrence[0]
for idx, char in enumerate(s):
if char == c:
right_pos = occ_1.popleft()
dis_right.append(0)
else:
dis_right.append(abs(idx - occurrence[0]))
# print(dis_right)
dis_left = [] # 当前距离左边最近的c的距离
left_pos = inf
for idx, char in enumerate(s):
if char == c:
left_pos = occ_2.popleft()
dis_left.append(0)
else:
dis_left.append(abs(idx - left_pos))
res = []
for i in range(len(dis_left)):
res.append(min(dis_left[i], dis_right[i]))
# print(dis_left)
return res
时间. 空间复杂度: 都是O(N)
var shortestToChar = function(s, c) {
// 中心扩散法,从当前元素为中心,寻找左右两边的c值,然后找出最短距离
const res = []
for(let i = 0;i < s.length;i ++) {
let l = r = i
while(l >= 0) {
if(s[l] == c) break
l--
}
while(r < s.length) {
if(s[r] == c) break
r++
}
if(l < 0) l = -10000
if(r === s.length) r = 10000
res.push(Math.min(i - l, r - i))
}
return res
};
双指针
java
public int[] shortestToChar(String S, char C) {
int[] res = new int[S.length()];
int cur = S.indexOf(C), pre = cur;
for(int i = 0; i < S.length(); i++){
if(S.charAt(i) == C){//其实就是每当遍历到C就更新cur和pre
res[i] = 0;
pre = i;
cur = S.indexOf(C, i+1);//注意:这里如果当前是最后一个C时,此时cur为-1,这也保证了上面的情况3
}else{
res[i] = Math.min(Math.abs(pre - i), Math.abs(cur - i));//
}
}
return res;
}
时间 O(n) 空间O(n)
左右遍历 问题在于初始的c位置怎么算,算到数组中间好了 对于prev 因为如果不除以2的话,INT_MIN= -2^31,而刚开始的时候i-INT_MIN=i+2^31就会发生溢出,但是INT_MAX-i就不会发生溢出了,所以INT_MAX就没必要除以2了,为了看起来舒服点都除以2了
class Solution {
public:
vector<int> shortestToChar(string S, char C) {
vector<int> distance(S.size(), 0);
int prev = INT_MIN/2;
for(int i = 0; i < S.size(); i ++){
if(S[i] == C) prev = i;
distance[i] = i - prev;
}
prev = INT_MAX/2;
for(int i = S.size() - 1; i >= 0; i --){
if(S[i] == C) prev = i;
distance[i] = min(distance[i], prev - i);
}
return distance;
}
};
时空O(N)
从后往前遍历,遇到等于C的字符就把pre指针置为当前的索引,然后对答案数组进行修改。再从前往后遍历,也是遇到等于C的字符就把pre指针置为当前的索引,对答案数组修改的时候需要对比刚刚已经修改的值和当前赋的值的中选最小值。
class Solution:
def shortestToChar(self, s: str, c: str) -> List[int]:
ans = [0]*len(s)
pre = float("inf")
for i in range(len(s)-1,-1,-1):
if s[i]==c:
pre = i
ans[i]=pre-i
pre = float("-inf")
for i in range(len(s)):
if s[i]==c:
pre = i
ans[i]=min(abs(pre-i),ans[i])
return ans
时间:O(n)
空间:O(n)
class Solution {
public int[] shortestToChar(String s, char c) {
int prev = Integer.MIN_VALUE/2;
int n = s.length();
int ans[] = new int[n];
for(int i=0;i<n;i++){
if(s.charAt(i) == c){
prev = i;
}
ans[i] = i-prev;
}
prev = Integer.MAX_VALUE/2;
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;
}
}
时间:O(n)
空间:O(n)
双指针,两次遍历,一次从头到尾,一次从尾到头。
class Solution:
def shortestToChar(self, s: str, c: str) -> List[int]:
c_pos, ans = [], []
for idx, i in enumerate(s):
class Solution:
def shortestToChar(self, s: str, c: str) -> List[int]:
c_pos, ans = [], []
for idx, i in enumerate(s):
if i == c:
c_pos.append(idx)
p = 0
for i in range(len(s)):
if i < c_pos[0]:
ans.append(c_pos[0] - i)
elif i > c_pos[-1]:
ans.append(i - c_pos[-1])
elif i == c_pos[p]:
ans.append(0)
p += 1
else:
ans.append(min(c_pos[p] - i, i - c_pos[p-1]))
return ans if i == c:
c_pos.append(idx)
p = 0
for i in range(len(s)):
if i < c_pos[0]:
ans.append(c_pos[0] - i)
elif i > c_pos[-1]:
ans.append(i - c_pos[-1])
elif i == c_pos[p]:
ans.append(0)
p += 1
else:
ans.append(min(c_pos[p] - i, i - c_pos[p-1]))
return ans
复杂度
时间复杂度:O(n) 空间复杂度:O(n)
/**
* @param {string} s
* @param {character} c
* @return {number[]}
*/
var shortestToChar = function(s, c) {
// 转换为数组
// 遍历找出所有c的索引
// 遍历数组,比较距离,取最小值
const strArray = s.split('');
let cIndexArray = [];
strArray.forEach((s, i) => {
if (s === c) {
cIndexArray.push(i);
}
})
let result = [];
strArray.forEach((s, i) => {
let diff = Infinity;
cIndexArray.forEach((cIndex) => {
diff = Math.min(diff, Math.abs(cIndex - i));
})
result.push(diff);
})
return result;
};
## 复杂度
- 时间复杂度:O(n2)
- 空间复杂度:O(n)
思路: 从左向右遍历,记录上一个字符 C 出现的位置 prev,那么答案就是 i - prev。 从右想做遍历,记录上一个字符 C 出现的位置 prev,那么答案就是 prev - i。 这两个值取最小就是答案。
public int[] shortestToChar(String S, char C) {
int N = S.length();
int[] ans = new int[N];
int prev = Integer.MIN_VALUE / 2;
for (int i = 0; i < N; ++i) {
if (S.charAt(i) == C) prev = i;
ans[i] = i - prev;
}
prev = Integer.MAX_VALUE / 2;
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;
}
复杂度 时间复杂度:O(N),其中 N 是 S 的长度,我们需要遍历字符串两次。 空间复杂度:O(N),ans 数组的大小。
class Solution {
public int[] shortestToChar(String s, char c) {
int N = s.length();
int[] ans = new int[N];
int pre = -N;
for(int i = 0; i<N;i++) {
if(s.charAt(i) == c) pre = i;
ans[i] = i-pre;
}
pre = 2*N;
for(int i = N-1; i>=0;i--) {
if(s.charAt(i) == c) pre = i;
ans[i] = Math.min(ans[i],pre-i);
}
return ans;
}
}
class Solution { public int[] shortestToChar(String s, char c) { int len = s.length(); int[] res = new int[len]; int pre = Integer.MIN_VALUE / 2; for (int i = 0; i < len; i++) { if (s.charAt(i) == c) { pre = i; } res[i] = i - pre; } pre = Integer.MAX_VALUE / 2; for (int i = len - 1; i >= 0; i--) { if (s.charAt(i) == c) { pre = i; } res[i] = Math.min(res[i], pre - i); } return res; } }
先把s中所有等于c的元素的下标值存入到数组sc中,然后利用双重循环遍历s,比较s中各个下标值与sc中元素值的大小,将当前下标值与sc[j]的差的绝对值最小值存入scret中
class Solution {
public:
vector<int> shortestToChar(string s, char c) {
vector<int> sc; // 与c相同的值得索引
vector<int> scret; // 距离结果
for(int i =0; i<s.size(); i++){
if(s[i] == c){
sc.push_back(i);
}
}
if(sc.size() == 1){
for(int i = 0; i < s.size(); i++){
scret.push_back(abs(i-sc[0]));
}
}
for (int i = 0; i<s.size(); i++){
for(int j = 0; j<sc.size()-1; j++){
if(i<=sc[j]){
scret.push_back(abs(sc[j]-i));
break;
}
if(i>sc[j]&&i<=sc[j+1]){
scret.push_back(min(abs(i-sc[j]), abs(i-sc[j+1])));
break;
}
if(i>sc[sc.size()-1]){
scret.push_back(abs(i-sc[sc.size()-1]));
break;
}
}
}
return scret;
}
};
从左向右遍历,记录上一个字符 C 出现的位置 prev,那么答案就是 i - prev。 从右想做遍历,记录上一个字符 C 出现的位置 prev,那么答案就是 prev - i。
class Solution {
public int[] shortestToChar(String s, char c) {
int n = s.length();
int pre = -10000; //最大数据范围是10000
int[] ans = new int[n];
for (int i = 0; i < s.length(); i++) { //计算左段与c最近的距离
if (s.charAt(i) == c) pre = i;
ans[i] = i - pre;
}
pre = 10000;
for (int i = s.length() - 1; i >= 0; i--) { //计算右段与c最近的距离,同时与之前记录的左段进行比较
if (s.charAt(i) == c) pre = i;
ans[i] = Math.min(ans[i], pre - i);
}
return ans;
}
}
时间复杂度:O(N)O(N),其中 NN 是 S 的长度,我们需要遍历字符串两次。 空间复杂度:O(N)O(N),ans 数组的大小。
用的双指针循环部分有待优化
var shortestToChar = function(s, c) {
const res=[];
let l=0,r=0,pos=0;
let length=s.length;
for (let i = 0; i < length; i++) {
let array_abs=0;
l=r=pos=i;
for (let j = r; j < length; j++) {
if (s[j]===c) {
r=j;
break;
}
}
for (let j = l; j >=0 ; j--) {
if (s[j]===c){
l=j;
break;
}
}
if (s[l]===c && s[r]===c)
array_abs=Math.min(Math.abs(l-pos),Math.abs(r-pos));
else if (s[l]===c && s[r]!==c)
array_abs=Math.min(Math.abs(l-pos));
else
array_abs=Math.min(Math.abs(r-pos));
res.push(array_abs);
}
return res;
};
复杂度分析
Idea 1) Loop through the string s and note down and note down the index of occurance of target char c 2) Loop through s and array of all c occurance index again, create a temp int that stores the distance between current digit and each c occurance. If there is a shorter distance, update temp
Code
class Solution:
def shortestToChar(self, s: str, c: str) -> List[int]:
occur = []
result = []
for i in range(len(s)):
if s[i] == c:
occur.append(i)
for j in range(len(s)):
min = len(s)
for k in range(len(occur)):
temp = abs(j-occur[k])
if temp<min:
min = temp
result.append(min)
return result
Complexity
Time complexity: O(N^2)
Memory space complexity: O(N)
Language: Java
public int[] shortestToChar(String s, char c) {
int n = s.length();
int[] result = new int[n];
Arrays.fill(result, n);
// Find closest c on the right of each char
int cur = 0;
for (int i = 0; i < n; i++) {
if (s.charAt(i) != c) {
continue;
}
while (cur <= i) {
result[cur] = i - cur;
cur++;
}
}
// Update to get the closest c from both sides by comparing left side
cur = n - 1;
for (int i = n - 1; i >=0; i--) {
if (s.charAt(i) != c) {
continue;
}
while (cur >= i) {
result[cur] = Math.min(result[cur], cur - i);
cur--;
}
}
return result;
}
class Solution {
public:
vector
时间复杂度:O(n) 空间复杂度:O(n)
class Solution:
def shortestToChar(self, s: str, c: str) -> List[int]:
L = []
result = []
for i in range(len(s)):
if s[i] == c:
L.append(i)
for i in range(len(s)):
diff = 10000
for j in L:
if (abs(j - i)) < diff:
diff = abs(j - i)
result.append(diff)
return result
时间复杂度:O(N^2) 空间复杂度:O(N)
class Solution:
def shortestToChar(self, s: str, c: str) -> List[int]:
result = [99999 for i in s]
n = len(s)
for i in range(n):
if s[i] != c:
continue
result[i] = 0
for j in range(i-1, -1, -1):
if s[j] == c:
result[j] = 0
break
result[j] = min(abs(i-j), result[j])
if i == n-1:
break
for j in range(i+1, n):
if s[j] == c:
result[j] = 0
break
result[j] = min(abs(i-j), result[j])
return result
时间复杂度:O(N) 空间复杂度:O(N)
821. 字符的最短距离
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/shortest-distance-to-a-character
前置知识
题目描述
示例 1:
输入: S = "loveleetcode", C = 'e' 输出: [3, 2, 1, 0, 1, 0, 0, 1, 2, 2, 1, 0] 说明: