Desmos, 94 93 bytes
g(M,j)=j-max([1...j]0^{mod(M,2)})
f(L)=L[[i+g(L[n...1],n+1-i)-g(L,i)fori=[1...n]]]
n=L.length
Try it on Desmos!
*-1 byte thanks to @AidenChow (remove space after for
)
How it works
g(M,j)
gives the difference between j
and the greatest index less than (or equal to) j
of an even entry in M
. For example, g([0,2,4,1,3,5,7,6,8],6) = 3
because the 6th element in the list is 5, and the last even entry before it is 4, which is 3 elements earlier.
f(L)
is the solution to the challenge. It's of the form L[[h(i)for i=[1...n]]]
, which is a list indexing: h(i)
gives the index of the value in L
that should be at index i
in the result list.
The main difficulty lies in h(i)
, defined as h(i) = i+g(L[n...1],n+1-i)-g(L,i)
. Note that g(M,j) = 0
whenever M[j]
is even, so h(i)=i
if L[i]
is even (this corresponds to even entries not moving) since L[n...1][n+1-i]=L[i]=even
If L[i]
is odd then we have a more complicated story: g(L,i)
gives the distance to the element before the start of the odd run, and g(L[n...1],n+1-i)
gives the distance to the element after the end of the odd run. Then g(L[n...1],n+1-i)-g(L,i)
says how much closer the element is to the end of the run than the start of the run. For example, for L=[0,2,4,1,3,5,7,6,8]
and i=6
, this difference is -1
, so L[6]
has to move 1 element to the left, to where the 3
is currently.
In general regarding the difference g(L[n...1],n+1-i)-g(L,i)
:
- if the difference is positive, then the element is closer to the left than the right, and it needs to move right by the value of the difference
- if the difference is negative, then the element is closer to the right than the left, and it needs to move left by the negative of the difference
- if the difference is zero, then the element is at the center of an odd-length run, so it doesn't need to move at all.