Skip to content

Instantly share code, notes, and snippets.

@rpdillon
Created June 18, 2012 15:27
Show Gist options
  • Save rpdillon/2948908 to your computer and use it in GitHub Desktop.
Save rpdillon/2948908 to your computer and use it in GitHub Desktop.
Generate permutations of a string using the rank/unrank method (Skiena)
def rank(s)
if s.length == 1
return 0
else
multiplier = s.split("").sort.index(s[0].chr)
subcombos = (1..(s.length-1)).reduce { |a,b| a * b }
return (multiplier * subcombos) + rank(s.slice(1..-1))
end
end
def unrank(n, s)
sorted = s.split("").sort
if n == 0
return sorted.join("")
end
subcombos = (1..(s.length-1)).reduce { |a,b| a * b }
index = n/subcombos
char = sorted[index]
sorted.delete_at(index)
return char + unrank(n-(index*subcombos), sorted.join(""))
end
# Sort of an ad hoc test framework.
rank_tests = [["abf", 0],
["afb", 1],
["baf", 2],
["bfa", 3],
["fab", 4],
["fba", 5]]
unrank_tests = [[0, "abf"],
[1, "afb"],
[2, "baf"],
[3, "bfa"],
[4, "fab"],
[5, "fba"]]
passed = 0
rank_tests.each do |test, expected|
if rank(test) != expected
puts "Failed on input: #{test}"
else
passed += 1
end
end
unrank_tests.each do |test, expected|
if unrank(test, "abf") != expected
puts "Failed on input: #{test}"
else
passed += 1
end
end
puts "Passed #{passed} tests."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment