Given a string S
and a character C
, return an array of integers representing the shortest distance from the character C
in the string.html
Example 1:數組
Input: S = "loveleetcode", C = 'e' Output: [3, 2, 1, 0, 1, 0, 0, 1, 2, 2, 1, 0]
Note:post
S
string length is in [1, 10000].
C
is a single character, and guaranteed to be in string S
.S
and C
are lowercase.
這道題給了咱們一個字符串S,和一個字符C,讓咱們求字符串中每一個字符到字符C到最短距離,這裏的字符C可能有多個。題目中給的例子中就是有多個e,每一個e的位置必定是0,其餘位置的值是到其最近的e的距離。最原始粗獷的方法確定是對於每一個非e的字符,左右兩個方向來查找e,令博主感到意外的是,這種暴力搜索的方法竟然能夠經過OJ,太仁慈了啊,參見代碼以下:優化
解法一:url
class Solution { public: vector<int> shortestToChar(string S, char C) { int n = S.size(); vector<int> res(n, n); for (int i = 0; i < n; ++i) { if (S[i] == C) {res[i] = 0; continue;} int j = i + 1; while (j < n && S[j] != C) ++j; if (j < n) res[i] = j - i; j = i - 1; while (j >= 0 && S[j] != C) --j; if (j >= 0) res[i] = min(res[i], i - j); } return res; } };
通常來講,優化線性搜索的方法就是用二分搜索法,這裏咱們先把全部爲字符C的位置存入數組idx,由於是按順序遍歷的,因此idx數組也是有序的,這爲二分搜索創造了條件。而後對於數組中的每個位置,咱們都在idx數組中二分查找不小於該位置的數,這時候要分狀況討論一下,若是找不到這樣的數的時候,說明全部字符C的位置都在當前位置的左邊,那麼咱們取idx數組中最後一個數,就是左邊最近的一個字符C,求出距離便可。若是返回的是idx數組中的首數字,說明當前的位置是字符C,或者最近的字符C在右邊,那麼只要用這個首數字減去當前位置就是最近距離了。對於其餘狀況,左右兩邊都有字符C,因此咱們都要各自計算一下距離,而後取較小的那個便可,參見代碼以下:spa
解法二:code
class Solution { public: vector<int> shortestToChar(string S, char C) { vector<int> res, idx; for (int i = 0; i < S.size(); ++i) { if (S[i] == C) idx.push_back(i); } for (int i = 0; i < S.size(); ++i) { auto it = lower_bound(idx.begin(), idx.end(), i); if (it == idx.end()) res.push_back(i - *(--it)); else if (it == idx.begin()) res.push_back(*it - i); else { int d1 = *it - i, d2 = i - *(--it); res.push_back(min(d1, d2)); } } return res; } };
還有一種相似距離場的解法,與解法一不一樣的是,這裏是對於每一個是字符C的位置,而後分別像左右兩邊擴散,不停是更新距離,這樣當全部的字符C的點都擴散完成以後,每一個非字符C位置上的數字就是到字符C的最短距離了,參見代碼以下:htm
解法三:blog
class Solution { public: vector<int> shortestToChar(string S, char C) { int n = S.size(); vector<int> res(n, n); for (int i = 0; i < n; ++i) { if (S[i] != C) continue; res[i] = 0; for (int j = i + 1; j < n && S[j] != C; ++j) { res[j] = min(res[j], j - i); } for (int j = i - 1; j >= 0 && S[j] != C; --j) { res[j] = min(res[j], i - j); } } return res; } };
下面這種方法也是創建距離場的思路,不過更加巧妙一些,只須要正反兩次遍歷就行。首先進行正向遍歷,若當前位置是字符C,那麼直接賦0,不然看若是不是首位置,那麼當前位置的值等於前一個位置的值加1。這裏不用和當前的值進行比較,由於這個算出來的值不會大於初始化的值。而後再進行反向遍歷,要從倒數第二個值開始往前遍歷,用後一個值加1來更新當前位置的值,此時就要和當前值作比較,取較小的那個,參見代碼以下:leetcode
解法四:
class Solution { public: vector<int> shortestToChar(string S, char C) { vector<int> res(S.size(), S.size()); for (int i = 0; i < S.size(); ++i) { if (S[i] == C) res[i] = 0; else if (i > 0) res[i] = res[i - 1] + 1; } for (int i = (int)S.size() - 2; i >= 0; --i) { res[i] = min(res[i], res[i + 1] + 1); } return res; } };
參考資料:
https://leetcode.com/problems/shortest-distance-to-a-character/