June 27, 2008Coding challengeUpdate: I posted a wrap-up here. 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:
Post your solution in the comments or on your blog. All languages and all approaches (brute force or not) are welcome. I'm curious to see if somebody can come up with a clever solution (I don't have one)... Comments
In Ruby, brute-force, probably really slow: (98..103).select { |x| x.to_s.size == x.to_s.split(//).uniq.size } Perl: #!perl -wl my @nums = grep !/(.).*\1/, 1..MAX; Ruby, same approach (dunno if you call it clever or brute): #!ruby -w nums = (1..MAX).reject {|num| num.to_s =~ /(.).*\1/} Python, same approach: #!python MAX = 10000 BTW. Now I see I forgot to use precompilation of regexps in Perl and Ruby versions -- to do this, add o after the regexp, i.e. /(.).*\1/o Posted by: szeryf at June 28, 2008 01:44 AMJavascript, approach based on regexp : <script> </script> Sounds like a Google interview question or something. :) Am far too tired to "work" on that, but its a funny puzzler. Marc Java (I'm sorry for the lack of indentation, I couldn't figure out how the system expects you to post code): import java.io.PrintStream; public class Test { private List numbersWithoutRepeatingDigits; public Test(int start, int end) { numbersWithoutRepeatingDigits = new LinkedList(); public void calculateResults() { for (int number = start; number 0); return false; public void displayResults(PrintStream out) { public static void main(String... parameters) { A Set solution seems to be twice as slow, a regex one about 11 times. Both are still fast enough for finding results between 1 and 10000, though. Posted by: levi_h at June 28, 2008 02:16 AMThe comment system also ate my generics and most of both the calculateResults and hasRepeatingDigit(int) methods... oh well. I published it at docs.google.com/Doc?id=dppnxf9_0gtzdzzfw Posted by: levi_h at June 28, 2008 02:24 AMC#3: //this could also be a regex based func //get all the non-repeating nums int last = 1, gap = 0, count = 0; Console.WriteLine( "count: {0,0}", count ); Still brute forcing to get the gaps, I'm not sure whether there's a Linq expression for Last. Posted by: Keith Henry at June 28, 2008 02:39 AM// Groovy version. The readable version seems fast enough final MAX = 10000 def candidates = (1..MAX).findAll { def jump = 0 for (x in candidates) { println "Number of candidates: $candidates.size - Biggest jump $jump" Here is one from me in Java. public class GenrateNumbers { static int jump = 0; private static boolean hasRepeatingNumber(char[] charArray) { Cedric, Here is my not-clever solution: janaudy.com/weblog/ But, there is an easier solution to the total count of numbers, for 1 to 10,000: How many 4 digits number can be made out of 0, 1, ..., 9 if no digit can repeat: How many 3 digits number can be made out of 0, 1, ..., 9 if no digit can repeat: How many 2 digits number can be made out of 0, 1, ..., 9 if no digit can repeat: How many 1 digits number can be made out of 0, 1, ..., 9 if no digit can repeat: So the total count is 4,536 + 648 + 81 + 9 = 5,274 As for the biggest jump, it can only appear in the 4 digits one, so it is 10,000 - 9,876 = 124 Thierry Posted by: Thierry Janaudy at June 28, 2008 05:57 AMCedric, Here is my not-clever solution: janaudy.com/weblog/ But, there is an easier solution to the total count of numbers, for 1 to 10,000: How many 4 digits number can be made out of 0, 1, ..., 9 if no digit can repeat: How many 3 digits number can be made out of 0, 1, ..., 9 if no digit can repeat: How many 2 digits number can be made out of 0, 1, ..., 9 if no digit can repeat: How many 1 digits number can be made out of 0, 1, ..., 9 if no digit can repeat: So the total count is 4,536 + 648 + 81 + 9 = 5,274 As for the biggest jump, it can only appear in the 4 digits one, so it is 10,000 - 9,876 = 124 Thierry Posted by: Thierry Janaudy at June 28, 2008 05:58 AMThierry, your answer raises an important question. Is the biggest jump 124? Do we include the gap between 9876 and 10000 as a "jump" even though 10000 is not one of the values in the sequence? Posted by: Dan at June 28, 2008 06:30 AMHere is my naive Haskell solution: import List(nub) -- Predicate that returns True if a number contains no duplicate digits. values :: Int -> [Int] Brute force in Erlang without erlang library calls. -module(count). to_digits(Number) -> to_digits(Number, List) when Number div 10 == 0 -> test_to_digits() -> in_list(Element, [Element|_T]) -> test_in_list() -> unique_list([]) -> test_unique_list() -> count(From, Max) -> count(Upto, Upto, _Fun, State) -> test_count() -> test_count4() -> challenge(Max) -> test_challenge() -> I also posted my solution on my blog, because the comments and indentation were stripped here. blog.uncommons.org/2008/06/28/cedrics-coding-challenge/ Posted by: Dan at June 28, 2008 07:32 AMThe following python generator also works: (i for i in xrange(start, end) if len(str(i)) == len(set(str(i)))): -DeWitt C#3 again, down to two Linq loops: //get all the non-repeating nums, conv to array to make ordinal lookups quicker //get all the gaps, using array to loop up previous Another python implementation at tincancamera.com which is somewhat coloured by my normal use of python (prototyping algorithms before porting them to C++ or Java). Both brute-force iterate and filter and a combinatorics approach; the combinatorics one is faster for big N, but slower for N < 2e6. For max = 10000, total 25277895; biggest jump 105, from 1098 to 1203. Why doesn't your url form allow h t t p No, I don't want my email published on your web site. Please remove link. Posted by: Pete Kirkham at June 28, 2008 09:39 AMA Scala version: for (i <- 1 to 100000; s = i.toString; if HashSet[Char](s:_*).size == s.size) println(i) Posted by: Pär at June 28, 2008 10:00 AMJava version (brute-force) without collections and nearly no memory allocation. www.jroller.com/eu/entry/cedric_s_coding_challenge I wonder if it is possible to give an answer to "the biggest jump" question without iterating trough entire sequence. Also, it would be interesting to check possibilities of parallelizing tasks, perhaps using Kilim or Doug Lea's for/join framework. Posted by: Eugene Kuleshov at June 28, 2008 10:36 AMCedric, what is with your comment filter? it doesn't allow to use "http" "colon" "slash" "slash" in the comment text and in the url field... Posted by: Eugene Kuleshov at June 28, 2008 10:39 AMDan, You are right. Cedric needs to clarify this point. It is no a 'jump' as per say, let's call my jump a 'relative jump' and not an 'absolute jump'. Posted by: Thierry Janaudy at June 28, 2008 10:40 AMNon brute force, in python: from collections import deque Also results in 5275 numbers in the sequence, max gap of 105. Posted by: Mathieu Robin at June 28, 2008 11:06 AMFollowing my investigation, a "clever" solution, only valid when max is a multiple of 10: 1000, 10,000, 100,000.... public class CC2 { Small patch to my solution: Waiting for someone to post a solution using Fan ;-) Posted by: Andres Almiray at June 28, 2008 02:28 PMThis problem is so much easier to solve in binary. Posted by: Charles Miller at June 28, 2008 03:49 PMA somewhat non-bruteforce functionally factored Python solution: pastebin.com/f63ce9880 Posted by: Ants Aasma at June 28, 2008 04:08 PMSorry, pasted the wrong URL, the correct one is pastebin.com/f5cec4683 Posted by: Ants Aasma at June 28, 2008 04:09 PMszeryf, in your Ruby solution (which is neat and quick, by the way) wouldn't this jump = 0 be more naturally expressed using each_cons(2) instead of inject with its "arbitrary" initial value and redundant return value? Posted by: Ed Davies at June 28, 2008 05:30 PMI've got a heuristics based solution on my blog. It's mildly slower than a brute-force solution for small n, and I bet it's competitive with a combinatronics based solution for large n. I would post a link, but your comment filter will just eat it. Posted by: Erik Engbrecht at June 28, 2008 06:30 PMEric's heuristic solution is at erikengbrecht.blogspot.com/2008/06/cedrics-code-challenge.html Posted by: Cedric at June 28, 2008 06:49 PMEd Davies: sure, I forgot about each_cons. But the return value in inject is not redundant, it's used as `a' in next pair :) Ruby version with each_cons: #!ruby -w MAX = 10_000 nums = (1..MAX).reject {|num| num.to_s =~ /(.).*\1/o} solution based on searching the string space: docs.google.com/View?docID=dhpjhcjh_14f9msp3c8 Posted by: Logan Johnson at June 29, 2008 12:51 AMHere's a really simple and efficient Java implementation that can find all values up to 10,000,000,000 on my Mac Pro in about 0.7s (not counting println overhead): crazybob.org/BeustSequence.java.html Posted by: Bob Lee at June 29, 2008 01:52 AMMake that 0.6s after a slight refactoring. Posted by: Bob Lee at June 29, 2008 02:17 AMPlease find herein a version that satisfies the challenge as stated, written in ANSI Forth. *WARNING* -- This blog strips whitespace. VERY annoying. If the Forth code is found to be hard to read, this is partly to blame.
: rdrop postpone r> postpone drop ; immediate ( a simple approximation of integer sets using bit-masks ) : mask ( n -- n' ) 1 swap lshift ; ( the challenge solution proper ) variable seen-set : digits ( n -- c-addr u ) 0 <# #s #> ; challenge
Another Scala approach class Counter(lower:Int, upper:Int) { new Counter(1,10000) results in count: 5274, max gap: 105 after about 5 minutes Posted by: david at June 29, 2008 03:20 AMAS3: private const powers : Array = [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 ]; private function doIt(max : Number) : void { outer: for (var i : Number = 1; i 0) { var remainder : uint = tmp % 10; Repost in html :) private const powers : Array = [ 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 ]; private function doIt(max : Number) : void { outer: for (var i : Number = 1; i < max; i++) { var remainder : uint = tmp % 10; Writing of the program was very simple with Java. The answer with 10K as the max limit is , a Jump of 124 : The jump from 9876 to 10K, a jump of 123 nos (All numbers from 9877 to 10000 are excluded hence a jump of 123). It was interesting to look at how the gap progression happened. There is a clear pattern and with this knowledge one can very trivially predict the biggest gap for numbers as big as google :-) Results : Tests run: 2, Failures: 0, Errors: 0, Skipped: 0 ------------------------------------------------------------------------
A fast non-trivial readable Java solution is published on docs.google.com/Doc?id=ddn32vzw_25dqbrq2c4 The trick is to generate only the next good number - starting from the end see which is the first digit that can be incremented, then fill the rest with the smallest allowed number.
Scala code that only visits valid numbers: def numsWithDigits(len: Int, digs: Set[Char], leading:Boolean): Iterator[List[Char]] = { nice idea, however its pretty easy Posted by: raveman at June 29, 2008 08:37 AMI further simplified and sped up my implementation. It's down to 330ms for max=10,000,000,000. It recursively iterates through all possible values for each digit. crazybob.org/BeustSequence.java.html Posted by: Bob Lee at June 29, 2008 11:05 AMOut of curiosity, I ported my solution to C: crazybob.org/beust.c.html Even when compiled using "gcc -O3", the C version takes 532ms while the Java version only takes 475ms (335ms if you subtract Java startup time). Posted by: Bob Lee at June 29, 2008 12:57 PMBrute force, 44ms on my 1.8 lappy: Func include = i => { @chrisb: FWIW, that would take 12 hrs. for max=10,000,000,000. Posted by: Bob Lee at June 29, 2008 02:31 PMI spent some time over the problem, with python. The result is linked below. Bob Lee might find this interesting, as there is a comparison with my implementation of his methods. ciju.wordpress.com/2008/06/29/beust-sequence-aka-sequence-of-numbers-without-repeating-digits/ Posted by: ciju at June 29, 2008 03:56 PMOK, last time. I made mine a little longer, but clearer and faster: crazybob.org/BeustSequence.java.html @ciju: This implementation may help reduce the overhead you're seeing from method calls in Python. Posted by: Bob Lee at June 29, 2008 05:10 PMOK, last last time. I went the other direction and made an alternate, more concise version: crazybob.org/BeustSequence2.java.html Posted by: Bob Lee at June 29, 2008 08:46 PMA not very pretty but quite fast Java version: rifers.org/paste/show/7580 Time of 1 to 10,000,000 ~58ms on a very old Pentium 4. The test method could do to be a bit more comprehensive. Posted by: John Wilson at June 30, 2008 07:04 AMTried my solution in C. It ran through the whole sequence in 180ms. The most important change is the use of integer to store the sequence, rather than string(originally, Bob's idea). @Bob: I tried implementing your method(BeustSequence2), in C. It took about 700ms. Again I am being partial of not trying to improve your code. Let me know if you would like to see the code, and suggest changes, although I assume we have spent too much time on this problem. Posted by: ciju at June 30, 2008 07:41 AMForgot to mention. The performance results are for limit of 10,000,000,000(ex: all possible). Posted by: ciju at June 30, 2008 07:45 AMCreated another (my last ;-)) version based on 'Permutations Listing': oogifu.blogspot.com/2008/06/coding-challenge-ii.html Runs the 10^9 one in .6 second. Posted by: Thierry Janaudy at June 30, 2008 08:15 AMThere was a bug in the code :(. Current version runs in about 230ms($time ./a.out). This is a pretty fast solution using ascii-APL J (jsoftware.com). Experts from likely will write even more terse code f =: [:(#;[:>./2-~/\])(#~([:*/[:~:":)"0) @ciju: BeustSequence2 is the slower but more concise version. I'd try BeustSequence. Then again, the C compiler may not optimize around the recursion very well. Posted by: Bob Lee at June 30, 2008 09:22 AMNot really particularly cute or clever, but a solution in Lua that uses a coroutine that generates numbers as high as your implementation can count: local c = coroutine.create(function () I'm sure it's not especially fast either. Posted by: Taylor Venable at June 30, 2008 09:32 AMpublic static void main(String[] args) { Oops: public static void main(String[] args) { Alright, I've settled on the shorter solution: crazybob.org/BeustSequence.java.html Here's the test harness which prints the count and largest gap: crazybob.org/TestBeustSequence.java.html And here's the shared Listener interface: crazybob.org/Listener.java.html This is exactly the type of problem in which you want to avoid high level structures like Strings. Couldn't post the code so I put it in my google docs: My guess is this is about the fastest implementation you'll come up with unless someone codes it in C with pointers, and even then the JVM is probably close. To do large numbers be sure to comment out the println that prints a number every iteration. The one you requested: A smallish one: The largest power of 10 that executes instantly: Big one still takes less than a minute: The pattern on "Biggest Jump" seems strange. I suppose it's a power of 10 type thing. I could probably go up another power of 10 or two, but that would start to take minutes/hours and any higher than that and I'll have to change a few ints to longs. Never mind--I hadn't seen Eugene's solution--keeping it all within ints improves the hell out of it as long as you aren't printing anything each iteration. Posted by: Bill Kress at June 30, 2008 12:17 PMI think the sum of the values for n digits is (9!/(9-(n-1))!) * ( 45 * pow(10, n-1) + 40 * floor(pow(10, n-1) / 9) ) . Or the progression of the pattern in my blog. Empirically, the maximum jump for n digits is floor( ( 1203456789-1098765432 ) / pow(10, 10-n) ), since they all have much the same format. For the maximum below an arbitrary value, you'd test the 987... 1023... jump as well. Probably could think of an expression for a non-noughty number, but it's bed time. tincancamera.com/blog Posted by: Pete Kirkham at June 30, 2008 05:07 PM@Bill Kress: Mine handles 10^10 in less than half a second. Posted by: Bob Lee at June 30, 2008 05:40 PMfactor-language.blogspot.com/2008/06/cedrics-code-challenge.html Posted by: at July 1, 2008 05:03 AMYeah, sorry. I started coding before reading the bottom 1/2 of the responses (the power solutions). I mostly feel strange about all the earlier solutions using higher language constructs to make a short (nloc) solution when that really doesn't help anyone. Even java String should be out of the consideration--let alone anything that actually manipulated their strings by splitting them apart just to compare them--holy cow that's inefficient. Also, all the solutions are brute force. The pattern of count of numbers found for each power of 10 leads me to believe there actually is a much faster mathematical solution than comparing digits. Probably some factorial-looking thing. Posted by: Bill Kress at July 1, 2008 11:13 AMAnother version of recursive approach - the similar with Crazy Bob's. I did a quick benchmark and it is faster. I'm not sure it is because I calculate bits and reuse them... public class Test { private static class ResultListener static int BITS[]; static for( int i = 0 ; i < 10; i++ ) My bad. The above does not return in 1 to MAX in sequence. It is basically combinatorial approach so it will be ( 1 , 10 , 102, 1023 , 1203 ) Posted by: stinkyminky at July 1, 2008 11:47 AMAs requested, I posted my solution on my blog. It's in OCaml, and finds all the values from 1 to max_int in 27 seconds on my 2.16 GHz MacBook Pro. enfranchisedmind.com/blog/2008/07/01/cedrics-problem-in-ocaml/ Posted by: Robert Fischer at July 1, 2008 01:03 PMBTW, your blog software balks at if you prefix the URL with the HyperText Transfer Protocol prefix. Posted by: Robert Fischer at July 1, 2008 01:03 PM@Bill Kress If you are talking about the count of such numbers, then thats altogether a different issue. Its simple permutation. Here's google helping us out with the answer for maximum possible such numbers. I'm fascinated by the number of authors that claim their solution isn't brute force, when in fact the solution is clearly brute force (up to and including regex! A recompiled regex on every loop iteration! That's brute with a big, wooden club!) We may be watching the end of the era when programmers even cared about the performance of an algorithm and nowadays simply assume that the implementation that takes the fewest characters to write is the fastest one. We need a symposium on the definition of brute force. Posted by: sidereal at July 1, 2008 05:16 PMBrute-force or not! Regarding the confusion about whats brute-force and whats not, let me explain a little. If you are asked to generate numbers form 1 to 10, generating those numbers is not brute-force. You have to go though them to print them out, at the least. Now, if you are asked to print numbers in range [1, 10] which are divisible by 5. Then checking each number and printing only the once divisible by 5 (ex: 5 and 10), does make it brute-force. Because the output length is 2, and you are going through whole of the search space to generate those 2 numbers. The one which only generates 5 and 10 is the _not_ brute-force method. And I can conform that at least Bob's and my method are not brute-force. They only generate the numbers which don't have repeated digits. They don't generate the whole sequence and check whether digits are repeated in a number. And thats why, for example, my solution completes in about 0.2s (I am talking about generating all the possibilities and only the possibilities, 8877690(see my comment above), in sequential order). Posted by: ciju at July 1, 2008 06:51 PM@Bill Kress: Something wrong with your algorithm: I could verify that your "Biggest Jump" is wrong for the 10,000 case. Here are my results: The one you requested:
414 ms Huge Crazy Bob's one...:
I just jump number ranges when most significant numbers have repetitions. The essentials (copy+paste on your IDE and format if you will):
private long m_maxContinuousSkippingCount; private long m_continuousSkippingCount; public BeustLongSequenceFinder(final long maxValue) { if (maxValue 0"); //... getters ... public void findNumbers() { // Calc. state fields final long xNextVal = loopNext(0, m_maxValue, digitCount(m_maxValue) - 1, 0); if (0 != m_continuousSkippingCount) private final void storeJump(final long xNextVal) { if (m_continuousSkippingCount > m_maxContinuousSkippingCount) {
if (0 == digitIndex) { return nextValue;
Sorry! 2nd attempt giving HTML escaping to less-than and greater-than operators: public class BeustLongSequenceFinder { private long m_maxContinuousSkippingCount; private long m_continuousSkippingCount; public BeustLongSequenceFinder(final long maxValue) { if (maxValue <= 0) //... getters ... public void findNumbers() { // Calc. state fields final long xNextVal = loopNext(0, m_maxValue, digitCount(m_maxValue) - 1, 0); if (0 != m_continuousSkippingCount) private final void storeJump(final long xNextVal) { if (m_continuousSkippingCount > m_maxContinuousSkippingCount) {
if (0 == digitIndex) { return nextValue; for (int i = 0; (i < 10) && (nextValue <= maxValue); i++) { final long xNextNextValue = nextValue + xSkipped; if (xNextNextValue > maxValue) return nextValue;
@sidereal: For max=10^10, 8,877,691 values match. My algorithm only performs 8,877,690 operations while the brute force approach requires 10^10 ops (or 1,125X more than mine). @sidereal: To illustrate, here's a log2-scale graph of: 1) the # of ops performed by my algorithm for maximum values up to 10^10: crazybob.org/beust.png As you can see, a brute force algorithm scales at about O(max) while my algorithm scales at O(matches) in the worst case (and much better in common cases). Posted by: Bob Lee at July 1, 2008 10:58 PMsome ugly java code usage @Override using System; namespace ConsoleApplication1 System.Console.WriteLine(); Slight improvement after a couple of optimizations, including seeding (when max big enough) the biggest jump with a very conservative (max/100)-1. Code is still ugly and I will just post the timings: The one you requested: Huge Crazy Bob's one...: Have Fun,
Simple Haskell version: import Data.List(nub) main = print $ counter 10000 counter n = (length ns, maximum $ zipWith (-) (tail ns) ns) where ns = filter (not . anySame . show) [1..n] anySame xs = xs /= nub xs @Paulo: Both 9,876,543,211 and 10,000,000,000 contain dups. Posted by: Bob Lee at July 2, 2008 07:52 AM@Bob Lee Of course they are! They are the first and last element of the range, since I am presenting the jump as a closed boundary interval. Now, if I can get my implementation as clean as yours... Have fun, Posted by: Paulo Gaspar at July 2, 2008 08:02 AMAnother Scala version (completely untested): def printNonRep(min: Int)(max: Int) = { No-where near as elegant as the first version given, but I think it works and is reasonably efficient. Of course, it's functional soup... There's probably an issue with type inference in the foldRight tuple, but I haven't tried it to be sure. Posted by: Daniel Spiewak at July 2, 2008 10:01 AMBob Lee's version in Java is by far the best one I've seen. Posted by: Sam Pullara at July 2, 2008 12:41 PM@Sam Yes, it is cleeeaaan! I wonder if I am getting any meaningful performance gain over Bob's version and still can't get clean code with my strategy. Posted by: Paulo Gaspar at July 2, 2008 01:14 PMwww.lolcode.com/home I will followup soon with a kickass LOLCODE implementation soon ;-) I have written a slightly more general solution in OCaml (it can count efficiently in any arbitrary base, not only in base 10, so e.g. base 1000 is no problem for it, unlike most solutions above). It is a bit faster than Bob Lee's Java version on my box (AMD Athlon 64 X2 6000+). My program runs in 640ms, the Java implementation counts to 10^10 in ~680ms (total exec time ~750ms including JVM startup time, etc.).
eigenclass.org/hiki/ordered_permutations Posted by: Mauricio Fernandez at July 2, 2008 05:08 PMWhat, no Lisp submissions?! Posted by: Jim at July 2, 2008 09:19 PMWell, here is one. (defun collect-numbers-without-repetition (min max) Since Mauricio upped the ante, here's a slightly longer version which runs in 210ms for max=10^10 on my machine: crazybob.org/FastBeustSequence.java.html Like Mauricio's OCaml solution, iteration of the digit set is now O(size) as opposed to O(capacity), but unlike the OCaml solution, set ops are O(1) instead of O(log(n)). Posted by: Bob Lee at July 3, 2008 01:38 AMI have a different approach which works quite quickly but is highly customized to fit max=10,000. It would in its current state involve code changes if max changed. Anyway, for what its worth, the code can be found here: ragstorooks.wordpress.com/2008/07/03/cedrics-coding-challenge/ Posted by: ragstorooks at July 3, 2008 02:25 AM@Bob Interesting code! You have to tell us what Java version + hardware you are using. My 10,000,000,000 done in 383 ms was ran in Java 6 on under OS X on a MacPro 2008 2.8GHz. (8 cores but that is not important.) Java 5 runs it twice as slow! Tkx, Posted by: Paulo Gaspar at July 3, 2008 04:00 AMHere is a brute force implementation in Fan. class Nonrepeat I still have to run it on my usual hardware to see how much faster it is, but this is for sure faster and leaner than my previous solution:
static { private final long m_maxValue; private long m_maxJumpDelta; private long m_printCount; public BeustFastSequenceFinder(final long maxValue) { public long getMaxJumpBegin() { public long getMaxJumpSize() { public long getMaxValue() { public long getPrintCount() { public void findNumbers() { loopNext(0, (m_maxValue > LAST_NOREPS) ? LAST_NOREPS : m_maxValue, 10, 0); final long xDelta = (m_maxValue+1) - m_lastPrintedValue; public long getMaxJumpEnd() { protected void print(final long value) { private long loopNext(long nextValue, final long maxValue, final int digitIndex, final int leftmostMask) { if (0 == digitIndex) { return nextValue; return nextValue;
import itertools MAX=10000 # Using lists nums = filter(lambda x: len(str(x)) == len(set(d for d in str(x))), range(1, MAX+1)) # With iterators and functional programming def mkseq(max): def mkdiff(max): def max_count_step(x,y): print "MAX, COUNT=", reduce(max_count_step, mkdiff(MAX), ((0, 0, 0), 1)) # Results: Python: [x for x in xrange(10000) if len(str(x))==len(set(str(x)))] @Paulo: Same as above, 3ghz Mac Pro, Java 6 w/ -server. Posted by: Bob Lee at July 3, 2008 09:47 AM@Bob I tested your (very interesting) algorithm at my laptop. Yours is faster. Takes roughly 60% of mine's time for the 10 Giga test. However, it is missing the last Gap/Jump, because the last gap does not end at the max value boundary and you only collect the gap/jump data when you "print". Therefore I got results like this (both printed my way): *** Bob Lee's: *** The largest power of 10...: *** Paulo's: *** So, you are just missing a final gap check to get the last and bigger one.
@PJG That last jump isn't really. There are no more jumps because after that last begin it always has duplicate digits. Posted by: Sam Pullara at July 3, 2008 11:06 AMI interpreted the biggest jump as being between two valid values (which 10^6 is not), but I suppose you could interpret it either way. Posted by: Bob Lee at July 3, 2008 11:08 AMRuby one-liner (not counting the import): require 'enumerator' puts (a=(1..10000).to_a.reject{|x| x.to_s.split(//).uniq!}), a.enum_cons(2).to_a.sort_by{|(b,c)|c-b}.last.inspect, a.inject(0){|s,n|s+n} Posted by: Darmani at July 3, 2008 12:28 PMIn Python u = [x for x in range(1,10000) if len(str(x))==len(set(str(x)))] # solution in Ursala #import nat func = ^(nleq$^+ difference*typ,length)+ ~&triK2tkZ2FlS+ iota+successor; * ^lrhPX/~& %nP answer = func 10000 Yes, reading the original post it really looks open to both interpretations. Anyway, changing Bob's code to my interpretation is trivial and, obviously, has no impact on its to performance. I can't imagine a more efficient solution (even if a couple of details could be added(*)). (*) - Like always limiting the search to max <= 9876543210, since afterwards all numbers are repeated for base 10. But its number of digits limit does something like that too. Have Fun, Posted by: Paulo Gaspar at July 3, 2008 03:11 PMlisp
//a recursion one , use C //set your max value here; int recu(int depth) //update max //increase the counter by 1 int main() //start search for the number, maxdepth is actually the width of the number, i.e 45321, maxdepth = 5+1, or 564321, maxdepth=6+1 //sorry for last post, the html tag covered some of the code, and that code is not complete //set your max value here; int recu(int depth) //if larger than max, just abort //update max //increase the counter by 1 int main() //start search for the number, maxdepth is actually the width of the number, i.e 45321, maxdepth = 5+1, or 564321, maxdepth=6+1 @Bob: interesting representation of the set of remaining digits. I have nothing against imperative code in general (I use it often in OCaml), $ time ./beust real 0m0.273s $ time java -server TestBeustSequence 10000000000 real 0m0.350s The difference is within the experimental error; I guess it's a draw :) You can find the code at eigenclass.org/misc/beust.ml The set of digits is represented with two lists (in a way reminiscent of a simpler ruby to to the basic stuff (10..12).to_a.reject { |x| x.to_s.split(//).uniq! } Posted by: joel at July 4, 2008 06:31 AMI found that challenge very interesting. I have an idea about finding the largest gap between two unvalid numbers. I tried that way: Mathieu BORDAS, France Posted by: Mathieu BORDAS at July 4, 2008 08:11 AMProlog Version(Well, GNU Prolog) checkit([]):-!. dif([_|[]],[]).
printResults:- main:- beust(98,120),printResults. Posted by: Frank Bolander at July 4, 2008 09:43 AMHere's one in awk. function scan(num) function iter(max) BEGIN { iter(5440) } Posted by: Elias Pipping at July 4, 2008 12:49 PM@Mauricio: When I try to run your program, I get: File "beust.ml", line 19, characters 12-26: I modified my test program to not allocate objects. Now it runs in 150ms for 10^10: crazybob.org/FastBeustSequence.java.html Bob: you need a 64-bit ocamlopt. I pushed the functional set some more. eigenclass.org/misc/beust2.ml Best of 5 runs: $ time ./beust2 real 0m0.217s $ time java -server TestFastBeustSequence 10000000000 real 0m0.309s The standard deviation is quite large, around 15ms (real time for OCaml, I guess an imperative structure is required for further improvements, but it's Best of 5 runs on my computer: eigenclass.org/misc/beust2.ml: $ time ./beust2 real 0m0.237s crazybob.org/FastBeustSequence.java.html: $ time java TestFastBeustSequence 10000000000 real 0m0.272s So, not counting Java startup overhead, we're looking at 237ms (OCaml) vs 150ms (Java). Posted by: Bob Lee at July 5, 2008 12:43 PMInteresting to see the effects of -client and -server on the Java versions. With -client (and Soylatte 1.0.2 on a MacBook Pro 2.16Ghz Core Duo) this one is faster than FastBeustSequence (though not as elegant): slm888.com/snippets/Beust.java $ java -client BeustTest 10 $ java -client TestFastBeustSequence 10000000000 With -server they both have best run times of around 400ms. Posted by: Mark Mahieu at July 5, 2008 01:10 PMThe best times I can get after N (= a few dozen) runs are 205ms for Java While my box runs the OCaml code a bit faster, yours is much better at Java. I'm using this JVM: java version "1.6.0_04" I've compiled the OCaml program in a 32-bit jail with no substantial I have ported that fast Java code to C, it's about twice faster on my PC: A nicer Perl version: #!/usr/bin/perl my @num = grep { !/(.).*\1/ } 1 .. 10_000; my $max_diff = max pairwise { $b - $a } ( print @num . "numbers, max diff $maxdiff\n"; Hi, my code is very simple but are not getting through properly via this comment, Contact me via email if you are interested. Hi, My codes are not getting through this comment, if you are interest contact me via email Final couple of tweaks to mine: slm888.com/snippets/Beust.java It now accepts a radix so you can try a larger range of values, eg base 11: $ java BeustTest 10000000000 11
@Bob The new method names for the Digit class are a readability improvement too - especially since your implementation is quite original / unusual. @Mark The radix thing is not so usefull since the maximum value without repeated digits is: 9876543210. Above this value ALL integer numbers have repeated digits.
@Paolo That's correct for base 10 numbers, but I'm applying the radix to the calculation as well, so in base 11, a9876543210 is the maximum value without repeating digits. There are limits though. Eg. in hex, fedcba987654321 is the maximum non-repeating value it's capable of finding since the data types I'm using limit it to values less than 2^63. @Paulo Oops, sorry I mis-typed your name on that last comment. Posted by: Mark Mahieu at July 7, 2008 02:16 PM@Mark Mahieu Sorry, I had missed the multi-base "detail". And don't hurry: that mistyping is quite common. var nums = (from n in Enumerable.Range(1, 10000) var gap = -1; for (int n = 1; n < nums.Length; n++) gap = Math.Max(gap, nums[n] - nums[n - 1]); Response.Write(String.Format("count: {0}, max gap: {1}", nums.Length, gap)); Takes about 0.01sec on my old 3.2GHz Athlon. And since it is written in performant C# I don't have to jump through hoops to optimize it. @Wheelwright "Takes about 0.01sec on my old 3.2GHz Athlon. And since it is written in performant C# I don't have to jump through hoops to optimize it." haha that's not very impressive really, it's barely faster than the Ruby one-liner... public class Puzzle String digitString=null; //holds string representation of numbers. } } Posted by: Ananyo Banerjee at July 8, 2008 05:12 AMSorry Cedric...The code in my previous comment is wrong and incomplete.I had posted the modifed code in my blog (ananyobanerjee.blogspot.com).Please have a look. Posted by: Ananyo Banerjee at July 11, 2008 02:02 AMI put a Common Lisp version here: paste.lisp.org/display/63602 It does the 10,000 solution in 0.005 seconds. No solution using A 'lispier' lisp solution (no iteration, just tail recursion) which also runs faster than any of my iterative solutions interestingly paste.lisp.org/display/64850 Posted by: Toby at August 5, 2008 08:24 PMclass Beust ++total; int gap = i - last; Console.WriteLine("\nTotal: {0}", total); private static bool DoDigitsRepeat(int num) int index = 1 << digit; return false; //javascript version (apply in c/c++,java,c#) function check(x)
Posted by: John Smith at August 30, 2008 08:46 PM
#!PYTHON max = 10000 nums = [x for x in range(1,max+1) if len(list(str(x))) == len(set(str(x)))]
count = last = 0 print nums So I'll ask the obvious question: do leading zeroes count as repeated digits? (Is that an African or a European swallow?) Posted by: dr-steve at August 30, 2008 09:39 PMThis is by no means the fastest way, but is done using list generators only #!/usr/bin/env python maximum = 10000
biggest_jump = max([b-a for a,b in zip(numbers, numbers[1:])]) Posted by: Keegan Carruthers-Smith at August 31, 2008 01:14 AMghci> let xs = filter (\x -> let st = show x in st == nub st) [1..10000] I don't understand exactly the definition of the problem. What does brute-force mean? Linear respect to max? I am pretty lazy to write the code. My high level solution is the following, which is NlogN complexity, where N = number of digits of _max_, power 10. tot_digits = number of digits of _max_ total_permutations = size of the tree Posted by: Saverio at August 31, 2008 04:10 AM# a single line lambda, returns numbers in which no digit repeats itself Here's a simple, permutation-based Haskell solution: Prelude> let perms 0 _ = [[]]; perms n xs = concat [ map (y:) (perms (n-1) (filter (/=y) xs)) | y <- xs] (Sorry if somebody posted something like this already, and I missed it). Posted by: Ketil at September 4, 2008 08:37 AMHere's my dumb haskell solution: import Data.List (nub) nodup n = (sn == nub sn) beust = filter nodup [1..10000] main = do Bob's solution in C# - 459 ms. Posted by: B P at September 14, 2008 09:53 AMk4:{(|/-':;#:)@\:&(=').#:''(::;=:')@\:$1+!x} 10.1 ms for 10,000, 141 ms for 100,000, 160 ms for 1,000,000 Posted by: Aaron Davies at September 22, 2008 06:55 PMOops, that should have been 1560 ms for 1,000,000 Posted by: Aaron Davies at September 22, 2008 06:57 PMhmmmmmmmmmmmmmmmmm, It seems that SQL is not cool because no one has tried to solve this problem with SQL. Here Oracle SQL: select num, count_tot, (max(diff) over ()) max_diff NUM COUNT_TOT MAX_DIFF I used the Mikito way the generate the numbers. If anyone knows how to use a regular expression as a filter to check for duplicate digits I could use this regular expressions instead of all the translate functions? Posted by: RC at October 5, 2008 06:47 AMMy sql statement becomes maimed, I can't post it properly. Beneath the connect by level.... one should insert: ) Post a comment
|