按字典序排列最小的等效字符串【力扣】

问题描述

给出长度相同的两个字符串:A 和 B,其中 A[i] 和 B[i] 是一组等价字符。举个例子,如果 A = "abc" 且 B = "cde",那么就有 'a' == 'c', 'b' == 'd', 'c' == 'e'

等价字符遵循任何等价关系的一般规则:

  • 自反性:’a’ == ‘a’
  • 对称性:’a’ == ‘b’ 则必定有 ‘b’ == ‘a’
  • 传递性:’a’ == ‘b’ 且 ‘b’ == ‘c’ 就表明 ‘a’ == ‘c’

例如,A 和 B 的等价信息和之前的例子一样,那么 S = "eed""acd" 或 "aab",这三个字符串都是等价的,而 "aab" 是 S 的按字典序最小的等价字符串

利用 A 和 B 的等价信息,找出并返回 S 的按字典序排列最小的等价字符串。

问题理解

此问题是先要将字母分组,再将分组的字母当成字典来转换新字符串。

问题分析

用并查集,中间一个数组来过渡,这个数组存放每个字母对应的最小等价字母。

方法实现,分两个步骤,查找和合并。查找是指在数组中查找当前字母对应的最小字母;合并是指修改两个字母的最小字母为同一个最小字母。

方法复杂度是log(nlogn)。

其他

此题如果用vector,map来做非常麻烦,转化成字母来考虑,非常简单清晰,并查集思想相当牛逼。

链接

class Solution {
public:
    vector<int> p; //p存储字母所在集合的最小字母值(字母ascii码-'a')
    
    int find(int x)
    {
        if (p[x] == -1) {  //如果最小字母是默认值
            return x;    //自己本身是最小值
        }
        else    //否则
        {
            return p[x] = find(p[x]);    //递归找到最小值,然后更新当前字母的最小值为最小值
        }
    }
    void merge(int x, int y)
    {
        int min_x = find(x);    //找到x的最小值
        int min_y = find(y);    //找到y的最小值
        if (min_x == min_y)    //相等
            return;        //已经合并,不用考虑
        else if (min_x < min_y)    //x小
        {
            p[min_y] = min_x;    // y降低到x的最小值
        }
        else
        {
            p[min_x] = min_y;    // x降低到y的最小值
        }
    }
    string smallestEquivalentString(string A, string B, string S) {
        p = vector<int>(26, -1);    //初始值都为-1
        int len = A.size();
        string ansStr = "";
        for(int i = 0; i < len; i ++)
        {
            merge(A[i] - 'a', B[i] - 'a');    //合并每组等价字母
        }
        for(char c : S)
        {
            ansStr += find(c - 'a') + 'a';    //找到当前字母的最小值加上'a'转化成字母输出。
        }
        return ansStr;
    }
};

 

点赞