[LeetCode] Shortest Distance to a Character 到字符的最短距離


 

Given a string S and a character C, return an array of integers representing the shortest distance from the character C in the string.

Example 1:

Input: S = "loveleetcode", C = 'e'
Output: [3, 2, 1, 0, 1, 0, 0, 1, 2, 2, 1, 0]

 

Note:

  1. S string length is in [1, 10000].
  2. C is a single character, and guaranteed to be in string S.
  3. All letters in S and C are lowercase.

 

這道題給了我們一個字符串S,和一個字符C,讓我們求字符串中每個字符到字符C到最短距離,這里的字符C可能有多個。題目中給的例子中就是有多個e,每個e的位置一定是0,其他位置的值是到其最近的e的距離。最原始粗獷的方法肯定是對於每個非e的字符,左右兩個方向來查找e,令博主感到意外的是,這種暴力搜索的方法居然可以通過OJ,太仁慈了啊,參見代碼如下:

 

解法一:

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,所以我們都要各自計算一下距離,然后取較小的那個即可,參見代碼如下:

 

解法二:

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的最短距離了,參見代碼如下:

 

解法三:

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來更新當前位置的值,此時就要和當前值做比較,取較小的那個,參見代碼如下:

 

解法四:

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/

https://leetcode.com/problems/shortest-distance-to-a-character/discuss/156216/2-pass-solution-in-C%2B%2B-(beats-100-submissions).

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM