Nested for loops - how to ignore certain combinations?

前端 未结 2 2141
暗喜
暗喜 2021-02-10 20:58

I\'m doing some kind of brute force attack to solve a problem. Theoratically it is a working solution, it also really is, but it takes rather long.

I have 7 nested for l

相关标签:
2条回答
  • 2021-02-10 21:41

    The problem is that you are doing extra work. In your c loop you already know that a and b are not equal, but you check anyway. You could exploit the flexibility of c-style for loops:

    for(var a=0;a<14;a++) {
        for(var b=0;b<14 && b!=a;b++) {
            for(var c=0;c<14 && c!=a && c!=b;c++) {
                ...
            }
        }
    }
    

    This gets a little verbose in the inner loop, but is at least simple.

    0 讨论(0)
  • 2021-02-10 21:43

    What you're doing here is iterating over all the permutations of a list of 14 discreet values.

    In general, to visit all the permutations of a list of discreet things, you visit each element of the list. For each element, form a new list containing all other elements of the original list. Get all the permutations of that list, prepend the element to each, and you've got all the permutations of the original list that can start with that particular element. When you've done all the elements, you're done.

    Finding all permutations of a list with one element in it is a simple task, of course.

    Thus what we've got is something like this:

    function forEachPermutation(list, operation) {
      function pluckElement(list, index) {
        var e = list[index];
        var l = [];
        for (var i = 0; i < list.length; ++i)
          if (i !== index) l.push(list[i]);
        return { element: e, remainder: l };
      }
    
      function permute(partial, remainder) {
        if (remainder.length === 0)
          operation(partial);
        else {
          for (var i = 0; i < remainder.length; ++i) {
            var plucked = pluckElement(remainder, i);
            partial.push(plucked.element);
            permute(partial, plucked.remainder);
            partial.length--;
          }
        }
      }
    
      permute([], list);
    }
    

    What that does is recursively carry out the operation I described above. The "pluckElement" function returns an element from a list, and the rest of that list. The "permute" function then either carries out the operation passed in on a complete permutation of the original list (when it notices that the remainder list is empty), or else calls itself recursively with each element of the list it's passed.

    To use that function, you'd just do this:

    forEachPermutation([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], check);
    

    edit — if you want to be plucking only a certain number of values from the original list, then the above would have to be modified; give me a sec.

    OK - if you want to pass in a list of (say) 14 elements, but have the "operation" function invoked for each distinct list of (say) 7 of the 14, you could modify the function as follows. The outer "forEachPermutation" function would take an additional "len" parameter, to tell it the length of string desired. Then, the "permute" function would check to see if "partial.length" is that target length, instead of checking for an empty remainder.

    function forEachPermutation(list, len, operation) {
      function pluckElement(list, index) {
        var e = list[index];
        var l = [];
        for (var i = 0; i < list.length; ++i)
          if (i !== index) l.push(list[i]);
        return { element: e, remainder: l };
      }
    
      function permute(partial, remainder) {
        if (partial.length === len)
          operation(partial);
        else {
          for (var i = 0; i < remainder.length; ++i) {
            var plucked = pluckElement(remainder, i);
            partial.push(plucked.element);
            permute(partial, plucked.remainder);
            partial.length--;
          }
        }
      }
    
      permute([], list);
    }
    

    and you'd call it with

    forEachPermutation([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], 7, check);
    

    Another edit — if for some reason you want to save the permutations after the "operation" function processes each one, then we'll have to account for the fact that the partial array being used gets overwritten. The call to "operation" can be changed:

    if (partial.length === len)
      operation(partial.slice(0));
    

    That makes a copy of the "partial" array, so that each invocation of "operation" gets its very own array to use. It'll make the process slower, of course.

    0 讨论(0)
提交回复
热议问题