算法特别篇_强大的static_注重细节的百倍优化(LeetCode_839_相似字符串组)

算法特别篇_强大的static优化

:思来想去,果然还是有必要记录一下这见证历史的时刻!学c++也有点时间了,关于代码基础细节反面,一直没有切身体会过有多大的影响。今天借这份每日一题记录一下细节上的百倍优化。
来源:力扣(LeetCode)
链接:LeetCode_839_相似字符串组

故事开始

首先题目

我打开力扣看到了今天的每日一题,又是困难,又是并查集,大体思路并不难,不会并查集的hxd去隔壁博客康康算法特别篇_并查集思路(LeetCode_778_水位上升的泳池中游泳) 。嗯,那我先把题扔上来。

  • 题目
    如果交换字符串 X 中的两个不同位置的字母,使得它和字符串 Y 相等,那么称 X 和 Y 两个字符串相似。如果这两个字符串本身是相等的,那它们也是相似的。
    例如,“tars” 和 “rats” 是相似的 (交换 0 与 2 的位置); “rats” 和 “arts” 也是相似的,但是 “star” 不与 “tars”,“rats”,或 “arts” 相似。
    总之,它们通过相似性形成了两个关联组:{“tars”, “rats”, “arts”} 和 {“star”}。注意,“tars” 和 “arts” 是在同一组中,即使它们并不相似。形式上,对每个组而言,要确定一个单词在组中,只需要这个词和该组中至少一个单词相似。
    给你一个字符串列表 strs。列表中的每个字符串都是 strs 中其它所有字符串的一个字母异位词。请问 strs 中有多少个相似字符串组?

  • 例子
    示例 1:
    输入:strs = [“tars”,“rats”,“arts”,“star”]
    输出:2
    示例 2:
    输入:strs = [“omv”,“ovm”]
    输出:1

  • 提示
    1 <= strs.length <= 100
    1 <= strs[i].length <= 1000
    sum(strs[i].length) <= 2 * 104
    strs[i] 只包含小写字母。
    strs 中的所有单词都具有相同的长度,且是彼此的字母异位词。

  • 备注
    字母异位词(anagram),一种把某个字符串的字母的位置(顺序)加以改换所形成的新词。

然后AC这道题目

下来我就动手了,很快啊!直接搓了一个并查集,给他ac了,但是效率感人(如下图),我刷力扣以来第一次这么惨淡,虽然ac了,但是伤害不高羞辱性极强。我能忍吗,我不能,我得优化它。算法特别篇_强大的static_注重细节的百倍优化(LeetCode_839_相似字符串组)

这边先贴一下最开始用的那份代码

class UnionFind
{
public:
    vector<int> parents;
    int count = 0;
    UnionFind(int n)
    {
        count = n;
        for(int i = 0;i<n;i++)
        {
            parents.push_back(i);
        }
    }
    int Find(int x)
    {  
        if(parents[x]==x) return x;
        return Find(parents[x]);
    }
    void marge(int x,int y)
    {
        if(Find(x)!=Find(y))
        {
            parents[Find(x)] = Find(y);
            count--;
        }
    }
};
class Solution {
public:
    int numSimilarGroups(vector<string>& strs) {
        UnionFind uf(strs.size());
        for(int i = 0;i<strs.size();i++)
            for(int j = i+1;j<strs.size();j++)
                if(strResemble(strs[i],strs[j])) uf.marge(i,j);
        return uf.count;
    }
    bool strResemble(string& a,string& b)
    {
        vector<int> ve;
        for(int i = 0;i<a.length();i++)
        {
            if(a[i]!=b[i])
            {
                ve.push_back(i);
            }
        }
        if(ve.size()==0) return true;
        if(ve.size()!=2) return false;
        if(a[ve[0]]==b[ve[1]]&&a[ve[1]]==b[ve[0]]) return true;
        return false;
    }
};

接着优化我的效率

  • 如上代码中,我只有一个方法的参数使用了引用,是因为感觉那些int参数无关紧要的,但是效率太低之后,我决定给我所有的参数都改成引用,但是效率仍旧感人。你可以理解成没变
  • 在苦思冥想之后,我觉得是因为频繁调用strResemble方法频繁创建了vector并且频繁申请空间导致,于是我当机立断,给这个vector改成了static,然后稍稍调整代码,但仍旧基本没有改变,让我直呼发生甚么事了。
  • 最终得出结论,问题可能并不出在声明vector上,二是出在push_back()这一手动态内存申请上,于是我把vector改成了静态数组,并取一个int变量去作为size来使用,全员静态,就不存在动态申请内存,导致内存使用过多的情况了,反复利用一块内存的优势就来了,看下图
    算法特别篇_强大的static_注重细节的百倍优化(LeetCode_839_相似字符串组)
    贴个最终代码
class UnionFind
{
public:
    vector<int> parents;
    int count = 0;
    UnionFind(int n)
    {
        count = n;
        parents = vector<int>(n);
        for(int i = 0;i<n;i++)
        {
            parents[i] = i;
        }
    }
    int Find(int& x)
    {  
        if(parents[x]==x) return x;
        return Find(parents[x]);
    }
    void marge(int& x,int& y)
    {
        if(Find(x)!=Find(y))
        {
            parents[Find(x)] = Find(y);
            count--;
        }
    }
};
class Solution {
public:
    int numSimilarGroups(vector<string>& strs) {
        UnionFind uf(strs.size());
        for(int i = 0;i<strs.size();i++)
            for(int j = i+1;j<strs.size();j++)
                if(strResemble(strs[i],strs[j])) uf.marge(i,j);
        return uf.count;
    }
    bool strResemble(string& a,string& b)
    {
        static int p[2];
        static int boo;
        boo = 0;
        for(int i = 0;i<a.length();i++)
        {
            if(a[i]!=b[i])
            {
                if(boo>1) return false;
                p[boo] = i;
                boo++;
            }
        }
        if(boo==0) return true;
        if(boo==1) return false;
        if(a[p[0]]==b[p[1]]&&a[p[1]]==b[p[0]]) return true;
        return false;
    }
};
上一篇:leetcode_990等式方程的课满足性(并查集)


下一篇:算法:二叉树公共父节点