Во-первых, когда вы собираете индексы, вам не нужно вести подсчет, так как длина конечного массива будет равна счетчику: каждый элемент массива будет соответствовать совпадению и будет списком соответствующих индексов..
Вы можете сделать возвращаемое значение функции, для которой совпадает массив (частичный), и расширить каждый массив дополнительным индексом (для случая, когда этот символ берется в совпадении) при возврате:
function count(str, pattern, strInd = str.length, patternInd = pattern.length) {
if (patternInd === 0) {
return [[]]; // A match. Provide an array with an empty array for that match
}
if (strInd === 0) {
return []; // No match. Provide empty array.
}
if (str.charAt(strInd - 1) === pattern.charAt(patternInd - 1)) {
const matches1 = count(str, pattern, strInd - 1, patternInd - 1);
const matches2 = count(str, pattern, strInd - 1, patternInd);
// For the first case, add the current string index to the partial matches:
return [...matches1.map(indices => [...indices, strInd-1]), ...matches2];
} else {
return count(str, pattern, strInd - 1, patternInd);
}
}
console.log(count("abab", "ab"));
Обратите внимание, что индексы начинаются с нуля, поэтому они на единицу меньше ожидаемого результата.Кроме того, индексы располагаются слева направо, что представляется более полезным.
Общая идея
Как правило, лучше избегать глобальных переменных и максимально использовать возвращаемое значение рекурсивной функции.,То, что вы получите от него, будет касаться только «поддерева», которое посещал рекурсивный вызов.В приведенном выше случае это поддерево является более короткой версией как строки, так и шаблона.То, что возвращает рекурсивная функция, должно соответствовать переданным параметрам (это должно быть «решение» для этих параметров).
Возвращаемые значения могут быть сложными: когда вам нужно вернуть больше, чем «одно», выможно просто поместить разные части в объект или массив и вернуть его.Затем вызывающий абонент может снова распаковать его в отдельные части.Например, если бы мы также вернули счет в приведенном выше коде, мы бы сделали:
function count(str, pattern, strInd = str.length, patternInd = pattern.length) {
if (patternInd === 0) {
return { count: 1, matches: [[]] };
}
if (strInd === 0) {
return { count: 0, matches: [] };
}
if (str.charAt(strInd - 1) === pattern.charAt(patternInd - 1)) {
const { count: count1, matches: matches1 } =
count(str, pattern, strInd - 1, patternInd - 1);
const { count: count2, matches: matches2 } =
count(str, pattern, strInd - 1, patternInd);
// For the first case, add the current string index to the partial matches:
return {
count: count1 + count2,
matches: [...matches1.map(indices => [...indices, strInd-1]), ...matches2]
};
} else {
return count(str, pattern, strInd - 1, patternInd);
}
}
Всегда должно быть возможно решить проблему рекурсии, подобную этой, но в случае, если она окажется слишком сложнойв качестве альтернативы вы можете передать дополнительную объектную переменную (или массив), к которой рекурсивный вызов добавит свои результаты: он подобен коллектору, который постепенно увеличивается до конечного решения.Недостатком является то, что лучше не допускать, чтобы функции имели побочные эффекты, и, во-вторых, вызывающая функция должна уже подготовить пустой объект и передать его для получения результатов.
Наконец, не делайте 'не должно быть соблазна использовать глобальные переменные для такого сбора данных.Было бы немного лучше, если бы такие «глобальные» переменные были фактически локальными переменными в замыкании.Но все же, другой вариант должен быть предпочтительным.