CodeWars / Merged String Checker

时间:2018-04-21 21:40:01

标签: javascript arrays string algorithm sorting

接下来是挑战:

  

在求职面试中,你要写一个算法来检查给定的字符串s是否可以由另外两个字符串part1和part2组成。   限制是part1和part2中的字符与s中的字符顺序相同。   面试官给出了以下示例,并告诉您从给定的测试用例中找出其余部分。

我做错了什么?无论如何它为什么会失败?

我写了两个不同的脚本,两个都不适用于某些测试用例

function isMerge(s, part1, part2) {
    var sArr = s.split('');
    var part1Arr = part1.split('');
    var part2Arr = part2.split('');
    var tempArr = new Array(sArr.length);
    function compareArrays(arr1, arr2){
    var count = 0;
    for (var i = 0; i < arr1.length; i++) {
        if (arr1[i] !== arr2[i]) count++;
    }
    return (count == 0);
    }
    for (var i = 0; i < sArr.length; i++) {
        for (var j = 0; j < part1Arr.length; j++) {
            if (sArr[i] == part1Arr[j]) tempArr[i] = j;
        }
        for (var k = 0; k < part2Arr.length; k++) {
            if (sArr[i] == part2Arr[k]) tempArr[i] = k;
        }
    }
    alert(tempArr);
    var check = tempArr.slice();
    check.sort();
    alert(check);
    if (compareArrays(tempArr, check)) return true;
    else return false;
}
alert(isMerge('codewars', 'cdw', 'oears'));

function isMerge(s, part1, part2) {
    // create arrays of letters
    var sArr = s.split('');
    var part1Arr = part1.split('');
    var part2Arr = part2.split('');
    // create an associative array 'temp' (0:C, 1:O and so on)
    var temp = {};
    for (var k = 0; k < sArr.length; k++) {
      temp[k] = sArr[k];
    }
    // reverse an associative array 'temp' (now C:0, O:0 and so on)
    for (var key in temp) {
        var keyTemp = key;
        var keyValue = temp[key];
        key = keyValue;
        temp[key] = keyTemp;
    }
    // the function that compares arrays
    function compareArrays(arr1, arr2){
        var count = 0;
        for (var i = 0; i < arr1.length; i++) {
            if (arr1[i] !== arr2[i]) count++;
        }
        return (count == 0);
        }
    // sorting function
    function order(a, b) {
        var comparingA;
        var comparingB;
      for (var char in temp) {
          if (char == a) {
              comparingA = temp[char]; // comparingA is the number of 'a' in object 'temp'
          }
          if (char == b){
              comparingB = temp[char]; // comparingB is the number of 'b' in object 'temp'
          }
      }
        return (comparingA - comparingB);
    }
    // create copies of arrays
    var part1Sorted = part1Arr.slice();
    var part2Sorted = part2Arr.slice();
    // and sort that copies
    part1Sorted.sort(order);
    part2Sorted.sort(order);
    // If the array did not change after sorting, the order of the letters was correct
    if  (compareArrays(part1Sorted, part1Arr) && compareArrays(part2Sorted, part2Arr)) {
    // so now we can check is merge possible
    sArr = sArr.sort();
    var parts = part1Arr.concat(part2Arr);
    parts = parts.sort();
    var res = compareArrays(sArr, parts);
    return res;
    }
    return false;
}
alert(isMerge('codewars', 'code', 'wasr'));
alert(isMerge('codewars', 'oers', 'cdwa'));

我刚刚在第二个脚本中添加了评论

6 个答案:

答案 0 :(得分:2)

我发现很难理解您的代码尝试做什么。如果您提供评论并解释您试图实施的算法背后的想法,将会有所帮助。

这是一个递归的注释示例,它考虑指针ij是否指向第1部分和第1部分。 2可以构成到那一点的有效合并。

&#13;
&#13;
function isMerge(s, part1, part2) {
  // Merge is invalid if the parts' lengths don't add up to the string's
  if (part1.length + part2.length != s.length)
    return false;
    
  // Recursive function
  function g(i, j){
    // Base case: both pointers are exactly at the end of each part
    if (i == part1.length && j == part2.length)
      return true;
    
    // One of our pointers has extended beyond the part's length,
    // that couldn't be right
    if (i > part1.length || j > part2.length)
      return false;
    
    // Just part1 matches here so increment i
    if (part1[i] == s[i + j] && part2[j] != s[i + j])
      return g(i + 1, j);
      
    // Just part2 matches here so increment j
    else if (part1[i] != s[i + j] && part2[j] == s[i + j])
      return g(i, j + 1);
      
    // Both parts match here so try incrementing either pointer
    // to see if one of those solutions is correct
    else if (part1[i] == s[i + j] && part2[j] == s[i + j])
      return g(i + 1, j) || g(i, j + 1);
      
    // Neither part matches here
    return false;
  }
    
  // Call the recursive function
  return g(0,0);
}

console.log(isMerge('codewars', 'cdw', 'oears'));
console.log(isMerge('codecoda', 'coda', 'code'));
console.log(isMerge('codewars', 'oers', 'cdwa'));
console.log(isMerge('codewars', 'cdw', 'years'));
&#13;
&#13;
&#13;

真正长字符串的堆栈版本:

&#13;
&#13;
function isMerge2(s, part1, part2) {
  if (part1.length + part2.length != s.length)
    return false;
    
  let stack = [[0,0]];
  
  while (stack.length){
    [i, j] = stack.pop();
    
    if (i == part1.length && j == part2.length)
      return true;

    if (i > part1.length || j > part2.length)
      continue;
    
    if (part1[i] == s[i + j] && part2[j] != s[i + j])
      stack.push([i + 1, j]);
      
    else if (part1[i] != s[i + j] && part2[j] == s[i + j])
      stack.push([i, j + 1]);
      
    else if (part1[i] == s[i + j] && part2[j] == s[i + j]){
      stack.push([i + 1, j]);
      stack.push([i, j + 1]);
    }
  }
    
  return false;
}

function test(){
  let s = '';
  
  for (let i=0; i<1000000; i++)
    s += ['a','b','c','d','e','f','g'][~~(Math.random()*6)];
  
  let lr = {
    l: '',
    r: ''
  };
  
  for (let i=0; i<s.length; i++){
    let which = ['l', 'r'][~~(Math.random()*2)];
    
    lr[which] += s[i];
  }
  
  console.log(isMerge2(s,lr.l,lr.r));
}

test();
&#13;
&#13;
&#13;

答案 1 :(得分:1)

递归呼叫:

您可以使用递归方法,首先检查字符串和部分字符串的长度,然后检查长度或检查字符并检查给定部分字符串的其余部分。

function isMerge(s, part1, part2) {
    if (s.length !== part1.length + part2.length) {
        return false;
    }

    if (!s.length) {
        return true;
    }

    if (part1[0] === s[0] && isMerge(s.slice(1), part1.slice(1), part2)) {
        return true;
    }

    if (part2[0] === s[0] && isMerge(s.slice(1), part1, part2.slice(1))) {
        return true;
    }

    return false;
}

console.log(isMerge('codewars', 'cdw', 'oears'));  //  true
console.log(isMerge('codewars', 'oers', 'cdwa'));  //  true
console.log(isMerge('codecoda', 'coda', 'code'));  //  true
console.log(isMerge('baeabb', 'b', 'baeab'));      //  true
console.log(isMerge('bdab', 'bdab', ''));          //  true
console.log(isMerge('bfaef', 'f', 'bfae'));        //  true
console.log(isMerge('codewars', 'cdw', 'years'));  // false
console.log(isMerge('codewars', 'code', 'warss')); // false
console.log(isMerge('codewars', 'codes', 'wars')); // false
console.log(isMerge('', 'a', 'b'));                // false
.as-console-wrapper { max-height: 100% !important; top: 0; }

使用堆栈而不是递归调用:

function isMerge(s, part1, part2) {
    var stack = [[s, part1, part2]];

    if (s.length !== part1.length + part2.length) {
        return false;
    }

    while (stack.length) {
        [s, part1, part2] = stack.shift();

        if (!s.length) {
            return true;
        }

        if (part1[0] === s[0]) {
            stack.push([s.slice(1), part1.slice(1), part2]);
        }

        if (part2[0] === s[0]) {
            stack.push([s.slice(1), part1, part2.slice(1)]);
        }
    }
    return false;
}

console.log(isMerge('codewars', 'cdw', 'oears'));  //  true
console.log(isMerge('codewars', 'oers', 'cdwa'));  //  true
console.log(isMerge('codecoda', 'coda', 'code'));  //  true
console.log(isMerge('baeabb', 'b', 'baeab'));      //  true
console.log(isMerge('bdab', 'bdab', ''));          //  true
console.log(isMerge('bfaef', 'f', 'bfae'));        //  true
console.log(isMerge('codewars', 'cdw', 'years'));  // false
console.log(isMerge('codewars', 'code', 'warss')); // false
console.log(isMerge('codewars', 'codes', 'wars')); // false
console.log(isMerge('', 'a', 'b'));                // false
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 2 :(得分:1)

这是一种递归方法:它检查字符串的第一个字符与其中任何一个部分的匹配,如果匹配recurses,则尝试将其余字符串与其余字符串匹配部分。棘手的是,当两个部分的第一个字符相同时,你必须检查你是否可以匹配其中任何一个(这解决了Bananas测试)。

function isMerge(str, p1, p2) {
  if (!str.length) return !p1.length && !p2.length;
  if (p1.length && str.charAt(0) == p1.charAt(0)) {
    if (p2.length && str.charAt(0) == p2.charAt(0)) {
      return isMerge(str.substr(1), p1.substr(1), p2) || isMerge(str.substr(1), p1, p2.substr(1));
    }
    else {
      return isMerge(str.substr(1), p1.substr(1), p2);
    }
  }
  else if (p2.length && str.charAt(0) == p2.charAt(0)) {
    return isMerge(str.substr(1), p1, p2.substr(1));
  }
  else {
    return false;
  }
}

答案 3 :(得分:0)

你可以在下面试试吗?

function isMerge(s, part1, part2) { 
  var result= true;
  var total = part1 + part2; 
  for (var i = 0; i < s.length; i++) { 
    var char = s.charAt(i); 
    if(total.indexOf(char) === -1) {
      result = false;
      break;
    } 
  } 
  return result;
} 

答案 4 :(得分:0)

首先,这是您的代码正常工作:

function isMerge(s, part1, part2) {
var sArr = s.split('');
var part1Arr = part1.split('');
var part2Arr = part2.split('');
var tempArr = new Array(sArr.length);
function compareArrays(arr1, arr2){
var count = 0;
for (var i = 0; i < arr1.length; i++) {
    if (arr1[i] != arr2[i]) count++;
}
return (count == 0);
}
for (var i = 0; i < sArr.length; i++) {
    for (var j = 0; j < part1Arr.length; j++) {
        if (sArr[i] == part1Arr[j]) tempArr[i] = part1Arr[j];
    }
    for (var k = 0; k < part2Arr.length; k++) {
        if (sArr[i] == part2Arr[k]) tempArr[i] = part2Arr[k];
    }
}
alert(tempArr);

 if (compareArrays(tempArr, sArr)) return true;
 else return false;
}
alert(isMerge('codewars', 'cdw', 'oears'));

现在,问题是什么?

for (var j = 0; j < part1Arr.length; j++) {

                /* Here you assigned the index (tempArr[i] = j;) not the char */
     if (sArr[i] == part1Arr[j]) tempArr[i] = part1Arr[j];
}

for (var k = 0; k < part2Arr.length; k++) {

                /* Here you assigned the index (tempArr[i] = k;) not the char */
     if (sArr[i] == part2Arr[k]) tempArr[i] = part2Arr[k];
}

希望我能帮助你;)

答案 5 :(得分:0)

简单合并逻辑:

function isMerge(s, part1, part2) {
    var sArr = s.split('');
    var part1Arr = part1.split('');
    var part2Arr = part2.split('');
    
    var j = 0;
    var k = 0;
    for (var i = 0; i < sArr.length; i++) {
        if ((j < part1Arr.length) && (sArr[i] == part1Arr[j]))
          j++
        else if ((k < part2Arr.length) && (sArr[i] == part2Arr[k])) 
          k++
        else 
          break
    }
    return (j == part1Arr.length && k == part2Arr.length && (j + k) == sArr.length);
}

console.log(isMerge('abcd', 'ac', 'bd'));
console.log(isMerge('abcd', 'acd', 'b'));
console.log(isMerge('abcd', 'ac', 'b'));
console.log(isMerge('abcd', 'ac', 'db'));
console.log(isMerge('abcd', 'c', 'b'));
console.log(isMerge('a', '', 'a'));
console.log(isMerge('', '', ''));
console.log(isMerge('', 'a', 'b'));
console.log(isMerge('ab', '', ''));