How to rearrange an array in such a way that each element is greater/smaller than its neighbours

前端 未结 4 1626
孤独总比滥情好
孤独总比滥情好 2020-12-29 10:50

For example, if the numbers are:

30, 12, 49, 6, 10, 50, 13

The array will be:

[10, 6, 30, 12, 49, 13, 50]
<
相关标签:
4条回答
  • 2020-12-29 11:08

    Assuming the numbers are all distinct, the easiest way is probably to sort the numbers then interleave the first and second halves of the sorted list. This will guarantee the high/low/high/low/high/low/.... pattern that you need.

    This algorithm is O(n log n) which should be efficient enough for most purposes, and may benefit from optimised sorting routines in your standard library.

    If the numbers are not distinct, then it is possible that there is no solution (e.g. if the numbers are all equal)

    0 讨论(0)
  • 2020-12-29 11:09

    I'm not too knowledgeable about complexity, but here's my idea.

    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]
    

    Haskell code:

    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
    

    Output:

    *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]
    
    0 讨论(0)
  • 2020-12-29 11:14

    This can be done in O(n):

    1. Find median in O(n) (description is available in Wikipedia
    2. Put every element larger than the median on odd places and every smaller element - on even places

    Of course, this assumes that all elements are distinct, otherwise sometimes it will fail.

    0 讨论(0)
  • 2020-12-29 11:27

    Someone posted this question as a dupe to this but the solution over there is better than the accepted solution here so I figured I'd post it here.

    Basically the key is for every three numbers where it has to hold that a < b > c you look at the sequence and swap the biggest number into the center. Then you increment by 2 to get to the next sequence like a < b > c and do the same thing.

    Technically the solution still runs in O(n) like the accepted solution, but it is a better O(n) and it is much simpler because the median of medians algo is tricky to implement. Hopefully anyone who favorited this problem will at least see this solution, I can post the code if anyone is interested.

    0 讨论(0)
提交回复
热议问题