我正在尝试找出检查是否可以通过组合数组中的其他字符串来创建特定字符串的最佳方法。其他字符串可以是任意长度,包括一个字符。此外,其他字符串中的字符可以重新排序。
因此,如果我们正在寻找“闪避”这个词并且我们的字符串数组是['god','house','d','e','cat','c','r','jump']
,那么我们就会有匹配,因为我们可以将'god','d'和'e中的字母组合在一起'创造'躲闪'。
如果数组包含“dot”而不是“d”,我们就不会有匹配,因为我们必须使用我们重新组合的每个单词中的所有字符(我们必须使用'o'和' t'以及。)
我还想知道哪些单词用于创建指定的单词,所以如果匹配,我希望函数返回重组的单词的数组索引以创建指定的单词。对于上面的“闪避”示例,它将返回[0,2,3]。
答案 0 :(得分:3)
我写了一个最差情况O(2^n)
的解决方案,但在大多数情况下它会表现得很好。我开始使用一个函数,将每个字符串映射到一个对象,该对象计算字符串中所有不同的字母。例如:
map("dodge") --> { "d": 2, "e": 1, "g": 1, "o": 1, size: 5 }
如您所见,它还会在结果中存储大小。这是实施:
function map(str) {
var obj = { size: str.length };
for(var i=0; i<str.length; i++) {
var ch = str.charAt(i);
obj[ch] = (ch in obj) ? obj[ch]+1 : 1;
}
return obj;
}
然后我写了一个“减去”两个映射对象的函数。例如:
subtract(map("ab"), map("a")) --> { "b": 1, size: 1 }
subtract(map("dodge"), map("god")) --> { "d": 1, "e": 1, size: 1 }
subtract(map("abc"), map("abc")) --> { size: 0 }
subtract(map("a"), map("b")) --> null
正如您在上一个示例中所看到的,如果无法进行减法,则函数将返回null
。这是subtract
的实现:
function subtract(a, b) {
var result = { size: 0 };
for(var i=97; i<123; i++) { // from a to z (ASCII)
var ch = String.fromCharCode(i);
var diff = (a[ch] || 0) - (b[ch] || 0);
if(diff < 0)
return null;
if(diff > 0) {
result[ch] = diff;
result.size += diff;
}
}
return result;
}
最后一步是编写一个方法findCombination(word, dict)
,如果找到任何组合,则返回一个组合,否则返回null。例子:
var dict = ['god','house','d','e','cat','c','r','jump'];
findCombination("dodge", dict) --> [0, 2, 3]
findCombination("housecat", dict) --> [1, 4]
findCombination("hose", dict) --> null
findCombination("xyz", dict) --> null
我使用带有回溯的递归方法,我尝试从给定键中“减去”单词,直到结果为“空”:
var findCombination = function(word, dict)
{
var solution = [];
var mappedDict = [];
for(var i=0; i<dict.length; i++)
mappedDict[i] = map(dict[i]);
var recursiveFind = function(key, i)
{
if(i == mappedDict.length)
return false;
var result = subtract(key, mappedDict[i])
if(result == null)
return recursiveFind(key, i+1);
solution.push(i);
if(result.size == 0 || recursiveFind(result, i+1))
return true;
solution.pop();
return recursiveFind(key, i+1);
};
if(recursiveFind(map(word), 0))
return solution;
return null;
};
您可以(而且应该)通过仅初始化mappedDict
变量一次来优化代码,而不是每次调用findCombination()
。
答案 1 :(得分:1)
算法:
JavaScript实现:
// Assume: target=target string, words_array=array of strings
function groupByLetters(map, text) {
for (var x=0; x < text.length; x++) {
var ch = text.charAt(x);
var n = map[ch] || 0;
map[ch] = n + 1;
}
}
// Split the target string into letters
var target_map = {};
groupByLetters(target_map, target);
// Create permutation slots
var slots = [];
for (var x=0; x < words_array.length; x++) {
// Now in order to optimize speed, store the length of each string in the slot
// Negative = not selected, positive = selected
slots.push(-words_array[x].length);
}
// Loop through all permutations
while(true) {
var carry = true;
var plength = 0;
for (var x=0; x < slots.length; x++) {
var slen = slots[x];
if (carry) {
if (slen < 0) { // Bit 0
carry = false;
slots[x] = -slen; // 0->1, no carry
} else {
slots[x] = -slen; // 1->0, continue to carry
}
}
if (slots[x] > 0) plength += slots[x];
}
if (carry) { // We have exhausted the permutations
return null;
}
// Now plength = total number of letters in selected permutation
if (plength !== target.length) continue; // Not the same number of letters, skip
// Build map of all letters in selected permutation
var pmap = {};
var permutation = [];
for (var x=0; x < slots.length; x++) {
if (slots[x] > 0) {
groupByLetters(pmap, words_array[x]);
permutation.push(words_array[x]);
}
}
// Check if the map is the same as the target map
var match = true;
for (var letter in target_map) {
if (!target_map.hasOwnProperty(letter)) continue;
if (target_map[letter] !== pmap[letter]) {
match = false;
break;
}
}
if (match) return permutation; // Success!
}
警告:我有不尝试运行此功能。如果我在这里或那里打错了,请告诉我。
答案 2 :(得分:1)
修改强>
这应该比天真的解决方案快得多,因为所有的工作都是通过内置的indexOf搜索来完成的,这种搜索非常快,而且它可以在第一次不匹配时退出。
function match(array, word){
var char_array = word.split(''),
char, index;
array = array.join('').split('');
while(char_array.length > 0){
char = char_array.shift();
if ((index = array.indexOf(char)) > -1)
array.splice(index, 1);
else
return false;
}
return true;
}
这是天真的解决方案:
function match(array, word){
var char_array = word.split(''),
array_elem;
//loop over array
for(var i=0, l=array.length; i < l; i++){
array_elem = array[i].split('');
//loop over the remaining chars in the word and
//cross-check with the current array element
for (var j=0,len = char_array.length,index; j < len; j++)
if ((index = array_elem.indexOf(char_array[j])) > -1){
//char matched, remove it from both arrays
char_array.splice(j, 1);
array_elem.splice(index, 1);
}
}
if(char_array.length < 1) return true
else return false
}
如果这是一个问题,应该进行优化以使其更快。
答案 3 :(得分:0)
var wordInDict = function ( word, dict ) {
var dict = dict.slice(0), // copy dict to not mutate original
wl = word.length,
dl = dict.length,
i, j, diw,
wCount = 0;
for (i = 0; i < wl; i++) {
for (j = 0; j < dl; j++) {
diw = dict[j].indexOf(word[i]); // is letter of word in dict word
if (diw > -1) {
wCount++;
// remove used character from dictionary
if (diw == dict[j].length-1) {
dict[j] = dict[j].slice(0, diw);
} else if (diw == 0) {
dict[j] = dict[j].slice(1);
} else {
dict[j] = dict[j].slice(0,diw) +
dict[j].slice(diw+1,dict[j].length-1);
}
// letter found, so move to next letter in target word
break;
}
}
}
return wCount == wl;
};
var tW = 'dodge';
var tD = ['god','house','d','e','cat','c','r','jump'];
var tE = ['got','house','d','e','cat','c','r','jump'];
console.log(wordInDict(tW, tD)); // true
console.log(wordInDict(tW, tE)); // false
答案 4 :(得分:0)
我刚刚意识到这个问题等同于the subset product problem,因此NP-Complete。
让s(x)
成为一个size方法,它通过将字符映射到素数然后返回这些素数的乘积来为每个字符串返回一个整数:
a --> 2, b --> 3, c --> 5, d --> 7, e --> 11, etc.
然后我们得到
s("abc") = 2 * 3 * 5 = 30 = 5 * 2 * 3 = s("cab")
鉴于字典A
,我们现在正在寻找一个子集A'⊂ A
,以便产品
p = ∏ { s(a) : a ∈ A' }
对于给定的s(key)
,等于key
。
答案 5 :(得分:0)
我可能想到的两种解决方案
使用 Array.sort() 对给定的字符串进行排序,如果排序的数组匹配,则繁荣字符串是字谜。
写了一段原生代码
函数置换(输入1,输入2){
if(typeof input1 === 'string' && typeof input2 === 'string' ) {
const array_1 = input1.split('')
const array_2 = input2.split('')
让 count2 = 0;
让计数 1 = 0
让 is_permutable = false
if(array_1.length === array_2.length) {
for(let j =0;j } 函数检查重复(字,数组_1){
让计数 = 0;
让我=0;
// array_1[j] = t 和 t e s t
while(i if(count1 === count2) {
is_permutable = true;
} else {
is_permutable = false;
}
}
if(is_permutable) {
return true;
} else {
return false;
}
} else {
return false
}
}else {
return false;
}
P.S 学习编码,因此感谢任何有关内存/变量管理的建议。