横浜へなちょこプログラミング勉強会にて過去に出題された多段階選抜を解いてみた。
回答にかかった時間は30分程度。
本当は@list
は長さ決め打ちではなく1..Float::INFINITY
にしたかったのだが、Enumerator::Lazy
では解けそうになかったので1..2000
という範囲でやりくりすることにした。
今回のテストケースを満たせばよいという考え方はやはり性に合わないのだが、これ以外回答が思いつかなかったのが悔やまれる。
class Selection
def seq input
@list = (1..2000).to_a
input.chars.each{|c|
case c
when "2".."9"
delete_multiple c.to_i
when "S"
delete_indexes square_next
when "s"
delete_indexes square_prev
when "C"
delete_indexes cubic_next
when "c"
delete_indexes cubic_prev
when "h"
@list = @list.drop(100)
end
}
@list[0..9]
end
private
def delete_multiple n
@list = @list.reject.with_index(1){|_, i|
(i % n) === 0
}
end
def delete_indexes indexes
indexes.reverse.map{|i|
@list.delete_at i
}
end
def square_next
next_indexes square.map{|n| @list.index(n)}
end
def square_prev
prev_indexes square.map{|n| @list.index(n)}
end
def cubic_next
next_indexes cubic.map{|n| @list.index(n)}
end
def cubic_prev
prev_indexes cubic.map{|n| @list.index(n)}
end
def next_indexes indexes
indexes.map{|i| i + 1}.reject{|i| i < 0 || @list.size <= i}
end
def prev_indexes indexes
indexes.map{|i| i - 1}.reject{|i| i < 0 || @list.size <= i}
end
def square
@list.select{|n|
sq = Math.sqrt n
sq.to_i === sq
}
end
def cubic
@list.select{|n|
cu = Math.cbrt n
cu.to_i === cu
}
end
end
test = <<_TEST
/*0*/ test( "ss6cc24S", "1,9,21,30,33,37,42,44,49,56" );
/*1*/ test( "h", "101,102,103,104,105,106,107,108,109,110" );
/*2*/ test( "hh", "201,202,203,204,205,206,207,208,209,210" );
/*3*/ test( "hhh", "301,302,303,304,305,306,307,308,309,310" );
/*4*/ test( "2", "1,3,5,7,9,11,13,15,17,19" );
/*5*/ test( "22", "1,5,9,13,17,21,25,29,33,37" );
/*6*/ test( "222", "1,9,17,25,33,41,49,57,65,73" );
/*7*/ test( "3", "1,2,4,5,7,8,10,11,13,14" );
/*8*/ test( "33", "1,2,5,7,10,11,14,16,19,20" );
/*9*/ test( "333", "1,2,7,10,14,16,20,23,28,29" );
/*10*/ test( "s", "1,2,4,5,6,7,9,10,11,12" );
/*11*/ test( "ss", "1,4,5,6,9,10,11,12,13,16" );
/*12*/ test( "sss", "4,5,9,10,11,12,16,17,18,19" );
/*13*/ test( "S", "1,3,4,6,7,8,9,11,12,13" );
/*14*/ test( "SS", "1,4,7,8,9,12,13,14,15,16" );
/*15*/ test( "SSS", "1,8,9,13,14,15,16,20,21,22" );
/*16*/ test( "c", "1,2,3,4,5,6,8,9,10,11" );
/*17*/ test( "cc", "1,2,3,4,5,8,9,10,11,12" );
/*18*/ test( "ccc", "1,2,3,4,8,9,10,11,12,13" );
/*19*/ test( "C", "1,3,4,5,6,7,8,10,11,12" );
/*20*/ test( "CC", "1,4,5,6,7,8,11,12,13,14" );
/*21*/ test( "CCC", "1,5,6,7,8,12,13,14,15,16" );
/*22*/ test( "23", "1,3,7,9,13,15,19,21,25,27" );
/*23*/ test( "32", "1,4,7,10,13,16,19,22,25,28" );
/*24*/ test( "2h", "201,203,205,207,209,211,213,215,217,219" );
/*25*/ test( "h2", "101,103,105,107,109,111,113,115,117,119" );
/*26*/ test( "sC", "1,4,5,6,7,9,10,11,12,13" );
/*27*/ test( "Cs", "1,4,5,6,7,8,10,11,12,13" );
/*28*/ test( "s468", "1,2,4,6,7,11,12,16,17,20" );
/*29*/ test( "S468", "1,3,4,7,8,12,13,16,18,21" );
/*30*/ test( "cc579", "1,2,3,4,8,9,11,13,15,16" );
/*31*/ test( "CC579", "1,4,5,6,8,11,13,15,17,18" );
/*32*/ test( "85", "1,2,3,4,6,7,9,10,12,13" );
/*33*/ test( "sh", "110,111,112,113,114,115,116,117,118,119" );
/*34*/ test( "94h", "150,151,154,155,156,158,159,160,163,164" );
/*35*/ test( "h9c8", "101,102,103,104,105,106,107,110,111,112" );
/*36*/ test( "Cc3s", "1,3,5,6,10,11,13,16,17,19" );
/*37*/ test( "cs4h6", "149,150,152,153,154,157,158,160,161,162" );
/*38*/ test( "84523c", "1,3,11,15,23,26,34,38,46,49" );
/*39*/ test( "54C78hS", "228,231,232,233,236,241,242,243,246,247" );
/*40*/ test( "65h7ccs", "151,152,153,154,157,158,160,163,164,165" );
/*41*/ test( "c95hSc2C", "145,147,151,153,156,159,162,164,168,171" );
/*42*/ test( "c5h3Ss794", "130,131,133,137,138,142,148,150,152,157" );
/*43*/ test( "7ShscC846", "129,130,131,134,135,139,141,142,146,148" );
/*44*/ test( "cshSCCS7ch", "253,254,256,259,260,261,263,264,265,266" );
/*45*/ test( "hhC7849Ss6C", "201,202,203,205,206,211,212,216,220,225" );
/*46*/ test( "hhsc3C987Ccs", "201,202,204,205,207,208,214,217,218,220" );
/*47*/ test( "SC7S8hc59ss2", "162,169,174,178,182,185,188,194,199,203" );
/*48*/ test( "s7S6c35C9CShc", "367,371,377,379,380,385,387,388,392,395" );
/*49*/ test( "4scC3hh982Cc5s", "422,426,430,434,447,451,459,463,471,479" );
/*50*/ test( "23h465Ssc9CchC", "1027,1033,1045,1047,1057,1069,1071,1075,1081,1093" );
_TEST
require 'minitest/autorun'
describe 'Selection' do
selection = Selection.new
test.split("\n").each do |line|
t, n, input, expect = line.match(/^\/\*(\d+)\*\/\s*test\(\s*"([^"]+)",\s*"([^"]+)"\s*\);*\s*$/).to_a
it input do
assert_equal expect, selection.seq(input).join(",")
end
end
end