【820】单词的压缩编码(Short Encoding of Words)

给定一个单词列表,我们将这个列表编码成一个索引字符串 S 与一个索引列表 A。
例如,如果这个列表是 [“time”, “me”, “bell”],我们就可以将其表示为 S = “time#bell#” 和 indexes = [0, 2, 5]。
对于每一个索引,我们可以通过从字符串 S 中索引的位置开始读取字符串,直到 “#” 结束,来恢复我们之前的单词列表。
那么成功对给定单词列表进行编码的最小字符串长度是多少呢?

示例 1:

输入: words = [“time”, “me”, “bell”]
输出: 10
说明: S = “time#bell#” , indexes = [0, 2, 5] 。

个人思路:首先要理解题意,假设只有两个词A,B 那么就要检查A是否是B的后缀,或者B是A的后缀,这样显然麻烦,我们每次都要互相判断A或B是否是其的后缀,可以想到排序,这样就能保证判断一次, 以单词的末尾进行排序显然是不方便的,所以可以考虑先将单词反转,然后进行排序。

比如先有单词组

string[] words = { "outint", "like", "int", "dislike", "nt" };

首先单词倒序
在这里插入图片描述
然后单词组排序-正序
在这里插入图片描述
单词组排序-倒序
在这里插入图片描述
经过排序后,找相同值(前缀)就方便多了,只要比价相邻值就行了,这里要注意的是如果你是采用正序排序遍历比较时需要从后向前([4]=>[3]=>...=>[0]),倒序就从前向后([0]=>[1]=>...=>[4]),至于原因看上面的图很好明白。

C#

class Program
{
    static void Main(string[] args)
    {
        string[] words = { "outint", "like", "int", "dislike", "nt" };
        Console.WriteLine(MinimumLengthEncoding(words));
        Console.Read();
    }

    public static int MinimumLengthEncoding(string[] words)
    {
        /*首先要理解题意,假设只有两个词A,B 
         * 那么就要检查A是否是B的后缀,或者B是A的后缀,
         * 这样显然麻烦,我们每次都要互相判断A或B是否是其的后缀,
         * 可以想到排序,这样就能保证判断一次,
         * 以单词的末尾进行排序显然是不方便的,所以可以考虑先将单词反转,然后进行排序
         */

        //1.使用HashSet<>和SortedSet<>容器时间会明显变长,因为每次加入新元素都要排序去重,
        //所以这里使用List<>
        List<string> wordList = new List<string>();

        //2-1.遍历所有单词,将其反转
        foreach (string word in words)
        {
            //添加到List中
            wordList.Add(new string(word.Reverse().ToArray()));
        }

        //2-2去重,倒序
        //倒序,保证相同前缀的单词长的在前面
        wordList = wordList.Distinct().OrderByDescending(reWord => reWord).ToList();

        //3.首位作为初始值
        string curStr = wordList.First();       //初始索引字符串
        int count = curStr.Length;    //初始索引字符串长度

        //4.遍历单词集
        for (int i = 0; i < wordList.Count - 1; i++)
        {
            //加上每次比较后的结果,ref保证当前索引字符串更新
            count += CompareWords(ref curStr, wordList.ElementAt(i + 1));
        }

        //5.加上最后一个#
        return ++count;
    }

    /// <summary>
    /// 比较是否是前缀
    /// </summary>
    /// <param name="curStr">当前索引字符串</param>
    /// <param name="nextWord">下一个准备比较单词</param>
    /// <returns></returns>
    private static int CompareWords(ref string curStr, string nextWord)
    {
        int cnt = 0;

        //4-1.找出两个词中较短的数值
        int min = Math.Min(curStr.Length, nextWord.Length);
        
        //4-2.从后向前检查,
        //因为判断是否前缀,所以最后不同就不是前缀了,前面的就不用判断了
        for (int i = min - 1; i >= 0; i--)  
        {
            //i==0即直到最后一个也符合,即next是cur的前缀
            if (curStr[i] == nextWord[i] && i == 0)
            {
                cnt = 0;
            }
            //不同,即不是前缀,直接跳出
            else if (curStr[i] != nextWord[i]) 
            {
                curStr = nextWord + curStr;
                cnt = nextWord.Length + 1;//有一个#
                break;
            }
        }

        //4-3.最后返回本次计算后需要的长度
        return cnt;
    }
}

不同集合需要的时间
在这里插入图片描述

发布了62 篇原创文章 · 获赞 68 · 访问量 16万+

猜你喜欢

转载自blog.csdn.net/ZUFE_ZXh/article/details/105182566