Arrays 如何重新排列数组,使每个元素都比相邻元素大/小
例如,如果数字为:Arrays 如何重新排列数组,使每个元素都比相邻元素大/小,arrays,algorithm,sorting,Arrays,Algorithm,Sorting,例如,如果数字为: 30, 12, 49, 6, 10, 50, 13 阵列将是: [10, 6, 30, 12, 49, 13, 50] 如你所见: 6小于10和30,并且 49大于12和13,依此类推 这些数字都是不同的、真实的。我需要最有效的算法。假设数字都是不同的,最简单的方法可能是对数字进行排序,然后交错排序列表的前半部分和后半部分。这将保证高/低/高/低/高/低/。。。。你需要的图案 此算法是O(n log n),对于大多数目的来说,它应该足够有效,并且可能受益于标准库中优化
30, 12, 49, 6, 10, 50, 13
阵列将是:
[10, 6, 30, 12, 49, 13, 50]
如你所见:
- 6小于10和30,并且
- 49大于12和13,依此类推
这些数字都是不同的、真实的。我需要最有效的算法。假设数字都是不同的,最简单的方法可能是对数字进行排序,然后交错排序列表的前半部分和后半部分。这将保证高/低/高/低/高/低/。。。。你需要的图案 此算法是
O(n log n)
,对于大多数目的来说,它应该足够有效,并且可能受益于标准库中优化的排序例程
如果数字不明显,则可能没有解决方案(例如,如果数字都相等)我对复杂性不太了解,但我的想法如下
For even length lists:
(For our odd length example,
put 30 aside to make the list even)
1. Split the list into chunks of 2 => [[12,49],[6,10],[50,13]]
2. Sort each chunk => [[12,49],[6,10],[13,50]]
3. Reverse-sort the chunks by
comparing the last element of
one to the first element of
the second => [[12,49],[13,50],[6,10]]
For odd length lists:
4. Place the removed first element in
the first appropriate position => [30,12,49,13,50,6,10]
哈斯克尔代码:
import Data.List (sortBy)
import Data.List.Split (chunksOf)
rearrange :: [Int] -> [Int]
rearrange xs
| even (length xs) = rearrangeEven xs
| null (drop 1 xs) = xs
| otherwise = place (head xs) (rearrangeEven (tail xs))
where place x (y1:y2:ys)
| (x < y1 && y1 > y2) || (x > y1 && y1 < y2) = (x:y1:y2:ys)
| otherwise = place' x (y1:y2:ys)
place' x (y1:y2:ys)
| (x < y1 && x < y2) || (x > y1 && x > y2) = (y1:x:y2:ys)
| otherwise = y1 : (place' x (y2:ys))
rearrangeEven = concat
. sortBy (\a b -> compare (head b) (last a))
. map sort
. chunksOf 2
这可以在O(n)中完成:
当然,这是假设所有元素都是不同的,否则有时它会失败。有人把这个问题作为一个傻瓜贴了出来,但那里的解决方案比这里接受的解决方案好,所以我想我应该把它贴在这里 基本上,关键是每三个数字,它必须保持
ac
你看序列,把最大的数字换到中间。然后你增加2到下一个序列,如ac
,然后做同样的事情
从技术上讲,该解决方案仍然像已接受的解决方案一样在O(n)中运行,但它是一个更好的O(n)而且它更简单,因为中值算法很难实现。希望任何喜欢这个问题的人至少都能看到这个解决方案,如果有人感兴趣,我可以发布代码。你需要所有的解决方案还是只需要第一个?如果算法能生成所有的解决方案,那就太好了。但是算法必须时间效率最高。我觉得计算“所有解决方案”可能会有
O(n!)
复杂性…最好的解决方案不在这里检查一下,我认为这将是最好的方法[23]是一半[12]是另一半。所以[21 3 2]实际上是将两半交错。为了记录在案,@mikera说他的解决方案是针对不同的数字…取决于你先放哪一半。我会尝试想出一个反例。不需要完全排序。使用快速选择(中位数)算法,你可以在O(n)中找到中位数元素
并将数组分成大小,然后可以交错,O(n)
。是的,出于实际目的,快速的O(n log(n))
比慢速的O(n)
@a Webb更好-很好的一点,我同意不需要完全排序。不过如果您的语言有一个像样的排序实现(可能?)它可能会击败手动中值分区实现,并且使用.YMMV时会更简单/更少出错。这似乎不起作用。例如,对于[3,4,0,1,2]
它返回[1,0,2,4,3]
这是无效的,因为2
大于0
,但小于4
。在这种情况下,一个有效的解决方案是,例如[0,4,1,3,2]
。使用查找。@hammar这里有一件有趣的事情:我更改了一行,如下所示:prop_correct(Distinct xs)=odd(length xs)| valid(reseat xs)
我得到了:+++好的,通过了100次测试。
等一下!我们找不到O(n)中的中值通过选择,我们可以找到中位数的中位数,它不一定是中位数。它不在数组长度的50%,只是大于30%和小于70%。@Peggy:请阅读整篇维基百科文章,即使我们可以始终选择最小部分为30%的pivot,这对于quickselect为O(n)就足够了在最坏的情况下。是的,你是对的。在找到中间值的中间值后,我们可以通过找到第(n/2)个最小元素来再次找到中间值。(找到第k个最小元素iin O(n))。对不起
*Main> rearrange [30,12,49,6,10,50,13]
[30,12,49,13,50,6,10]
*Main> rearrange [1,2,3,4]
[3,4,1,2]