From Otaku, Cedric’s weblog:
Here is an interesting coding challenge: write a counter function that counts from 1 to max but only returns numbers whose digits don’t repeat.
For example, part of the output would be:
* 8, 9, 10, 12 (11 is not valid)
* 98, 102, 103 (99, 100 and 101 are not valid)
* 5432, 5436, 5437 (5433, 5434 and 5435 are not valid)
Here’s an OCaml solution. Not terribly optimized, but good enough for free work. The solution is trivially changed into any base you’d like (even into calculating words with unique characters or whatever), and it calculates all the values from 1 to max_int in 27 seconds on my 2.16 GHz MacBook Pro.
(* Instead of thinking of these things in terms of number, I'm thinking in terms of strings. Really, the question is: "how many unique strings of any length can you come up with using the characters '0', '1', '2', '3', '4', '5', '6', '7', '8', and '9'", then capped at a certain point. *) let cap = max_int (* Set this to the cap you want *) let cap_s = string_of_int cap let cap_s_len = String.length cap_s let handle_match str check = if check && String.length str >= cap_s_len && String.compare str cap_s > 1 then exit 0 else () (* print_endline str *) let filter_out lst x = List.filter (fun y -> String.compare x y != 0) lst let symbols = List.map string_of_int [0;1;2;3;4;5;6;7;8;9] let starting_symbols = filter_out symbols "0" let rec build_of_length out len i syms = if i = len then handle_match out (len >= cap_s_len) else List.iter ( fun str -> out.[i] <- str.[0]; build_of_length out len (i+1) (filter_out syms str) ) syms let build_all_of_length len = List.iter (fun str -> let other_syms = filter_out symbols str in build_of_length (String.make len str.[0]) len 1 other_syms ) starting_symbols let () = for i = 1 to cap_s_len+1 do build_all_of_length i done; ()
Related posts:
Pingback: Cedric’s Coding challenge