【问题标题】:check if the string is a combination of strings in a array using javascript使用javascript检查字符串是否是数组中字符串的组合
【发布时间】:2017-10-30 22:35:33
【问题描述】:

我需要检查一个字符串是否由数组中给定的任何字符串组合组成 示例:我们有 ["for","car","keys","forth"] 的数组和一个 "forthcarkeys" 字符串,结果应该是 true。如果字符串是 "forthcarxykeys",结果应该是 false因为 xy 不在数组中。数组中的单词顺序无关紧要。 不必匹配数组中的所有字符串,但测试字符串应仅由数组中的任何字符串组成。如果它包含除数组中的字符串以外的任何字符串,则返回 false

我的方法:

var str = "forthcarkeys";
var arr = ["for","car","keys","forth"];
for(var i=0;i<arr.length;i++)
{
   if(str.indexOf(arr[i]) !== -1)
   {
      str.replace(arr[i],"");
   }
}

if(str !== "")
{
  console.log("yes");
} else 
{
  console.log("no");
}

但这种方法效率不高且失败。

【问题讨论】:

  • 为什么会失败?什么不起作用?
  • 如果我们在数组中有重复,它会失败,因为我们正在替换匹配的字符串,而且如果有更好的方法可以做到这一点,我愿意接受
  • 数组中单词的顺序无关紧要如果你按照单词的长度对数组进行排序,你的代码就可以工作。
  • @George 你能解释一下为什么我们需要按单词长度对数组进行排序
  • @kiranreddy 你不知道。它仅适用于此示例,但您必须尝试每个订单。使用arr = [ "abcd", "def", "abc" ] str = "abcdef" 进行测试

标签: javascript arrays string algorithm


【解决方案1】:

如果yes 的条件是str=="",则需要sort 数组长度Dec 并更改

function check(str){
var arr = ["for", "car", "keys", "forth"];
arr= arr.sort((a,b)=> b.length-a.length) // sort with length dec order
console.log(arr) //longest length string is first then to lower length
for (var i = 0; i < arr.length; i++) {
    str = str.replace(arr[i], ""); 
}

if (str.trim()== "") { //empty 
  console.log("yes");
} else {
  console.log("no");
}
}

check("forthcarkeys")
check("forthcarxykeys")

【讨论】:

  • arr.sort((a,b)=&gt; b.length-a.length) 你能解释一下找到长度差异背后的逻辑吗
  • 降序长度也是我的第一个想法,但如果数组还包含例如'the' 并且字符串为forthecar,这将失败
  • 您能否说明一下为什么我们需要在比较之前进行排序
  • 这不适用于arr = [ "abc", "def", "abcd" ] str = "abcdef"
  • @inetphantom 是的,你能建议一种使它工作的方法
【解决方案2】:

这里是更新的代码。字符串替换不起作用,因此使用正则表达式来实现。 var re = new RegExp(arr[i], 'g');

function check(str, arr) {
  var flag = true;
  for (var i = 0; i < arr.length; i++) {
    if (str.indexOf(arr[i]) === -1) {
      flag = false;
    }
  }

  if (!flag) {
    console.log("Some keys didn't matched.");
  } else {
    console.log("Nothing remains. All matched.");
  }
}

var str = "forcarxy";
var arr = ["for", "car", "keys", "forth"];
check(str, arr);
var arr = ["abcd", "def", "abc"];
var str = "abcdef";
check(str, arr);
var arr = [ "abcd", "cdef" ];
var str = "abcdef";
check(str, arr);
var str = "aabc";
var arr = ["a", "bc"];
check(str, arr);

代码已更新以考虑@inetphantom 评论的案例

【讨论】:

  • 这不适用于arr = [ "abcd", "def", "abc" ] str = "abcdef"
  • 对您的情况进行了必要的更正@inetphantom
  • 如果它应该适合任何组合,这也意味着不使用一个键。你的做法是无效的。另一种情况是:arr = [ "abcd", "cdef" ] 和`str = "abcdef"` 你不应该使用arr 的整个块来创建str
  • @MilanChheda 。你能在你的代码中添加一个错误的陈述吗?喜欢forcarxy
  • 您的代码现在不适用于str = "aabc" arr = ["a", "bc"]
【解决方案3】:

一种可能的方法是检查每个前缀是否可以使用输入字符串表示。

这个想法是,如果我们可以很容易地计算出长度为 i 的前缀是否可以用输入字符串来表示,如果我们已经有了较短前缀的信息(这可以通过检查是否任何允许的字符串都会导致更短的可表达前缀)——见下面的代码。

var str = "forthcarkeys";
var arr = ["for","car","keys","forth"];

// isPossible[i] indicates whether we can express the 
// prefix str.substring(0, i) using strings in arr.
var isPossible = Array(str.length + 1).fill(false);

// it is always possible to construct the empty string
isPossible[0] = true;

// consider each prefix of str, from shortest to longest
for (var i = 1; i <= str.length; i++) {
  // try to reach this prefix using an allowed string s_allowed,
  // by appending s_allowed to a shorter prefix
  for (var j = 0; j < arr.length; j++) {
    // "start" is the position where the current string 
    // would need to be appended
    start = i - arr[j].length;

    if (start >= 0 && isPossible[start]) {
      if (str.substring(start, i) == arr[j]) {
        isPossible[i] = true;
        // we break the loop over j, because we already found a
        // solution to express the current prefix str.substring(0,i)
        break;
      }
    }
  }
}

for (var i = 1; i <= str.length; i++) {
  console.log(str.substring(0, i) + " - " + isPossible[i] + "\n")
}

if (isPossible[str.length]) {
  console.log("yes");
} else {
  console.log("no");
}

要进一步详细说明其工作原理,请考虑一个较小的示例:

  • str = "abcd"
  • arr = ["ab", "a", "cd"]

这里描述的方法测试 str 的所有前缀,按长度递增的顺序:

第0步:空前缀——这被认为是正常的(可以用0个字符串表示)。


第1步:前缀“a”:

我们尝试使用较短的前缀 + 一个允许的字符串来达到此前缀。为此,我们遍历允许的字符串:

  • “ab”不能附加到较短的前缀以获得“a”(因为起始位置需要为 -1)。
  • “a”可以附加到空前缀,这总是可以的——因此我们得到前缀“a”可以(可以使用允许的字符串表示)。

第2步:前缀“ab”:

我们尝试使用较短的前缀 + 一个允许的字符串来达到此前缀。为此,我们遍历允许的字符串:

  • "ab" 可以附加到空前缀,这总是可以的——因此我们得到 prefix "ab" 可以(可以使用允许的字符串表示)。

第3步:前缀“abc”:

我们尝试使用较短的前缀 + 一个允许的字符串来达到此前缀。为此,我们遍历允许的字符串:

  • "ab" -- 要将这个附加到较短的前缀并获取当前的 "abc" 前缀,我们需要从位置 1 开始,但是从该开始位置开始的子字符串是 "bc",因此我们不能附加字符串“ab”以获得前缀“abc”。
  • "a" -- 和上面类似,我们不能附加"a"来获得前缀"abc"。
  • "cd" -- 和上面类似,我们不能附加"cd"来获取前缀"abc"。

我们用尽了所有允许的字符串,因此前缀“abc”不能用允许的字符串表示


第4步:前缀“abcd”(整个字符串):

我们尝试使用较短的前缀 + 一个允许的字符串来达到此前缀。为此,我们遍历允许的字符串:

  • "ab" -- 要将这个附加到一个较短的前缀并获得当前的 "abcd" 前缀,我们需要从位置 2 开始,但是从该位置开始的子字符串是 "cd",因此我们不能附加字符串“ab”以获得前缀“abcd”。
  • "a" -- 和上面类似,我们不能附加"a"来获取前缀"abcd"。
  • “cd”——我们可以将这个允许的字符串附加到“ab”前缀。在上一步中,我们发现“ab”前缀很好(可以用给定的字符串表示),因此从那里附加“cd”很好

因此,我们得到前缀“abcd”(对应于整个字符串)可以使用输入字符串来表示。

【讨论】:

  • @kiranreddy 我在代码中添加了 cmets 并发布了一个示例,详细说明了它是如何工作的。
【解决方案4】:

如果首先匹配所有单词,则可以在开头省略未出现的单词。那么如果匹配在字符串中是按出现顺序排列的,则可以使用递归来查找匹配后的所有匹配:

function eval(str, wordList = ["for","car","keys","forth", "the"]){	//note, added 'the' for testing
	if(!str)return false; //empty string -> false
  
  const words = wordList.map(w=> ({word:w, index: str.indexOf(w)})) //map all words with their occurence index inside the string
  	.filter(w=>w.index !== -1) //get rid of non occuring words alltogether
  	.sort((w1,w2) => w1.index - w2.index); //sort by index of occurence
  
  const check = (arr,ind) => {
  	if(ind>=str.length)return ind === str.length; //end of string reached -> match if exactly at end (false if greater than)
  	let w;    
    while(arr.length){
  	 	[w,...arr] = arr; //destructure: w = next word (index 0), arr is set to the remaining elements
      if(w.index > ind) return false; //gap since last match -> no match
      if(w.index===ind && check(arr,ind + w.word.length)) //if match is at the expected index, check the next indices
      	return true; //word started at the 'current' index and remaining words match as well   	
      //if code arrives here, try further with next word (while)
		}
    return false;
  };
  return check(words,0); //start recursive function with all words at string index 0
}

//test
function test(str, words){
	console.log(str,':', eval(str, words));
}
test("forthcarkeys");
test("forthcarxykeys");
test("forthecar");
test("abcdef",[ "abc", "def", "abcd" ]);

【讨论】:

    【解决方案5】:

    您可以进行扩展尝试并搜索每个单词并使用临时结果集来过滤掉字符串中的单词。

    function check(string, array) {
    
        function fork(i, t) {
            var s = t.slice(), j;
            if (i === possibilities.length) {
                result.push(t.join(''));
                return;
            }
            if (possibilities[i].word.split('').every(function (c, j) { return s[j + possibilities[i].position] !== ''; })) {
                for (j = 0; j < possibilities[i].word.length; j++) {
                    s[j + possibilities[i].position] = ''
                }
            }
            fork(i + 1, s);
            fork(i + 1, t);
        }
    
        var possibilities = array.reduce(function (r, a) {
                var p = string.indexOf(a);
                while (p !== -1) {
                    r.push({ word: a, position: p });
                    p = string.indexOf(a, p + 1);
                }
                return r;
            }, []),
            result = [];
    
        console.log(possibilities);
        fork(0, string.split(''));
        console.log(result);
        return result.some(function (a) { return !a; });
    }
    
    console.log(check("forthcarkeyboardingfor", ["for", "car", "key", "forth", "keyboard", "boarding"]));    // true
    console.log(check("forthxycarkeyboardingfor", ["for", "car", "key", "forth", "keyboard", "boarding"]));  // false
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    上述版本,提前退出。

    function check(string, array) {
    
        function fork(i, t) {
            var s = t.slice(), j;
            if (i === possibilities.length) {
                return !t.join('');
            }
            if (possibilities[i].word.split('').every(function (c, j) { return s[j + possibilities[i].position] !== ''; })) {
                for (j = 0; j < possibilities[i].word.length; j++) {
                    s[j + possibilities[i].position] = '';
                }
            }
            return fork(i + 1, s) || fork(i + 1, t);
        }
    
        var possibilities = array.reduce(function (r, a) {
                var p = string.indexOf(a);
                while (p !== -1) {
                    r.push({ word: a, position: p });
                    p = string.indexOf(a, p + 1);
                }
                return r;
            }, []);
    
        return fork(0, string.split(''));
    }
    
    console.log(check("forthcarkeyboardingfor", ["for", "car", "key", "forth", "keyboard", "boarding"]));    // true
    console.log(check("forthxycarkeyboardingfor", ["for", "car", "key", "forth", "keyboard", "boarding"]));  // false

    【讨论】:

      【解决方案6】:

      这是一个更强大的函数,它可以找到所有可能的元素和用于组合它的方式。如果结果的长度为零,则无法从池中生成原始文本。

      function decompose(orignal, pool) {  // recurisve function to find combinations of text
        var results = [];
        for (var element of pool) {     // for each element in pool
          if (orignal == element) {     // resursive base case, stop when orignal == element
            results.push([element]);    // * add solution
          } else {
            if (orignal.indexOf(element) == 0) {                    // if original text starts with element
              var remaining = orignal.slice(element.length);        // ready remaining text to be scanned
              var subresults = decompose(remaining, pool); // recursive call: findCombinationsOf remaining
              for (subresult of subresults) {
                results.push([element].concat(subresult));          // * add solution
              }
            }
          }
        }
        return results;
      }
      
      console.log(JSON.stringify(decompose("forthcarkeys", ["for","car","keys","forth"])));
      console.log(JSON.stringify(decompose("forthcarkeys", ["for","car","keys","forth", "th"])));
      console.log(JSON.stringify(decompose("nowaydude!", ["for","car","keys","forth", "th"])));

      【讨论】:

        【解决方案7】:

        这是我的解决方案

        详情:

        1. 将给定的字符串"forthcarxykeys"转换成数组,赋值给变量chars
        2. 遍历给定数组["for","car","keys","forth"]
        3. 每次迭代,检查数组中是否存在单词(即"for"
        4. 如果存在,获取每个找到的字母的索引,并在char数组中将其标记为true
        5. 如果chars 中的所有值都为真,则返回真,否则返回假。

        JS:

        // arr = ["for", "car", "keys", "forth"];
        // str = "forthcarxykeys";
        
        function check(arr, str) {
            let chars = str.split('');
            for (let i = 0; i < arr.length; i++) {
                let word = arr[i];
                let index = str.indexOf(word);
                let wordExists = index !== -1;
                if (wordExists) {
                    let endIndex = index + word.length;
                    for (index; index < endIndex; index++) {
                        chars[index] = true;
                    }
                }
            }
            return chars.every(i => i === true);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-02-24
          • 1970-01-01
          • 2021-12-14
          • 1970-01-01
          • 2014-09-24
          • 2017-03-17
          • 2021-06-10
          相关资源
          最近更新 更多