View Full Version : The best challenge (please read!)
bernie1227
06-24-2012, 09:24 PM
Hiya guys,
I came across this pretty little problem a while ago, and I was wondering if anyone here wanted to give it a crack.
It was invented by a guy called Cedric beust, so here it is:
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)
Also:
Display the biggest jump (in the sequences above, it’s 4: 98 -> 102)
Display the total count of numbers
Give these two values for max=10000
Anyone want a shot?
Bernie
jscheuer1
06-24-2012, 10:33 PM
Even going to just 1000, the biggest jump is 13, from 987 to 1000, not "4: 98 -> 102" as stated. If you're going higher, 1001 would be disqualified as well, etc.
I've just about got this, but since part of the problem as stated appears wrong, I'm going to wait for clarification. Output to 1000 shows these numbers (among others) disqualified (the number after the colon is the length of the gap at that point for the current gap that each number to the left is a part of):
988: 1
989: 2
990: 3
991: 4
992: 5
993: 6
994: 7
995: 8
996: 9
997: 10
998: 11
999: 12
1000: 13
And, there's an awful lot of numbers that qualify, to output them all seems almost pointless. Giving the total number that qualify, and the total that don't and of course giving the largest gap seems more sensible. Going to 10000 would yield an awful lot of rejects too, why list them all?
bernie1227
06-25-2012, 03:16 AM
:mad:
Even going to just 1000, the biggest jump is 13, from 987 to 1000, not "4: 98 -> 102" as stated. If you're going higher, 1001 would be disqualified as well, etc.
I've just about got this, but since part of the problem as stated appears wrong, I'm going to wait for clarification. Output to 1000 shows these numbers (among others) disqualified (the number after the colon is the length of the gap at that point for the current gap that each number to the left is a part of):
And, there's an awful lot of numbers that qualify, to output them all seems almost pointless. Giving the total number that qualify, and the total that don't and of course giving the largest gap seems more sensible. Going to 10000 would yield an awful lot of rejects too, why list them all?
Because beust said so :p
jscheuer1
06-25-2012, 04:30 AM
Because he said the biggest gap is one of the smaller ones?
bernie1227
06-25-2012, 04:34 AM
Because he said the biggest gap is one of the smaller ones?
Interestingly enough, when he set the challenge, he had no idea how to do it himself.
And yes
Bernie
jscheuer1
06-25-2012, 05:50 AM
Well, unless I missed something, this is nothing all that challenging, really:
<!DOCTYPE html>
<html>
<head>
<title>Beustiality</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
table {
border: 2px solid #ccc;
}
td {
border: 1px solid #555;
}
#good, #bad {
vertical-align: top;
}
</style>
<script type="text/javascript">
// Cedric Beust's Challenge Script (c)2012 John Davenport Scheuer
// as first seen in http://www.dynamicdrive.com/forums/
// username: jscheuer1 - This Notice Must Remain for Legal Use
function beust(){
var count = 0, max = 10000, good = [], r = [], bad = {}, str, t, ok, gap = [0, 0];;
while(count < max){
ok = true;
str = (++count).toString(10);
t = str.split('');
for(var i = 0; i < t.length; ++i){
for (var j = t.length - 1; j > -1; --j){
if(j !== i && t[j] === t[i]){
bad[str] = count - good[good.length -1];
ok = false;
break;
}
if(!ok){break;}
}
}
if(ok){good.push(str);}
}
for(var p in bad){
if(gap[1] < bad[p]){
gap = [p, bad[p]];
}
r.push(p);
}
return {max: max, gnum: good.length, good: good.join(', '), bnum: r.length, bad: r.join(', '), biggest: gap[1] + ', from: ' + (gap[0] - gap[1] + 1) + ' to: ' + gap[0]};
}
</script>
</head>
<body>
<table>
<tr>
<th colspan=2 id="title"></th>
</tr>
<tr>
<th>Good</th><th>Bad</th>
</tr>
<tr>
<td id="totg"></td><td id="totb"></td>
</tr>
<tr>
<td id="good"></td><td id="bad"></td>
</tr>
</table>
<script type="text/javascript">
(function(){
var data = beust();
document.getElementById('title').innerHTML = 'Cedric\'s Challenge to: ' + data.max;
document.getElementById('totg').innerHTML = 'Total Good: ' + data.gnum;
document.getElementById('totb').innerHTML = 'Total Bad: ' + data.bnum + '<br>Largest gap was: ' + data.biggest + ', inclusive';
document.getElementById('good').innerHTML = data.good;
document.getElementById('bad').innerHTML = data.bad;
})();
</script>
</body>
</html>
Demo:
http://home.comcast.net/~jscheuer1/side/beust.htm
But other languages are apparently much more efficient at math, see:
http://beust.com/weblog/2008/08/28/coding-challenge-wrap-up/
bernie1227
06-25-2012, 06:43 AM
Pretty nice,
Good work John
Bernie
jscheuer1
06-25-2012, 07:15 AM
Actually there's an error in math for the starting number of the largest gap. Correcting that led to the elimination of 1 var and the simplification of another. And some time can be saved by breaking out of the loops as soon as ok becomes false. I'm going to edit my previous post for the changes.
djr33
06-25-2012, 09:57 AM
That's not too bad doing a loop where you generate each number then throw out the ones that are bad. It would be much harder (and probably mathematically interesting) doing this by looping through only the good numbers.
I did something else recently that was similar. I don't remember exactly what the task was, but it was so much easier looping through all numbers then throwing them out when they failed a test rather than generating them 'correctly' the first time around.
Then the trick can be making this recursive. That's where a second loop to throw out the bad ones becomes the real time saver for the programmer, although perhaps not the 'best' way to do it.
I would've tried this today, but I was busy on another project. And now John has done it so that should be enough.
bernie1227
06-25-2012, 10:38 AM
Sure thing dj, it'll be interesting to see if anyone other than mods actually post an answer
keyboard
06-25-2012, 11:29 AM
<?php
$total = 0;
for ($i = 0; $i < 1000; $i++) {
$total += $i;
$array = str_split($i);
for($v = 0; $v < count($array); $v++) {
if(substr_count($i,$array[$v]) == 1) {
echo $i . '<br />';
break;
}
}
}
echo 'Total: ' . $total;
?>
Strips out numbers like 11, 22, 33 but not 101, 122, 262... Can anyone work out why???
jscheuer1
06-25-2012, 03:19 PM
That's not too bad doing a loop where you generate each number then throw out the ones that are bad. It would be much harder (and probably mathematically interesting) doing this by looping through only the good numbers.
I did something else recently that was similar. I don't remember exactly what the task was, but it was so much easier looping through all numbers then throwing them out when they failed a test rather than generating them 'correctly' the first time around.
Then the trick can be making this recursive. That's where a second loop to throw out the bad ones becomes the real time saver for the programmer, although perhaps not the 'best' way to do it.
I would've tried this today, but I was busy on another project. And now John has done it so that should be enough.
I think it might have been in a thread calculating odds, perhaps in the PHP section, ring any bells? I don't think I contributed to that thread, but was lurking in it.
However, this challenge stipulates that we list all the good numbers and all the bad numbers. Unless I misunderstood that, we can't skip anything.
But, in the challenge author's blog there is a response page:
http://beust.com/weblog/2008/08/28/coding-challenge-wrap-up/
where several or more elegant and not so elegant solutions are proffered in various languages. It looks to me, even though I'm no expert in those languages, that at least some of the solutions, even the ones he lists first as having impressed him in one way or another, seem to play fast and loose with the original stipulations. I see a number that don't look like they output anything.
Javascript and PHP will never approach the speeds of some of those other languages. C/C++ are probably about the industry standard for speed. That one called j I never heard of, neither had Cedric, but he checked and it's a real language. It might be faster.
And on that blog page, speed had become the main criteria, as he upped the ante to 10 to the tenth as the minimum number to count to. Just using 1000000, will crash Firefox with my javascript method. It gets the right answer, but the browser is useless after that. And it takes forever.
I've tightened the code up a little and noticed that it runs faster on Chrome, 1000000 runs OK there with the new code, but there's a noticeable lag of a few moments and refreshing the page causes a crash imminent warning, I selected to skip the page and went back to 10000, then it was OK again in Chrome:
<!DOCTYPE html>
<html>
<head>
<title>Beustiality</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<style type="text/css">
table {
border: 2px solid #ccc;
}
td {
border: 1px solid #555;
}
#good, #bad {
vertical-align: top;
}
th {
font: bold 95% sans-serif;
}
</style>
<script type="text/javascript">
// Cedric Beust's Challenge Script (c)2012 John Davenport Scheuer
// as first seen in http://www.dynamicdrive.com/forums/
// username: jscheuer1 - This Notice Must Remain for Legal Use
function beust(){
var start = 1, max = 10000, good = [], bad = [], gap = [0, 0], count, gapln, str, temp, i, ok;
count = start - 1;
while(count < max){
ok = true;
str = (++count).toString(10);
temp = str.split('');
i = temp.length;
while(temp[--i]){
if(str.indexOf(temp[i]) !== i){
bad.push(str);
ok = false;
if(gap[1] < (gapln = count - good[good.length - 1])){
gap = [count, gapln];
}
break;
}
}
if(ok){good.push(str);}
}
return {
start : start,
max : max,
gnum : good.length,
good : good.join(', '),
bnum : bad.length,
bad : bad.join(', '),
biggest : gap[1] + ', from: ' + (gap[0] - gap[1] + 1) + ' to: ' + gap[0]
};
}
</script>
</head>
<body>
<table>
<tr>
<th colspan=2 id="title"></th>
</tr>
<tr>
<th>Good</th><th>Bad</th>
</tr>
<tr>
<td id="totg"></td><td id="totb"></td>
</tr>
<tr>
<td id="good"></td><td id="bad"></td>
</tr>
</table>
<script type="text/javascript">
(function(){
var data = beust();
document.getElementById('title').innerHTML = 'Cedric\'s Code Challenge from: ' + data.start + ' to: ' + data.max;
document.getElementById('totg').innerHTML = 'Total Good: ' + data.gnum;
document.getElementById('totb').innerHTML = 'Total Bad: ' + data.bnum + '<br>Largest gap was: ' + data.biggest + ', inclusive';
document.getElementById('good').innerHTML = data.good;
document.getElementById('bad').innerHTML = data.bad;
})();
</script>
</body>
</html>
http://home.comcast.net/~jscheuer1/side/beust.htm
jscheuer1
06-25-2012, 03:40 PM
<?php
$total = 0;
for ($i = 0; $i < 1000; $i++) {
$total += $i;
$array = str_split($i);
for($v = 0; $v < count($array); $v++) {
if(substr_count($i,$array[$v]) == 1) {
echo $i . '<br />';
break;
}
}
}
echo 'Total: ' . $total;
?>
Strips out numbers like 11, 22, 33 but not 101, 122, 262... Can anyone work out why???
This logic:
if(substr_count($i,$array[$v]) == 1) {
in that loop checks each character. If it finds one that's unique it echoes the number. Because of that, numbers like 984 get echoed 3 times, 991 gets echoed once. 999 is skipped. 1000 is not considered, if it were it would echo once for the 1. 10 echoes twice.
Even if it worked, it doesn't completely fulfill the original challenge. Neither does this, but it fixes the above problem:
<?php
$total = 0;
for ($i = 0; $i < 1001; ++$i) {
$total += $i;
$str = implode('', array_unique(str_split($i)));
if($str == $i){
echo $i . '<br />';
}
}
echo 'Total: ' . $total;
?>
djr33
06-25-2012, 07:25 PM
However, this challenge stipulates that we list all the good numbers and all the bad numbers. Unless I misunderstood that, we can't skip anything.You're right, John. These directions do suggest you do it in that way. And I'm not sure (I think the math is beyond me) how you could do this without stripping them out. I'm just saying that the harder version of this is to "plan ahead" rather than go through a second time.
In fact, the easiest way to do this is just with two loops: generate all numbers, then loop through all of them and decide good/bad. Done.
(You could also embed one in the other, but that's not necessary and could potentially make the logic a little complicated, as in the case of what keyboard did.)
jscheuer1
06-26-2012, 12:08 AM
You're right, John. These directions do suggest you do it in that way. And I'm not sure (I think the math is beyond me) how you could do this without stripping them out. I'm just saying that the harder version of this is to "plan ahead" rather than go through a second time.
In fact, the easiest way to do this is just with two loops: generate all numbers, then loop through all of them and decide good/bad. Done.
(You could also embed one in the other, but that's not necessary and could potentially make the logic a little complicated, as in the case of what keyboard did.)
In my revised edition, that's what I do 1 loop in a loop:
while(count < max){
ok = true;
str = (++count).toString(10);
temp = str.split('');
i = temp.length;
while(temp[--i]){
if(str.indexOf(temp[i]) !== i){
bad.push(str);
ok = false;
if(gap[1] < (gapln = count - good[good.length - 1])){
gap = [count, gapln];
}
break;
}
}
if(ok){good.push(str);}
}
See post #12 for the full revised code.
But the real bottleneck here is javascript. Other languages have innate functions (like uniq, or similar under other names) that can do this stuff so much faster, and closer to machine level, rather than relying upon the browser's script engine.
In any language, it's my impression that an innate function is always faster than one you write in that language to replace it or create it if none exists. That's certainly true in javascript.
djr33
06-26-2012, 06:31 AM
In any language, it's my impression that an innate function is always faster than one you write in that language to replace it or create it if none exists. That's certainly true in javascript. I've gotten the impression that expert users believe they can write certain functions in a faster way than some of the defaults in PHP. But probably not all. I can certainly imagine that is true for JS, and probably for some of PHP and other languages. I'd guess that of course it's the general pattern rather than the other way, but in some cases (what about C++?) it would be equivalent if written with the same logic.
JS might be slower because it needs to parse it?
jscheuer1
06-26-2012, 07:32 AM
I've never heard of a function written in javascript to replace native code that was faster than the native code, do you have any examples?
Parsing may be an issue in speed in some cases, not so much here because the code is short and sweet. It's the loops. You have to check every digit of every number that passes. Well, depending upon which direction you're checking the digits in, you can actually skip the first or last digit. By the time you get to it, if none of the others matched it, it's unique. But it's still a lot of checking per number once the numbers start getting larger/longer. And there seems to be in javascript a sort of 'loop decay'. Almost like a human doing a repetitive action would forget exactly what they're doing and slow down, or get bored, maybe even lose count.
Javascript just isn't built for speed though, for whatever reasons, and this is widely known. PHP isn't much better if at all. I fixed keyboard1333's code so it at least listed the 'good' numbers correctly. It bogs down around 1000000, just the way javascript does.
PHP and javascript are both runtime languages. For speed you need a compiled language. That's not enough on its own, the code still has to be well written, but it does seem to be a prerequisite.
bernie1227
06-26-2012, 08:38 AM
I've never heard of a function written in javascript to replace native code that was faster than the native code, do you have any examples?
Parsing may be an issue in speed in some cases, not so much here because the code is short and sweet. It's the loops. You have to check every digit of every number that passes. Well, depending upon which direction you're checking the digits in, you can actually skip the first or last digit. By the time you get to it, if none of the others matched it, it's unique. But it's still a lot of checking per number once the numbers start getting larger/longer. And there seems to be in javascript a sort of 'loop decay'. Almost like a human doing a repetitive action would forget exactly what they're doing and slow down, or get bored, maybe even lose count.
Javascript just isn't built for speed though, for whatever reasons, and this is widely known. PHP isn't much better if at all. I fixed keyboard1333's code so it at least listed the 'good' numbers correctly. It bogs down around 1000000, just the way javascript does.
PHP and javascript are both runtime languages. For speed you need a compiled language. That's not enough on its own, the code still has to be well written, but it does seem to be a prerequisite.
Indeed, it seems that web based scripting languages aren't good for heavy number crunching, offline applications seem to be more appropriate for that kind of thing, just on that topic, I was wondering what you guys think each kind of language are more suitable for.
Bernie
jscheuer1
06-26-2012, 07:39 PM
I don't know enough about all the various languages to really say. If I see a problem I generally can tell what might be good, if not best at dealing with it.
Assuming one wanted the output live on the web, what I would try with this one is to use PHP, but have it drop to the OS for a C or C++ app to do the math, which would pass back the info to PHP for display. I've done this before where I had an app for solving/generating sudoku. It output to the console, which PHP was able to pick up, format and echo to the page.
bernie1227
06-26-2012, 08:47 PM
I don't know enough about all the various languages to really say. If I see a problem I generally can tell what might be good, if not best at dealing with it.
Assuming one wanted the output live on the web, what I would try with this one is to use PHP, but have it drop to the OS for a C or C++ app to do the math, which would pass back the info to PHP for display. I've done this before where I had an app for solving/generating sudoku. It output to the console, which PHP was able to pick up, format and echo to the page.
As far as I'm aware, the best language for very heavy number crunching, is MATLAB, which is used by a lot of mathematicians to do very big equations.
Bernie
jscheuer1
06-27-2012, 12:31 AM
That may be, but I'd bet C or C++ would be fine for this. Even Java (not javascript) would be a great improvement over javascript or PHP. Do you code in MATLAB or C, C++, Java? Any higher level language?
I should probably learn one of them. It would come in handy for this and other things. I recently had an interesting paid job. It has a NDA so I can't go into the details. But I wrote the javascript, another fellow wrote and compiled the Java, a boss who didn't understand either language but who had the best grasp of the three of us of the overall project goals, advised and asked questions. I got to see some of the uncompiled Java code. It looked pretty easy. Once compiled it executes lightning fast compared to runtime code like PHP and javascript. But it needed javascript in order to interact with the page.
bernie1227
06-27-2012, 03:26 AM
That may be, but I'd bet C or C++ would be fine for this. Even Java (not javascript) would be a great improvement over javascript or PHP. Do you code in MATLAB or C, C++, Java? Any higher level language?
I should probably learn one of them. It would come in handy for this and other things. I recently had an interesting paid job. It has a NDA so I can't go into the details. But I wrote the javascript, another fellow wrote and compiled the Java, a boss who didn't understand either language but who had the best grasp of the three of us of the overall project goals, advised and asked questions. I got to see some of the uncompiled Java code. It looked pretty easy. Once compiled it executes lightning fast compared to runtime code like PHP and javascript. But it needed javascript in order to interact with the page.
At the moment, I do a bit of coding, particularly with visual BASIC, and a bit of C++, both of which are very suitable, but I have a friend who works in a heavy mathematics job and uses MATLAB.
Those kind of languages are very useful for fast or large calculations as well as many other things.
That seems like a very efficient way to do it.
Bernie
djr33
06-27-2012, 05:13 AM
You don't need MATLAB for this. It's not all that intense.
I've never heard of a function written in javascript to replace native code that was faster than the native code, do you have any examples?Sorry. My post was written badly. I wanted to state that I can imagine that you are CORRECT for JS, not that I think JS has cases of being faster than default functions. I think it's not designed the same way as PHP, etc. We don't disagree. I just wasn't clear.
jscheuer1
06-27-2012, 05:38 AM
You don't need MATLAB for this. It's not all that intense.
Sorry. My post was written badly. I wanted to state that I can imagine that you are CORRECT for JS, not that I think JS has cases of being faster than default functions. I think it's not designed the same way as PHP, etc. We don't disagree. I just wasn't clear.
That's OK, it's (native faster vs. substitute functions slower in javascript) just something I've pretty much always assumed, have seen in some cases borne out in testing and frequently see stated.
Like any rule, I suppose there could be one or more exceptions.
But am I to infer that in PHP you mean that you can rewrite its native functions and gain a speed advantage? If so, do you mean rewrite in PHP or farm out to another language? If the former, I would think that would mean PHP isn't written all that well, the latter, well that's perfectly understandable.
bernie1227
06-27-2012, 06:27 AM
You don't need MATLAB for this. It's not all that intense.
.
I wasnt saying that you need it, I was saying that it would be faster and if you wanted to Do this to a higher number
Bernie
Powered by vBulletin® Version 4.2.2 Copyright © 2021 vBulletin Solutions, Inc. All rights reserved.