1. 程式人生 > >763. Partition Labels的C++解法

763. Partition Labels的C++解法

1.從第一個字母開始,找到它最後一次出現的位置,那麼這一段就是當前最短的一節(因為一節需要把同一個字母全都包含進去)。但是在這一節中如果有別的字母在之後又出現了,這一節的長度需要延長到那個字母最後一次出現的位置。

2.同一個字母第一次遇到的時候其首尾之間的距離將是最大的,所以一個字母只要找一次記下來即可。

演算法主要分為兩個迴圈,第一個迴圈找到每個字母的首位最大距離(記錄頭和尾)。第二個迴圈順序計算,如果某個字母的頭位置超出了上一節的結尾,說明上一節結束了,開始新的一節。兩個迴圈好像也可以合併成一個迴圈,我沒有做,速度還是很快,4msbeat99%。

class Solution {
public:
	vector<int> partitionLabels(string S) {
		vector<int> res;
		int n = S.length();
		vector<pair<int, int>> index(26);
		vector<bool> record(26,false);
		for (int i = 0; i < n;i++)
		{
			if (record[S[i] - 'a'] == false)
			{
				int j = n - 1;
				while (S[j] != S[i]) j--;
				index[S[i] - 'a'] = make_pair(i, j);
                record[S[i] - 'a'] = true;
			}
		}
		int head = index[S[0] - 'a'].first;
		int tail = index[S[0] - 'a'].second;
		for (int i = 0; i < n; i++)
		{
			if (index[S[i] - 'a'].first > tail)
			{
				res.push_back(tail - head + 1);
				head = index[S[i] - 'a'].first;
				tail = index[S[i] - 'a'].second;
			}
			else if (index[S[i] - 'a'].second > tail) tail = index[S[i] - 'a'].second;
		}
        res.push_back(tail - head + 1);
		return res;
	}
};

emmmm看了一下別人的做法,發現其實不用記錄首位置:

class Solution {
public:
    vector<int> partitionLabels(string S) {
        vector<int> last(26, 0);
        int length = (int)S.length();
        for (int i = 0; i < length; i++) {
            last[S.at(i) - 'a'] = i;
        }

        int start = 0, end = 0;
        vector<int> partition;
        for (int i = 0; i < length; i++) {
            end = max(last[S.at(i) - 'a'], end);
            if (end == i) {
                partition.push_back(end - start + 1);
                start = i + 1;
            }
        }

        return partition;
    }
};