问题 拖曳一个字符串,使两个相邻的字母不相同


我一直试图解决这个面试问题,这个问题要求改变一个字符串,这样两个相邻的字母就不一样了 例如,

ABCC - > ACBC

我正在考虑的方法是

1)迭代输入字符串并存储(字母,频率)   配对 一些 采集

2)现在通过拉出我们不仅仅拉动的最高频率(即> 0)字母来构建结果字符串

3)每当我们拉信时更新(减少)频率

4)如果所有字母的频率为零,则返回结果字符串

5)如果我们只剩下一个频率大于1的字母,则返回错误

通过这种方法,我们可以为最后一个保存更珍贵(不太频繁)的字母。但为了实现这一点,我们需要一个集合,它可以让我们有效地查询密钥,同时根据值对其进行有效排序。就像是 这个 除了我们需要在每次检索字母后对集合进行排序时才会有效。

我假设是Unicode字符。

关于使用什么集合的任何想法?还是另一种方法?


7660
2017-08-26 17:34


起源

看起来像是重复的 stackoverflow.com/questions/37040164/...。 - Vijay
也许,但我在问是否有可以用于此目的的C#集合/数据结构 - NGambit
Bogosort直到满足标准! - itsme86
这与均匀分配物品的问题有关。看到 stackoverflow.com/q/37452547/56778。可能被视为重复? - Jim Mischel


答案:


您可以按频率对字母进行排序,将排序后的列表分成两半,然后依次从两半中取出字母来构造输出。这需要一个单一的。

例:

  • 初始字符串: ACABBACAB
  • 分类: AAABBBCC
  • 分裂: AAAB+BBCC
  • 结合: ABABACBC

如果最高频率的字母数超过字符串长度的一半,则问题无法解决。


12
2017-08-26 17:46



您不需要按频率排序;只是排序(然后从下半部分开始交错)。我不确定你是如何按频率对字母进行排序的;你需要先排序然后对频率进行排序,不是吗? - rici
@rici你是对的,只是排序可能实际上有些小心(比方说, ABBBC 需要分裂 ABB+BC 并开始合并 BC)。按频率排序需要计算频率,将它们与字母一起收集和分类,最后从计数器重建阵列。 - dasblinkenlight
实际上,你有一个奇数长度向量和一个字母频率的情况只有这个长度的一半是复杂的,但是如果有必要的话,很容易检测到这种情况和特殊情况。 - rici
@AndrewHanlon我很想知道一个可以作为O(n)实现的算法如何效率最高,特别是与O(n ^ 2)相比。 - dasblinkenlight
@dasblinkenlight并非所有O(n)算法都相同。组合需要额外的循环。按大小排序是许多不需要的额外工作。因此,首先修改排序算法当然可以创建更有效的算法。 - Andrew Hanlon


为什么不使用两个数据结构:一个用于排序(如堆)和一个用于密钥检索,如字典?


1
2017-08-26 17:46





接受的答案可能会产生正确的结果,但可能不是这个采访脑筋急转弯的“正确”答案,也不是最有效的算法。

简单的答案是采用基本排序算法的前提,并改变循环谓词以检查邻接而不是大小。这确保了“排序”操作是唯一需要的步骤,并且(像所有良好的排序算法一样)可以完成最少量的工作。

下面是一个c#示例,类似于插入排序以简化(虽然可以类似地调整许多排序算法):

string NonAdjacencySort(string stringInput)
{
    var input = stringInput.ToCharArray();

    for(var i = 0; i < input.Length; i++)
    {
        var j = i;

        while(j > 0 && j < input.Length - 1 && 
              (input[j+1] == input[j] || input[j-1] == input[j]))
        {
            var tmp = input[j];
            input[j] = input[j-1];
            input[j-1] = tmp;           
            j--;
        }

        if(input[1] == input[0])
        {
            var tmp = input[0];
            input[0] = input[input.Length-1];
            input[input.Length-1] = tmp;
        }
    }

    return new string(input);
}

标准插入排序的主要变化是函数必须向前看和向后看,因此需要回绕到最后一个索引。

最后一点是这种类型的算法优雅地失败,提供了最少的连续字符(在前面分组)的结果。


0
2017-08-31 16:15



“接受的答案[不是]一种有效的算法。”介意解释O(n ^ 2)如何比O(n)更有效? - dasblinkenlight
@dasblinkenlight插入排序仅用作一个简单示例。可以类似地调整具有更好的大O的排序算法。 - Andrew Hanlon
我真的很好奇看到一个具有更好的大I的排序算法可以“类似”调整,因为你当前的算法很大程度上依赖于相邻字母的比较。 - dasblinkenlight
当无法构造正确的输出时,您的算法如何检测情况? - dasblinkenlight
@dasblinkenlight在这种情况下,只需比较char [0]和char [1],如果它们相同则解决方案没有答案。 - Andrew Hanlon