每日一道leetcode

1657. 确定两个字符串是否接近 - 力扣(LeetCode)

题目

如果可以使用以下操作从一个字符串得到另一个字符串,则认为两个字符串 接近 :

  • 操作 1:交换任意两个 现有 字符。
    • 例如,abcde -> aecdb
  • 操作 2:将一个 现有 字符的每次出现转换为另一个 现有 字符,并对另一个字符执行相同的操作。
    • 例如,aacabb -> bbcbaa(所有 a 转化为 b ,而所有的 b 转换为 a )

你可以根据需要对任意一个字符串多次使用这两种操作。

给你两个字符串,word1 和 word2 。如果 word1  word2 接近 ,就返回 true ;否则,返回 false 

示例 1:

输入:word1 = "abc", word2 = "bca"
输出:true
解释:2 次操作从 word1 获得 word2 。
执行操作 1:"abc" -> "acb"
执行操作 1:"acb" -> "bca"

示例 2:

输入:word1 = "a", word2 = "aa"
输出:false
解释:不管执行多少次操作,都无法从 word1 得到 word2 ,反之亦然。

示例 3:

输入:word1 = "cabbba", word2 = "abbccc"
输出:true
解释:3 次操作从 word1 获得 word2 。
执行操作 1:"cabbba" -> "caabbb"
执行操作 2:"caabbb" -> "baaccc"
执行操作 2:"baaccc" -> "abbccc"

提示:

  • 1 <= word1.length, word2.length <= 105
  • word1 和 word2 仅包含小写英文字母

思路

  1. 可以任意进行交换,其实相当于可以将里面的字母按序排列,故考点和位置无关;
  2. 因为可以任意换位,字母也可以相互变换,所以只用判断字母集是否相等以及各个字母出现的频数(不需要一一对应)情况是否是一致的即可。
  3. 初步学习上次学到的map库来进行字母和数字的统计;
  4. 在统计过程中确定字母集是否相等;
  5. 统计完成后将频数按顺序排列,判断其频数的数量情况是否一致。

代码实现

class Solution {
public:
    bool closeStrings(string word1, string word2) {
        map char_cnt1, char_cnt2;
        vector cnt1, cnt2;
        map::iterator iter;
        for(int i = 0; i < word1.length(); i++) {
            char_cnt1[word1[i]]++;
        }
        for(int i = 0; i < word2.length(); i++) {
            char_cnt2[word2[i]]++;
            if(!char_cnt1.count(word2[i])) return false; # 若出现新字母则说明字母集不一致
        }
        for(iter = char_cnt1.begin(); iter != char_cnt1.end(); iter++) {
            cnt1.push_back(iter->second);
        }
        for(iter = char_cnt2.begin(); iter != char_cnt2.end(); iter++) {
            cnt2.push_back(iter->second);
        }
        sort(cnt1.begin(), cnt1.end());
        sort(cnt2.begin(), cnt2.end());
        if(cnt1.size() != cnt2.size()) return false; # 也是字母集的判断,这里是补充word1包含word2的情况
        for(int i = 0; i < cnt1.size(); i++) {
            if(cnt1[i] != cnt2[i]) return false; # 频数按序排列后若不一致即是频数情况不一致
        }
        return true;
    }
};

复杂度分析

  • 时间复杂度:map是基于红黑树结构实现的,增删改查的复杂度都是O(log N),再循环中泽其时间复杂度为O(N*logN)。sort函数的时间复杂度是O(N*logN),所以总体的时间复杂度为O(N*logN)。
  • 空间复杂度:O(N)。

函数学习

  • 在进行查询后,发现set和unordered_set,map和unordered_map中,前者都是基于红黑树进行实现的,增删改查的时间复杂度都是O(logN),而后者都是基于哈希表实现的(所以哈希集合和哈希字典应该是unordered_set和unordered_map在此纠正一下之前的错误),所以在冲突不强烈的情况下增删查的时间复杂度是可以达到O(1)的,只有在冲突比较多的情况下(最坏时间复杂度)会达到O(N)。

官方题解

看了一下官方题解,方法更高效,在此也理解一下(以下的C为26,即字母数):

  1. 因为只出现小写字母,所以统计完全可以只设计一个统计字母的数组,让字母按字母序排列统计即可,这样统计时的时间复杂度就从原来的O(N*logN)降低到了O(N)。
  2. 接着再用一次遍历确定字母集是否一致,即判断是否字母同时为0或同时不为0。——时间复杂度O(C)。
  3. 最后再进行排序,只要数组相等,其频数情况也就相等了。——时间复杂度O(C*logC)。

故总的时间复杂度为O(max(n1,n2)+ClogC),空间复杂度为O(C),显然比我的实现要快,具体代码可以参考官方题解。

你可能感兴趣的:(leetcode训练,leetcode,算法,职场和发展,c++)