0

I had to solve the following problem:-

problem

9 values, from 1 to 9 (0 and 10 not accepted) and all numbers need to be different.

To solve the problem, I made those horrible for loops inside for loops.
(I added 2 more conditions to check if I had one of the solutions)
It is working, but I was wondering how to create those for loops inside for loops in a better way?

Also, each number can't be equal to another. How can you accomplish this another way than I did? (Again, 2 first conditions can be deleted)

Here is code:

var a = 1,
 b = 1,
 c = 1,
 d = 1,
 e = 1,
 f = 1,
 g = 1,
 h = 1,
 i = 1

var x = 0

var result = []

function calc() {
 x = a + (13 * b) / c + d + 12 * e - f - 11 + (g * h) / i - 10

 if (x == 66) {
  result.push([a, b, c, d, e, f, g, h, i])
 }
}

for (a = 1; a < 10; a++) {
 calc()
 for (b = 1; b < 10; b++) {
  calc()
  for (c = 1; c < 10; c++) {
   calc()
   for (d = 1; d < 10; d++) {
    calc()
    for (e = 1; e < 10; e++) {
     calc()
     for (f = 1; f < 10; f++) {
      calc()
      for (g = 1; g < 10; g++) {
       calc()
       for (h = 1; h < 10; h++) {
        calc()
        for (i = 1; i < 10; i++) {
         calc()
        }
       }
      }
     }
    }
   }
  }
 }
}

console.log(result)

var result2 = result.filter(function (el) {
 return (
  el[0] == 5 &&
  el[1] == 9 &&
  el[0] != el[1] &&
  el[0] != el[2] &&
  el[0] != el[3] &&
  el[0] != el[4] &&
  el[0] != el[5] &&
  el[0] != el[6] &&
  el[0] != el[7] &&
  el[0] != el[8] &&
  el[1] != el[0] &&
  el[1] != el[2] &&
  el[1] != el[3] &&
  el[1] != el[4] &&
  el[1] != el[5] &&
  el[1] != el[6] &&
  el[1] != el[7] &&
  el[1] != el[8] &&
  el[2] != el[0] &&
  el[2] != el[1] &&
  el[2] != el[3] &&
  el[2] != el[4] &&
  el[2] != el[5] &&
  el[2] != el[6] &&
  el[2] != el[7] &&
  el[2] != el[8] &&
  el[3] != el[0] &&
  el[3] != el[1] &&
  el[3] != el[2] &&
  el[3] != el[4] &&
  el[3] != el[5] &&
  el[3] != el[6] &&
  el[3] != el[7] &&
  el[3] != el[8] &&
  el[4] != el[0] &&
  el[4] != el[1] &&
  el[4] != el[2] &&
  el[4] != el[3] &&
  el[4] != el[5] &&
  el[4] != el[6] &&
  el[4] != el[7] &&
  el[4] != el[8] &&
  el[5] != el[0] &&
  el[5] != el[1] &&
  el[5] != el[2] &&
  el[5] != el[3] &&
  el[5] != el[4] &&
  el[5] != el[6] &&
  el[5] != el[7] &&
  el[5] != el[8] &&
  el[6] != el[1] &&
  el[6] != el[2] &&
  el[6] != el[3] &&
  el[6] != el[4] &&
  el[6] != el[5] &&
  el[6] != el[7] &&
  el[6] != el[8] &&
  el[7] != el[0] &&
  el[7] != el[1] &&
  [7] != el[2] &&
  el[7] != el[3] &&
  el[7] != el[4] &&
  el[7] != el[5] &&
  el[7] != el[6] &&
  el[7] != el[8] &&
  el[8] != el[0] &&
  el[8] != el[1] &&
  el[8] != el[2] &&
  el[8] != el[3] &&
  el[8] != el[4] &&
  el[8] != el[5] &&
  el[8] != el[6] &&
  el[8] != el[7]
 )
})

console.log(result2)
DSDmark
  • 1,045
  • 5
  • 11
  • 25
gr3g
  • 2,866
  • 5
  • 28
  • 52
  • 6
    I think this should go to [CodeReview.SE](http://codereview.stackexchange.com) because the code is working but the OP asks for improvement. StackOverflow is for secific problems with non-working code. – Sebastian Simon May 27 '15 at 20:56
  • On the plus side, the code is easy to understand – samgak May 27 '15 at 23:19
  • may be a silly question but why are you calling `calc()` so many times ? also this is `O(9^9)` instead of obvious `O(9!)` – Spektre May 28 '15 at 05:51
  • Well give me 0(9!), with clean code. that's the question – gr3g May 28 '15 at 06:41

1 Answers1

-2

for starters you can make N x nested for loops like this

You can handle your problem as a 9 digit number generation

As your digits are not repeating you can discard many iterations. If encoded in the above manner (like nested for) you will came up with something like this:

Generalized Permutation (without repetitions) in C++:

//---------------------------------------------------------------------------
//--- permutation class ver 0.00 --------------------------------------------
//---------------------------------------------------------------------------
#ifndef _permutation_h
#define _permutation_h
/*---------------------------------------------------------------------------
    // usage:
    permutation per;
    per.alloc(N);

    per.first();
    for (;;)
        {
        ... here per.i[0..N-1] contains actual permutation
        ... N! permutations
        if (!per.next()) break;
        }
//-------------------------------------------------------------------------*/
class permutation
    {
public:
    int  *i;    // i[N] permutation
    BYTE *a;    // a[N] item not used yet ?
    int   N;    // items
    int  ix;    // actual permutation layer
    permutation()   { N=0; i=NULL; a=NULL; ix=0; }
    permutation(permutation& b) { *this=b; }
    ~permutation()  { free(); }
    permutation* operator = (const permutation *b) { *this=*b; return this; }
    permutation* operator = (const permutation &b) { alloc(b.N); for (int j=0;j<N;j++) { i[j]=b.i[j]; a[j]=b.a[j]; } ix=b.ix; return this; }

    void alloc(int _N)
        {
        free();
        i=new  int[_N];
        if (i==NULL) return;
        a=new BYTE[_N];
        if (a==NULL) { free(); return; }
        N=_N;
        }
    void free ()
        {
        N=0; ix=0;
        if (i!=NULL) delete i; i=NULL;
        if (a!=NULL) delete a; a=NULL;
        }
    void first()                                        // init permutation
        {
        for (ix=0;ix<N;ix++)
            {
            i[ix]=ix;
            a[ix]=0;
            } ix--;
        }
    bool next()                                         // next permutation return if it is not last
        {
        int *ii=&i[ix];
        for (;;)
            {
            if (*ii>=0) a[*ii]=1;
            for ((*ii)++;*ii<N;(*ii)++) if (a[*ii]) { a[*ii]=0; break; }
            if (*ii>=N)
                {
                if (ix==  0) return false;
                *ii=-1; ix--; ii=&i[ix];
                }
            else{
                if (ix==N-1) return true;
                ix++; ii=&i[ix];
                }
            }
        }
    };
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

The important stuff is in first() and next() members, each permutation is stored in the i[] array as index so set N=9 and your output numbers will be (per.i[0]+1),(per.i[1]+1),...,(per.i[9]+1)

it works in following manner:

  1. first() initialize permutation to state i[9]=(0,1,2,...8) and a[9]=(0,0,0,...0)

    I will write this for simplicity like this: i=012345678,a=000000000 where

    • ix points to last digit
    • i is the actual permutation
    • a flags if digit is unused(1) or used(0) (to avoid O(N^N) operation)
  2. next() increment to next valid permutation

    Increase the last digit to next unused value. If no unused value set it as unused and increment previous digit. The same goes for overflow. The first iteration will be like this:

    i=012345678,a=000000000 // starting iteration
    i=01234567? a=000000001 // unset (no unused values)
    i=01234568? a=000000010 // increment 8th digit
    i=012345687 a=000000000 // set the last digit result
    

    next iteration:

    i=012345687 a=000000000 // starting iteration
    i=01234568? a=000000010 // unset (no unused values)
    i=0123456?? a=000000011 // unset (8->9 overflow)
    i=0123457?? a=000000101 // increment 7th digit
    i=01234576? a=000000001 // after overflow digit set to lowest free value
    i=012345768 a=000000000 // after overflow digit set to lowest free value
    

    I hope it is clear enough.

Of coarse if you use recursion instead of iteration the code will look much nicer but in most languages will run also slower due to stack/heap trashing

As @NikolaDimitroff pointed out this is in C++ instead of javascript so:

  • ignore new,delete and class members other then first(),next()
  • set N=9; and arrays i,a can be static like: int i[9]; BYTE a[9];

Here the solution O(N!) for the task in C++:

int a,b,c,d,e,f,g,h,i;
permutation per;
per.alloc(9);
per.first();
for (;;)
    {
    if ((per.i[0]+1)
        +(13*(per.i[1]+1)/(per.i[2]+1))+(per.i[3]+1)
        +(12*(per.i[4]+1))
        -(per.i[5]+1)-11
        +((per.i[6]+1)*(per.i[7]+1)/(per.i[8]+1))-10
        ==66)
        {
        a=per.i[0]+'1';
        b=per.i[1]+'1';
        c=per.i[2]+'1';
        d=per.i[3]+'1';
        e=per.i[4]+'1';
        f=per.i[5]+'1';
        g=per.i[6]+'1';
        h=per.i[7]+'1';
        i=per.i[8]+'1';
        // here a,b,c,d,e,f,g,h,i holds the solution
        break;
        }
    if (!per.next()) break;
    }
Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380
  • 1
    The OP's question is regarding JS and you are providing a C++ solution. You should not expect that everyone knows C++, especially when you are allocating memory yourself which is something unheard of in other languages. – Nikola Dimitroff May 28 '15 at 05:54
  • @NikolaDimitroff I think as illustration it is good enough as the memory allocation is not that important in this case (N is always 9) and C++ and JS are similar enough. But as you do not agree with this you should post how you would done this instead to also help the OP to solve this – Spektre May 28 '15 at 06:06