# @file pendulum.002.rb
# Question-8 from some problem set.
# @date 03/28/2026
# Rearrange the word so the character with the smallest ASCII value
# is placed at the center, the second smallest to its right and the
# third to its left and so on.
#
# Example-1: In : COMPUTER
# Out: TPMCEORU
#
# Example-2: In : SCIENCE
# Out: SIECCEN
#
# The problem specifies characters should be rearranged by invoking
# the function 'int minimumCharIndex(String str)'.
def minimum_char_index(s)
s.index(s.each_byte.min.chr) # faster than each_char.min
end
def pendulum_0(s)
s = s.dup
n = s.size
m = (n-1) / 2
r = []
n.times do |i|
k = minimum_char_index(s)
m = i.even? ? m-i : m+i
r[m] = s.slice!(k)
end
r.join
end
# Breaking the rules a bit.
def minimum_index(a, first, last)
subarray = a[first...last]
subarray.index(subarray.min) + first
end
def pendulum_0_1(s)
s = s.bytes
n = s.size
m = (n-1) / 2
r = []
n.times do |i|
k = minimum_index(s, i, n)
m = i.even? ? m-i : m+i
r[m] = s[k]
s[k] = s[i]
end
r.map(&:chr).join
end
def swap!(a, i, j)
a[i], a[j] = a[j], a[i] if i != j
a
end
def selectsort!(a)
(a.size-1).times do |i|
swap!(a, i, minimum_index(a, i, a.size))
end
a
end
def pendulum_0_2(s)
n = s.size
m = (n-1) / 2
r = []
selectsort!(s.bytes).each_with_index do |x, i|
r[m = i.even? ? m-i : m+i] = x
end
r.map(&:chr).join
end
# Breaking the rules a bit more.
def pendulum_1(s)
n = s.size
m = (n-1) / 2
r = []
s.chars.sort!.each_with_index do |x, i|
r[m = i.even? ? m-i : m+i] = x
end
r.join
end
def pendulum_2(s)
r = []
s.chars.sort!.each_with_index do |x, i|
r.public_send(i.even? ? :unshift : :push, x)
end
r.join
end
def pendulum_3(s)
t = s.chars.sort!
l, r = t.drop(1).partition.each_with_index{|_, i| i.odd?}
(l.reverse + t.take(1) + r).join
end
def pendulum_4(s)
l, r = (1...s.size).partition{|i| i.even?}
s.chars.sort!.values_at(*l.reverse, 0, *r).join
end
# Main.
def test(f)
ss = ["", "a", "ba", "bca", "computer", "science"]
rs = ["", "a", "ab", "cab", "tpmceoru", "sieccen"]
ss.zip(rs) do |s, r|
s = f.call(s)
if s != r
puts ".Failed: expected `#{r}' got `#{s}'"
return
end
end
puts ".Passed"
end
def time(f)
def choices(pool, n)
n.times.map{pool.sample}
end
symbols = ('a'..'z').to_a
elapsed = 0
12.times do |i|
s = choices(symbols, 2**i).join
t = Time.now
f.call(s)
elapsed += Time.now - t
end
printf(".Elapsed: %.6fs\n", elapsed)
end
fs = [
:pendulum_0,
:pendulum_0_1,
:pendulum_0_2,
:pendulum_1,
:pendulum_2,
:pendulum_3,
:pendulum_4
]
fs.map(&method(:method)).each do |f|
puts f.name
test(f)
time(f)
end
IyBAZmlsZSBwZW5kdWx1bS4wMDIucmIKIyBRdWVzdGlvbi04IGZyb20gc29tZSBwcm9ibGVtIHNldC4KIyBAZGF0ZSAwMy8yOC8yMDI2CgojIFJlYXJyYW5nZSB0aGUgd29yZCBzbyB0aGUgY2hhcmFjdGVyIHdpdGggdGhlIHNtYWxsZXN0IEFTQ0lJIHZhbHVlCiMgaXMgcGxhY2VkIGF0IHRoZSBjZW50ZXIsIHRoZSBzZWNvbmQgc21hbGxlc3QgdG8gaXRzIHJpZ2h0IGFuZCB0aGUKIyB0aGlyZCB0byBpdHMgbGVmdCBhbmQgc28gb24uCiMKIyBFeGFtcGxlLTE6IEluIDogQ09NUFVURVIKIyAgICAgICAgICAgIE91dDogVFBNQ0VPUlUKIwojIEV4YW1wbGUtMjogSW4gOiBTQ0lFTkNFCiMgICAgICAgICAgICBPdXQ6IFNJRUNDRU4KIwojIFRoZSBwcm9ibGVtIHNwZWNpZmllcyBjaGFyYWN0ZXJzIHNob3VsZCBiZSByZWFycmFuZ2VkIGJ5IGludm9raW5nCiMgdGhlIGZ1bmN0aW9uICdpbnQgbWluaW11bUNoYXJJbmRleChTdHJpbmcgc3RyKScuCgpkZWYgbWluaW11bV9jaGFyX2luZGV4KHMpCiAgcy5pbmRleChzLmVhY2hfYnl0ZS5taW4uY2hyKSAjIGZhc3RlciB0aGFuIGVhY2hfY2hhci5taW4KZW5kCgpkZWYgcGVuZHVsdW1fMChzKQogIHMgPSBzLmR1cAogIG4gPSBzLnNpemUKICBtID0gKG4tMSkgLyAyCiAgciA9IFtdCiAgbi50aW1lcyBkbyB8aXwKICAgIGsgPSBtaW5pbXVtX2NoYXJfaW5kZXgocykKICAgIG0gPSBpLmV2ZW4/ID8gbS1pIDogbStpCiAgICByW21dID0gcy5zbGljZSEoaykKICBlbmQKICByLmpvaW4KZW5kCgojIEJyZWFraW5nIHRoZSBydWxlcyBhIGJpdC4KCmRlZiBtaW5pbXVtX2luZGV4KGEsIGZpcnN0LCBsYXN0KQogIHN1YmFycmF5ID0gYVtmaXJzdC4uLmxhc3RdCiAgc3ViYXJyYXkuaW5kZXgoc3ViYXJyYXkubWluKSArIGZpcnN0CmVuZAoKZGVmIHBlbmR1bHVtXzBfMShzKQogIHMgPSBzLmJ5dGVzCiAgbiA9IHMuc2l6ZQogIG0gPSAobi0xKSAvIDIKICByID0gW10KICBuLnRpbWVzIGRvIHxpfAogICAgayA9IG1pbmltdW1faW5kZXgocywgaSwgbikKICAgIG0gPSBpLmV2ZW4/ID8gbS1pIDogbStpCiAgICByW21dID0gc1trXQogICAgc1trXSA9IHNbaV0KICBlbmQKICByLm1hcCgmOmNocikuam9pbgplbmQKCmRlZiBzd2FwIShhLCBpLCBqKQogIGFbaV0sIGFbal0gPSBhW2pdLCBhW2ldIGlmIGkgIT0gagogIGEKZW5kCgpkZWYgc2VsZWN0c29ydCEoYSkKICAoYS5zaXplLTEpLnRpbWVzIGRvIHxpfAogICAgc3dhcCEoYSwgaSwgbWluaW11bV9pbmRleChhLCBpLCBhLnNpemUpKQogIGVuZAogIGEKZW5kCgpkZWYgcGVuZHVsdW1fMF8yKHMpCiAgbiA9IHMuc2l6ZQogIG0gPSAobi0xKSAvIDIKICByID0gW10KICBzZWxlY3Rzb3J0IShzLmJ5dGVzKS5lYWNoX3dpdGhfaW5kZXggZG8gfHgsIGl8CiAgICByW20gPSBpLmV2ZW4/ID8gbS1pIDogbStpXSA9IHgKICBlbmQKICByLm1hcCgmOmNocikuam9pbgplbmQKCiMgQnJlYWtpbmcgdGhlIHJ1bGVzIGEgYml0IG1vcmUuCgpkZWYgcGVuZHVsdW1fMShzKQogIG4gPSBzLnNpemUKICBtID0gKG4tMSkgLyAyCiAgciA9IFtdCiAgcy5jaGFycy5zb3J0IS5lYWNoX3dpdGhfaW5kZXggZG8gfHgsIGl8CiAgICByW20gPSBpLmV2ZW4/ID8gbS1pIDogbStpXSA9IHgKICBlbmQKICByLmpvaW4KZW5kCgpkZWYgcGVuZHVsdW1fMihzKQogIHIgPSBbXQogIHMuY2hhcnMuc29ydCEuZWFjaF93aXRoX2luZGV4IGRvIHx4LCBpfAogICAgci5wdWJsaWNfc2VuZChpLmV2ZW4/ID8gOnVuc2hpZnQgOiA6cHVzaCwgeCkKICBlbmQKICByLmpvaW4KZW5kCgpkZWYgcGVuZHVsdW1fMyhzKQogIHQgPSBzLmNoYXJzLnNvcnQhCiAgbCwgciA9IHQuZHJvcCgxKS5wYXJ0aXRpb24uZWFjaF93aXRoX2luZGV4e3xfLCBpfCBpLm9kZD99CiAgKGwucmV2ZXJzZSArIHQudGFrZSgxKSArIHIpLmpvaW4KZW5kCgpkZWYgcGVuZHVsdW1fNChzKQogIGwsIHIgPSAoMS4uLnMuc2l6ZSkucGFydGl0aW9ue3xpfCBpLmV2ZW4/fQogIHMuY2hhcnMuc29ydCEudmFsdWVzX2F0KCpsLnJldmVyc2UsIDAsICpyKS5qb2luCmVuZAoKIyBNYWluLgoKZGVmIHRlc3QoZikKICBzcyA9IFsiIiwgImEiLCAiYmEiLCAiYmNhIiwgImNvbXB1dGVyIiwgInNjaWVuY2UiXQogIHJzID0gWyIiLCAiYSIsICJhYiIsICJjYWIiLCAidHBtY2VvcnUiLCAic2llY2NlbiJdCgogIHNzLnppcChycykgZG8gfHMsIHJ8CiAgICBzID0gZi5jYWxsKHMpCiAgICBpZiBzICE9IHIKICAgICAgcHV0cyAiLkZhaWxlZDogZXhwZWN0ZWQgYCN7cn0nIGdvdCBgI3tzfSciCiAgICAgIHJldHVybgogICAgZW5kCiAgZW5kCiAgcHV0cyAiLlBhc3NlZCIKZW5kCgpkZWYgdGltZShmKQogIGRlZiBjaG9pY2VzKHBvb2wsIG4pCiAgICBuLnRpbWVzLm1hcHtwb29sLnNhbXBsZX0KICBlbmQKCiAgc3ltYm9scyA9ICgnYScuLid6JykudG9fYQogIGVsYXBzZWQgPSAwCgogIDEyLnRpbWVzIGRvIHxpfAogICAgcyA9IGNob2ljZXMoc3ltYm9scywgMioqaSkuam9pbgogICAgdCA9IFRpbWUubm93CiAgICBmLmNhbGwocykKICAgIGVsYXBzZWQgKz0gVGltZS5ub3cgLSB0CiAgZW5kCiAgcHJpbnRmKCIuRWxhcHNlZDogJS42ZnNcbiIsIGVsYXBzZWQpCmVuZAoKZnMgPSBbCiAgOnBlbmR1bHVtXzAsCiAgOnBlbmR1bHVtXzBfMSwKICA6cGVuZHVsdW1fMF8yLAogIDpwZW5kdWx1bV8xLAogIDpwZW5kdWx1bV8yLAogIDpwZW5kdWx1bV8zLAogIDpwZW5kdWx1bV80Cl0KCmZzLm1hcCgmbWV0aG9kKDptZXRob2QpKS5lYWNoIGRvIHxmfAogIHB1dHMgZi5uYW1lCiAgdGVzdChmKQogIHRpbWUoZikKZW5k