Hot100-Day31-T763划分字母区间

4 阅读2分钟

Day31[26/3/31]T763划分字母区间

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。例如,字符串 "ababcc" 能够被分为 ["abab", "cc"],但类似 ["aba", "bcc"]["ab", "ab", "cc"] 的划分是非法的。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s

返回一个表示每个字符串片段的长度的列表。

示例 1:

输入:s = "ababcbacadefegdehijhklij"
输出:[9,7,8]
解释:
划分结果为 "ababcbaca""defegde""hijhklij" 。
每个字母最多出现在一个片段中。
像 "ababcbacadefegde", "hijhklij" 这样的划分是错误的,因为划分的片段数较少。

示例 2:

输入:s = "eccbbbbdec"
输出:[10]

提示:

  • 1 <= s.length <= 500
  • s 仅由小写英文字母组成

解题思路

主要的思路是:任何元素的第一次出现和最后一次出现的位置构成一个区间,然后将有重叠的区间合并,到最后合并不了,就是答案了。

如何用贪心思想来完成这个区间合并?

首先,遍历整个数组构建一个哈希表,存储每个元素最后一次出现的位置。

后续,你从头遍历数组的时候,就查哈希表就可以了,这可以省好多时间。

然后来个例子:

已经确定了 nums[0] 这个元素最后一次出现是在 nums[3]

那么你只需要检查 nums[1], nums[2] 这两个元素最后一次出现在哪

如果最后一次出现不超过 3,那么 [0,3] 就是一个确定的区间了

否则,假设 nums[2] 在 nums[9] 上也出现了,那么你下一次就继续检查

nums[3+1] 到 nums[9] 之间有没有最后一次出现在超过 [9] 的

重复上述操作即可。

Code

#include <iostream>
#include <vector>
#include <unordered_map>
#include <numeric>

using namespace std;

class Solution
{
public:
    vector<int> partitionLabels(string s)
    {
        unordered_map<char, int> mp;
        vector<int> result;

        // 1. 建表存最后位置
        for (int i = 0; i < s.size(); i++)
        {
            mp[s[i]] = i;
        }

        // 2. 一段一段找区间
        int left = 0, right = mp[s[0]]; // 单次寻找的左右区间
        int next_range = mp[s[0]];      // 下次寻找的右区间

        while (left < s.size())
        {
            if (mp[s[left]] == left)
            {
                result.push_back(1);
                left++;
                right = mp[s[left]];
                continue;
            }

            int old_left = left;
            while (left <= right)
            {
                for (int i = left; i < right; i++)
                {
                    if (mp[s[i]] > next_range)
                    {
                        next_range = mp[s[i]];
                    }
                }
                left = right + 1;
                right = next_range;
            }

            result.push_back(right - old_left + 1);
            right = mp[s[left]];
        }
        result.pop_back();
        result.push_back(s.size() - accumulate(result.begin(), result.end(), 0));
        return result;
    }
};

auto main() -> int
{
    Solution sol;
    // string s = "ababcbacadefegdehijhklij";
    string s = "eccbbbbdec";
    // string s = "dccccbaabe";
    // string s = "vhaagbqkaq";

    cout << "result : " << endl;
    cout << "[ ";
    for (const auto &nums : sol.partitionLabels(s))
    {
        cout << "(" << nums << ")" << ',';
    }
    cout << " ]" << endl;
}