我之前已经问过这个问题(the first link to my question),但无法获得问题的完整解决方案。 编写一个算法来检查给定的字符串s是否可以由另外两个字符串part1和part2组成。
限制是part1和part2中的字符与s中的字符顺序相同。
示例:
' codewars'是一个合并来自' cdw'并且' oears':
c o d e w a r s = codewars
part1: c d w = cdw
part2: o e a r s = oears
无论我如何挑战我的解决方案,我都不会轻易通过所有检查。我得到相同的结果。请帮助你做正确的事。谢谢你
function isMerge(s, part1, part2) {
if(part1.length + part2.length != s.length)
{
return false;
}
if (s.length == '')
{
return true;
}
for(var i = 0, len = s.length; i < len; i++)
{
for (var j=0, jen = part1.length; j<jen; j++)
{
if(s[0] === part1[0])
{
return true;
}
}
for(var p = 0, pen = part2.length; p < pen; p++)
{
if(s[0] === part2[0])
{
return true;
}
}
}
return false;
}
答案 0 :(得分:3)
function isMerge(s, part1, part2) {
// length comparison is not required
// this is a roundabout way of saying A === B
// more comments on this below
if(part1.length + part2.length != s.length)
{
return false;
}
if (s.length == '')
{
return true;
}
for(var i = 0, len = s.length; i < len; i++)
{
// you don't have to loop over part1 or part2
for (var j=0, jen = part1.length; j<jen; j++)
{
// s[0] and part1[0] will always be the same char
// i'm certain you intended s[i] and part1[j]
if(s[0i] === part1[0j])
{
// if you `return` here, you will return lots of false positives
// the condition above only checks for two matching letters,
// you have to finish looping thru `s` to know we checked all letters
return true;
}
}
// this loop is broken the same way as the one above
for(var p = 0, pen = part2.length; p <l pen; p++)
{
if(s[0] === part2[0])
{
return true;
}
}
}
// this is also wrong too.
// what we will do is, if at anytime there is a non-match in the loop,
// it means we can `return false` early and stop looping
// otherwise if the loop finished without finding any non-matches,
// then we will return true
return false;
}
如果我们真的有兴趣比较字符串的内容,那么 length
不是比较字符串的好方法。当然,在某些情况下,这是一个false
值的捷径,但这是一个不成熟的优化。
从描述您意图的 minimal 程序开始。如果您稍后对代码进行分析并了解可以在您的函数中进行改进,然后您可以编写此类检查,并确保发表评论为何添加了length
比较
但在你需要之前,请将其删除。只会让你更多地思考/担心,这会让你更加努力。
我并不是说残酷,但我们只是取消了大部分功能。我们将挽救我们能够并从那里开展工作
function isMerge(s, part1, part2) {
for (let i = 0, len = s.length; i < len; i++) {
if (s[i] ...)
return false
}
return true;
}
因此,在该循环中,我们希望搜索s[i]
与part1
或part2
中的第一个字母匹配的位置。但并不总是第一个字母,对吗?一旦我们匹配第1部分中的字母,我们就无法重复使用该字母。
我将添加两个变量,用于跟踪part1
和part2
中当前未选中的位置。当任一部分匹配时,我们将提升相应变量的位置。
function isMerge(s, part1, part2) {
// i keeps track of position in s
// p1 keeps track of position in part1
// p2 keeps track of position in part2
for (let i = 0, len = s.length, p1 = 0, p2 = 0; i < len; i++) {
// check current letter for match in part1
if (s[i] === part1[p1]) {
p1++ // increment p1 so we don't reuse this char
continue // move on to next letter in s
}
// check current letter for match in part2
else if (s[i] === part2[p2]) {
p2++ // increment p1 so we don't reuse this char
continue // move on to next letter in s
}
// current letter didn't match part1 or part2 !
else {
return false
}
}
// we got thru the loop without resulting in false
// so it must be true that s isMerge of part1 and part2
return true
}
// example 1
{
let str = 'codewars'
let part1 = 'cdw'
let part2 = 'oears'
console.log(isMerge(str, part1, part2)) // true
}
// example 2
{
let str = 'codewars'
let part1 = 'cdb'
let part2 = 'oears'
console.log(isMerge(str, part1, part2)) // false
}
但实际上,我觉得这个解决方案难以推理。如果您剖析该函数的范围,您将看到我们需要跟踪的许多变量:s
,part1
,part2
,p1
,{ {1}},p2
,i
。更不用说len
,i
和p1
需要在循环运行时进行更改,因此您必须确保完全正确。这需要管理很多。
我们在那里有一些评论来帮助读者理解我们的意图,但代码应该表达我们的意图,而不是反过来。事实上,我认为评论通常会使代码更难阅读,因为代码的方式更加残缺。
有一种更好的方法......
这是一个基本的递归过程,会检查p2
的首字母对s
或x
的第一个字母。如果两者匹配,则使用匹配字符串中的剩余字母进行递归。否则返回false。
我们使用其他几个小程序来帮助我们更有效地描述我们的计划。您会看到此代码中没有任何注释,并且它仍然具有可读性 - 这次代码执行解释...
y
显然,您已经找到了一些条件,根据这些条件,我的最后一段代码无法满足您在原始帖子中未提及的某些条件。
我在代码大战上找到了测验,而这里的代码最失败的地方
const shead = s => s.substr(0,1)
const stail = s => s.substr(1)
const isEmpty = s => s === ''
const firstCharEqual = (x,y) => shead(x) === shead(y)
const isMerge = (s,x,y) => {
if (isEmpty(s))
return isEmpty(x) && isEmpty(y)
else if (firstCharEqual(s, x) && firstCharEqual(s, y))
return isMerge(stail(s), stail(x), y) || isMerge(stail(s), x, stail(y))
else if (firstCharEqual(s, x))
return isMerge(stail(s), stail(x), y)
else if (firstCharEqual(s, y))
return isMerge(stail(s), x, stail(y))
else
return false
}
// example 1; correct inputs; should be true
{
let str = 'codewars'
let part1 = 'cdw'
let part2 = 'oears'
console.log(isMerge(str, part1, part2)) // true
}
// example 2; mismatched input; should be false
{
let str = 'codewars'
let part1 = 'cdb'
let part2 = 'oears'
console.log(isMerge(str, part1, part2)) // false
}
// example 3; extra input; should be false (apparently)
{
let str = 'codewars'
let part1 = 'cdw_'
let part2 = 'oears'
console.log(isMerge(str, part1, part2)) // false
}
// example 3; extra input; should be false (apparently)
{
let str = 'Bananas from Bahamas'
let part1 = 'Bahas'
let part2 = 'Bananas from am'
console.log(isMerge(str, part1, part2)) // true
}
我已经编辑了上面的代码......
let s = 'Bananas from Bahamas',
let x = 'Bahas'
let y = 'Bananas from am'
isMerge(s,x,y); // should be true
...到......
if (isEmpty(s) && isEmpty(x) && isEmpty(y))
return true
这将确保if (isEmpty(s))
return isEmpty(x) && isEmpty(y)
else if (firstCharEqual(s, x) && firstCharEqual(s, y))
return isMerge(stail(s), stail(x), y) || isMerge(stail(s), x, stail(y))
和part1
在消耗part2
的同时被完全消耗(清空)。
更重要的是,它将确保如果s
和part1
同时匹配,我们会对递归进行分叉,并检查fork的任一分支是否导致part2
编辑后的代码通过了所有测试
答案 1 :(得分:0)
尝试类似:
function mergeCheck(s, p1, p2, i, j, k) {
if (i == s.length) {
return true;
} else {
if (s[i] == p1[j]) {
j++;
} else if (s[i] == p2[k]) {
k++;
} else {
return false;
}
i++;
return mergeCheck(s, p1, p2, i, j, k);
}
}
function isMerge(s, p1, p2) {
if (s.length == (p1.length + p2.length)) {
return mergeCheck(s, p1, p2, 0, 0, 0);
}
else {
return false;
}
}
console.log(isMerge("codewars", "cdw", "oears"))
console.log(isMerge("codewars", "cw", "oears"))
console.log(isMerge("codewars", "cdwx", "oears"))
从s
字符串的开头开始,将有问题的字母与p1
或p2
的顺序字母进行比较。如果在其中任何一个中找到匹配,它会向前移动并检查后续字母,直到找到不匹配或到达s
的末尾
答案 2 :(得分:-1)
function isMerge(s, part1, part2) {
if (part1.length === 0) {
return (s == part2);
}
if (part2.length === 0) {
return (s == part1);
}
if (s.length === 0) {
return false;
} /*because if you are still here, part 1 and part 2 are not empty*/
/*handle empty strings first both as "base case" and to not have to worry about expressions like s[0]*/
return ((s[0] == part1[0]) && isMerge(s.substr(1), part1.substr(1), part2)) || ((s[0] == part2[0]) && isMerge(s.substr(1), part1, part2.substr(1)));
}
// example 1
{
let str = 'codewars'
let part1 = 'cdw'
let part2 = 'oears'
console.log(isMerge(str, part1, part2)) // true
}
// example 2
{
let str = 'codewars'
let part1 = 'cdb'
let part2 = 'oears'
console.log(isMerge(str, part1, part2)) // false
}
答案 3 :(得分:-1)
这是一种非递归方法。
function checkIt (str, str1, str2){
if(str.length !== str1.length + str2.length){
return false;
}
var str1_index = -1
var str2_index = -1;
var curr_index1, curr_index2;
for(var i=0; i<str.length; i++){
curr_index1 = str1.indexOf(str[i]);
curr_index2 = str2.indexOf(str[i]);
if(curr_index1 == -1 && curr_index2 == -1){
return false;
}
if(curr_index1 > str1_index){
str1_index = curr_index1;
}
else if(curr_index1 !== -1 && curr_index1 < str1_index) {
return false;
}
if(curr_index2 > str2_index){
str2_index = curr_index2;
}
else if(curr_index2 !== -1 && curr_index2 < str2_index) {
return false;
}
}
return true;
}
console.log(checkIt('codewars', 'cdw', 'oears')); // true
console.log(checkIt('codewars', 'cdw', 'ears')); // false
console.log(checkIt('codewars', 'cwd', 'oears')); // false
console.log(checkIt('codewars', 'cdw', 'oeasr')); // false