如何在2dArray中使用给定的字符串

时间:2018-11-10 11:52:11

标签: javascript algorithm

假设我有简单的2d数组

let array2d = [
   ['a','a','b'],
   ['a','b','c'],
   ['a','c','a']
]

和一个随机长度的简单字符串,例如:

let string = 'abc';

如何在给定顺序重要的给定数组中找到该字符串的所有可能组合?

因此在此示例中,结果应为:

result = [
  [
     ['*','a','*'],
     ['a','b','*'],
     ['a','c','a']
  ],
  [
     ['*','a','*'],
     ['a','b','c'],
     ['a','*','a']
  ],
  [
     ['*','a','b'],
     ['a','*','*'],
     ['a','c','a']
  ],
  [
     ['*','a','b'],
     ['a','*','c'],
     ['a','*','a']
  ],
  [
     ['a','*','*'],
     ['a','b','*'],
     ['a','c','a']
  ],
  [
     ['a','*','*'],
     ['a','b','c'],
     ['a','*','a']
  ],
  [
     ['a','*','b'],
     ['a','*','*'],
     ['a','c','a']
  ],
  [
     ['a','*','b'],
     ['a','*','c'],
     ['a','*','a']
  ],
  [
     ['a','a','b'],
     ['*','*','*'],
     ['a','c','a']
  ],
  [
     ['a','a','b'],
     ['*','*','c'],
     ['a','*','a']
  ],
]

我对此有一些想法,但是我真的不确定。

  1. 我曾考虑过对字符串中的每个字母使用坐标数组,但我还没有弄清楚如何将其用于字符串的随机长度
  2. 将数组展平为1维并在其中查找索引可能会更容易。之后,将数组返回二维。

1 个答案:

答案 0 :(得分:0)

实际上,您很少想运动。 2方向正确。我所做的就是将任务分成两个部分:1.查找所有角色位置,2.将所有组合递归组合。

let array2d = [["a", "a", "b"], ["a", "b", "c"], ["a", "c", "a"]];
let string = "abc";

var chars = string.split(""); //Convert string to [ 'a', 'b', 'c' ]
var dataAsString = array2d.map(function(d) {
  return d[0] + d[1] + d[2];
});
let concatedArrayString = dataAsString.join(""); //Convert array2d to "aababcaca"

let locations = findAllCharLocations(chars, concatedArrayString); // returns { a: [ 0, 1, 3, 6, 8 ], b: [ 2, 4 ], c: [ 5, 7 ] }
var result = [];
recursiveFindAllCombinations(0, array2d, locations, []);
console.log(result);
// The result is:
// [ [ [ '*', 'a', '*' ], [ 'a', 'b', '*' ], [ 'a', 'c', 'a' ] ],
//   [ [ '*', 'a', '*' ], [ 'a', 'b', 'c' ], [ 'a', '*', 'a' ] ],
//   [ [ '*', 'a', 'b' ], [ 'a', '*', '*' ], [ 'a', 'c', 'a' ] ],
//   [ [ '*', 'a', 'b' ], [ 'a', '*', 'c' ], [ 'a', '*', 'a' ] ],
//   [ [ 'a', '*', '*' ], [ 'a', 'b', '*' ], [ 'a', 'c', 'a' ] ],
//   [ [ 'a', '*', '*' ], [ 'a', 'b', 'c' ], [ 'a', '*', 'a' ] ],
//   [ [ 'a', '*', 'b' ], [ 'a', '*', '*' ], [ 'a', 'c', 'a' ] ],
//   [ [ 'a', '*', 'b' ], [ 'a', '*', 'c' ], [ 'a', '*', 'a' ] ],
//   [ [ 'a', 'a', '*' ], [ '*', 'b', '*' ], [ 'a', 'c', 'a' ] ],
//   [ [ 'a', 'a', '*' ], [ '*', 'b', 'c' ], [ 'a', '*', 'a' ] ],
//   [ [ 'a', 'a', 'b' ], [ '*', '*', '*' ], [ 'a', 'c', 'a' ] ],
//   [ [ 'a', 'a', 'b' ], [ '*', '*', 'c' ], [ 'a', '*', 'a' ] ],
//   [ [ 'a', 'a', '*' ], [ 'a', 'b', '*' ], [ '*', 'c', 'a' ] ],
//   [ [ 'a', 'a', '*' ], [ 'a', 'b', 'c' ], [ '*', '*', 'a' ] ],
//   [ [ 'a', 'a', 'b' ], [ 'a', '*', '*' ], [ '*', 'c', 'a' ] ],
//   [ [ 'a', 'a', 'b' ], [ 'a', '*', 'c' ], [ '*', '*', 'a' ] ],
//   [ [ 'a', 'a', '*' ], [ 'a', 'b', '*' ], [ 'a', 'c', '*' ] ],
//   [ [ 'a', 'a', '*' ], [ 'a', 'b', 'c' ], [ 'a', '*', '*' ] ],
//   [ [ 'a', 'a', 'b' ], [ 'a', '*', '*' ], [ 'a', 'c', '*' ] ],
//   [ [ 'a', 'a', 'b' ], [ 'a', '*', 'c' ], [ 'a', '*', '*' ] ] ]

//Recursivly find all the combinations of a character at index, character array which is modified,
function recursiveFindAllCombinations(
  charIndex,
  characterArray,
  locations,
  currentCharIndexArray
) {
  //Copy the character array since we modifying it but dont want the other references to change
  let charArray = characterArray.map(function(arr) {
    return arr.slice();
  });
  //The current char
  let char = chars[charIndex];
  //For each location the character is found
  for (var index = 0; index < locations[char].length; index++) {
    //Copy the char index array 
    var newCharIndexArray = currentCharIndexArray.slice();
    var isAnOption = true;
    //Check and see if the new value is valid compared to the already choosen values.
    for (var check = 0; check < newCharIndexArray.length; check++) {
      let value = newCharIndexArray[check];
      if (value > locations[char][index]) {
        isAnOption = false;
      }
    }
    if (isAnOption) {
      //Example the first 'a' is found at
      // x = 0 % 3 = 0
      // y = Math.floor(0 / 3) = 0
      let x = locations[char][index] % array2d.length;
      let y = Math.floor(locations[char][index] / array2d.length);
      //Paint that location as found
      charArray[y][x] = "*";
      newCharIndexArray.push(locations[char][index]);
      //If there is more chars call recursively
      if (chars[charIndex + 1]) {
        //Use the next character in line
        recursiveFindAllCombinations(
          charIndex + 1,
          charArray,
          locations,
          newCharIndexArray
        );
      } else {
        //Since no more recursiv calls to do, push a copy of the charArray.
        result.push(
          charArray.map(function(arr) {
            return arr.slice();
          })
        );
      }
      //Reset the charArray
      charArray[y][x] = char;
    }
  }
}

//Find all the char locations
//Example returning : { a: [ 0, 1, 3, 6, 8 ], b: [ 2, 4 ], c: [ 5, 7 ] }
function findAllCharLocations(chars, concatedArrayString) {
  let charsCopy = chars.slice(0); //Make a copy on the char array.
  var locations = {};
  //Initiate the locations array { a: [], b: [], c: [] }
  for (var charIndex = 0; charIndex < charsCopy.length; charIndex++) {
    locations[charsCopy[charIndex]] = [];
  }
  var counter = 0;
  //As long as we havent found all the chars in 2d array continue
  while (counter != chars.length) {
    //Store the chars which we are done with and remove them after the loop.
    var charsToRemove = [];
    //Go through each char.
    for (var index = 0; index < charsCopy.length; index++) {
      let char = charsCopy[index];
      //Get the last index of that specific character, if nothing found yet this will be NaN.
      let lastIndexOfChar = locations[char][locations[char].length - 1];
      //Get the index of the next character
      let indexOfChar = concatedArrayString.indexOf(char, lastIndexOfChar + 1);
      //If a character was found push it to the location array
      if (indexOfChar != -1) {
        locations[char].push(indexOfChar);
      } else {
        //Since the character was not found remove it from the char array and let our counter know one less char to find.
        counter++;
        charsToRemove.push(char);
      }
    }
    //Do the removal of characters no longer found in the string.
    for (var index = 0; index < charsToRemove.length; index++) {
      charsCopy.splice(charsCopy.indexOf(charsToRemove[index]), 1);
    }
  }
  return locations;
}

我不认为这是最佳的实现方式,因此,如果速度至关重要,那么您可能需要对其进行优化,或者是否有人可以提供帮助?

我认为我没有正确实现函数recursiveFindAllCombinations,因为它使用了全局变量结果,所以我只是没有弄清楚如何将其与递归函数合并,让我知道是否可以!

编辑#1

更改了函数recursiveFindAllCombinations以考虑到值必须按所需顺序排列。

相关问题