按顺序排列列表

时间:2011-07-03 13:26:40

标签: algorithm

我有一个清单{10,5,3,9,12}。我需要把它转换成像这样的{3,1,0,2,4}。我的意思是将0分配给最小值,将1分配给下一个最小值。

我的代码:

     list = {2,3,10,5,1};
     for (int i =list.Count-1; i >= 0 ; i--)
        {

            var maxNo = list.Max();
            var smallIndex = list.IndexOf(maxNo);
            list[smallIndex] = i * -1;

        }
        for (int i = 0; i < list.Count; i++)
        {
            list[i] = list[i] * -1;
        }
        // prints {1,2,4,3,0}

注意:列表仅包含正数。

以上代码是否正常。 需要帮助。

5 个答案:

答案 0 :(得分:5)

基本上你只需要对列表进行排序。看看排序算法。

您可以构建另一个包含原始数字的列表,该数字与从0到列表长度的整数索引配对,如{{10,0}, {5,1}, {3,2}, {9,3}, {12,4}},使用您的编程语言的内置排序函数对此列表进行排序,然后提取整数索引

编辑:你的程序会运行,但它相当hackish(使用那些负数),效率非常低。它遍历列表两次,每个元素找到最大值并找到最大值的索引。我建议你阅读有关排序算法的内容。

EDIT2:实际的实现可能意味着为sort使用不同的比较函数:假设您的原始列表被称为array。创建另一个数组idx = {0,1,2,3,4},并且不是基于比较函数x < y而是array[x] < array[y]对其进行排序。

<强> CORRECTION

这里的算法找到了所需要的逆置换。正如唐提到的那样,你需要做另一种来颠倒排列。

答案 1 :(得分:3)

这是O(2 (n log n))因为它排序两次。首先,它将列表转换为按(index, value)排序的v列表,并添加排序后的位置s并按索引排序,然后提取排序后的位置。

>>> list( s for s, i in sorted( ( (s,i) for s,(i,v) in enumerate(sorted( ( (i,v) for i,v in enumerate([10,5,3,9,12]) ), key=lambda t: t[1] )) ), key=lambda t: t[1] ) )
[3, 1, 0, 2, 4]

或多行(请注意,这可能会使内存保留的时间超过所需时间):

def arrange(l):
    a = sorted( ( (i,v) for i,v in enumerate(l) ), key=lambda t: t[1] )
    b = sorted( ( (s,i) for s,(i,v) in enumerate(a) ), key=lambda t: t[1] )
    return list( s for s, i in b )

print arrange([10,5,3,9,12])

答案 2 :(得分:2)

您的算法适用于非负整数列表,但正如其他人所说,由于重复的最大计算,它的效率不高。

我不确定我在这里增加多少,因为Dan D的答案是正确的,但也许更多的解释会有所帮助......

{2,3,10,5,1}映射到{1,2,4,3,0}的示例中,您要查找的是原始列表在排序列表中占据的索引列表。

最自然的方法是通过排序,索引和“取消分类”如下(并且在Dan D的有点terser解决方案中实现):

为原始数据添加索引列:

{2,3,10,5,1} => {(2,0), (3,1), (10,2), (5,3), (1,4)}

按原始列排序:

{(2,0), (3,1), (10,2), (5,3), (1,4)} => {(1,4), (2,0), (3,1), (5,3), (10,2)}

添加另一个索引列:

{(1,4), (2,0), (3,1), (5,3), (10,2)} => {(1,4,0), (2,0,1), (3,1,2), (5,3,3), (10,2,4)}

通过对第一个索引列进行排序来回到原始订单:

{(1,4,0), (2,0,1), (3,1,2), (5,3,3), (10,2,4)} => {(2,0,1), (3,1,2), (10,2,4), (5,3,3), (1,4,0)}

删除原始列和第一个索引列,只保留在中间添加的索引,该索引现已放到正确的位置:

{(2,0,1), (3,1,2), (10,2,4), (5,3,3), (1,4,0)} => {1,2,4,3,0}

无论原始列表的数据类型如何,只要可以对其进行排序,此策略就可以正常工作。

由于问题肯定涉及一些排序,我强烈怀疑你可以做得比这更好的效率。添加和删​​除列是线性的,排序两次并不比排序一次差。

答案 3 :(得分:1)

这样可行,但每个项目使用list.IndexOf(maxNo)一次会产生O(n ^ 2)的时间。排序列表会更有效,除了维护一个索引数组,使得ix [i]是第i个最大项。换句话说,比较list [i],但在排序中分配ix [i]。这也适用于负数。

答案 4 :(得分:0)

对列表的副本进行排序,将其放入带有列表项作为键的键控数据结构中,并将排序列表中的位置作为值。使用键控数据结构映射原始列表。 knlogn + 2n = O(nlogn)表现。