本文介绍了Javascript Codewars挑战赛(isMerge)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 我之前曾问过这个问题( 解决方案 代码审查 function isMerge(s,part1,part2){ //不需要长度比较 //这是一种回旋方式,表示A === B // for(var i = 0,len = s.length ;我< len; i ++) { //您不必遍历part1或part2 // s [0]和part1 [0]将始终是相同的char // //我确定您打算使用s [i]和part1 [j] if(s [ i] === part1 [ j]) { //如果您在此处返回,则将返回很多误报 //以上条件仅检查两个匹配的字母, //您必须完成通过s的循环才能知道我们检查了所有字母 } } //此循环的破坏方式与上方的循环相同 for(var p = 0,pen = part2.length; p<l pen; p ++) } //这也是错误的。 //我们要做的是,如果循环中任何时候都不匹配,则 //这意味着我们可以`早返回false`并停止循环 //否则如果循环结束而未找到任何不匹配项,则 // //我们将返回true } length 不是比较字符串的好方法字符串。当然,在某些情况下,它是 false 值的捷径,但这是过早的优化。 开始使用 minimum 程序来描述您的意图。如果稍后对代码进行概要分析,并了解可以在函数中进行改进,则可以然后进行这种检查,并确保对 length 添加了比较。 但是在您需要之前,请将其保留。 定影液上限 $只会让您更难受。 b $ b 我并不是说要残酷,但我们只是取消了大部分功能。我们将挽救我们可以做的事情并从那里开始 function isMerge(s,part1,part2){ for(令i = 0,len = s.length; i< len; i ++){ if(s [i] ...)返回false } 返回true ; } 因此,在该循环中,我们要搜索 s [ i] 与 part1 或 part2 中的第一个字母匹配。但是不是总是第一个字母,对吗?一旦我们在part1中匹配了一个字母,就无法重复使用该字母。 我将添加两个变量,以跟踪当前在 part1 和 part2 。 函数isMerge(s,part1,part2){// i跟踪s中的位置// p1跟踪part1的位置// // p2跟踪part2的位置for(let i = 0,len = s.length,p1 = 0,p2 = 0; i< len; i ++){//如果(s [i] === part1 [p1]){p1 ++ //递增p1,则检查当前字母是否匹配此字符继续// //移至s中的下一个字母} //在part2中检查当前字母是否匹配,否则是否(s [i] === part2 [p2]){p2 ++ //递增p1,因此我们不重复使用char继续// //移至s中的下一个字母} //当前字母与part1或part2不匹配! else {return false}} //我们经过了循环而没有导致false //因此,一定是true part1和part2的s isMerge返回true} //示例1 {let str ='codewars'let part1 ='cdw 'let part2 ='oears'console.log(isMerge(str,part1,part2))// true} //示例2 {let str ='codewars'let part1 ='cdb'let part2 ='ears'console.log (isMerge(str,part1,part2))// false} 但实际上,我发现这种解决方案很难推理。如果您对该函数的范围进行了剖析,您会发现许多必须牢记的变量: s , part1 , part2 , p1 , p2 , i , len 。更不用说 i , p1 和 p2 随着循环的运行而变化,因此您必须确保正确理解所有这些内容。 我们在其中有一些注释可以帮助读者理解我们的意图,但是代码应该表达我们的意图,而不是相反。实际上,我认为注释常常使代码更难阅读,因为代码方式更加混乱。 … 有更好的方式 更好的方法 嘿!我们已经找到了更好的方法。 这是一个基本的递归过程,可以将 s 的首字母与 x 或 y 。如果两者均匹配,则使用匹配字符串中的其余字母递归。否则,它将返回false。 我们使用其他几个小程序来帮助我们更有效地描述程序。您会发现此代码中没有注释,并且仍保持可读性–这次 code 进行了解释… 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)=> {如果(isEmpty(s))返回isEmpty(x)&& isEmpty(y)否则,如果(firstCharEqual(s,x)&& firstCharEqual(s,y))返回isMerge(stail(s),stail(x),y)|| isMerge(stail(s),x,stail(y))else if(firstCharEqual(s,x))return isMerge(stail,stail(x),y)else if(firstCharEqual(s,y))return isMerge(stail(s),x,stail(y))else return false} //示例1;正确输入;应该为真{let str ='codewars'let part1 ='cdw'let part2 ='oears console.log(isMerge(str,part1,part2))// true} //示例2;输入不匹配;应该为假{let str ='codewars'let part1 ='cdb'let part2 ='oears console.log(isMerge(str,part1,part2))// false} //示例3;额外的投入;应该是假的(显然){let str ='codewars'let part1 ='cdw_'let part2 ='oears console.log(isMerge(str,part1,part2))// false} //示例3;额外的投入;应该是假的(很明显){let str ='来自巴哈马的香蕉'let part1 ='巴哈斯'let part2 ='来自美国的香蕉'console.log(isMerge(str,part1,part2))// true} 失败 显然,您发现某些情况下,我的最后一部分代码无法满足您在原始帖子中未提及的某些条件。 我在代码战中找到了测验,这是代码失败最多的地方 let s ='来自巴哈马的香蕉' , let x ='Bahas' let y ='Bannas from am' isMerge(s,x,y); //应该是正确的 我已经从… $ b编辑了上面的代码 $ b if(isEmpty(s&& isEmpty(x)&& isEmpty(y))返回true …到… 如果(isEmpty(s))返回isEmpty(x)& isEmpty(y)否则,如果(firstCharEqual(s,x)&& firstCharEqual(s,y))返回isMerge(stail(s),stail(x),y)|| isMerge(stail(s),x,stail(y)) 这将确保 part1 和 part2 已完全消耗(清空),同时 s 更重要的是,它将确保 part1 和 part2 同时匹配,我们分叉递归并检查分叉的任一分支是否产生 true 修改后的代码通过了所有测试 I have asked this question before (the first link to my question) but couldn't get the complete solution for the question.Write an algorithm to check if a given string, s, can be formed from two other strings, part1 and part2.The restriction is that the characters in part1 and part2 are in the same order as in s.Example:'codewars' is a merge from 'cdw' and 'oears': c o d e w a r s = codewars part1: c d w = cdw part2: o e a r s = oearsI am not finding it easy to pass all the checks no matter how i challenge my solution i get the same results.Please need help in getting it right.Thank you 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; } 解决方案 code reviewfunction isMerge(s, part1, part2) { // length comparison is not required // this is a roundabout way of saying A === B // more comments on this below for(var i = 0, len = s.length; i < len; i++) { // you don't have to loop over part1 or part2 // s[0] and part1[0] will always be the same char // i'm certain you intended s[i] and part1[j] if(s[i] === part1[j]) { // 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 } } // this loop is broken the same way as the one above } // 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 }length is not a good way to compare strings if we're actually interested in comparing the contents of the strings. Sure, it's a short-cut to a false value in some cases, but it's a premature optimization.Start with a minimal program that describes your intent. If you profile the code later and learn that improvements could be made in your function, then you can write this sort of check, and be sure to leave a comment why the length comparison was added.But until you need it, leave it out. It's only making this harder on you by giving you more to think/worry about.fixer upperI don't mean to be brutal, but we just scrapped most of that function. We will salvage what we can and work from therefunction isMerge(s, part1, part2) { for (let i = 0, len = s.length; i < len; i++) { if (s[i] ...) return false } return true;}So in that loop we want to search s[i] where it matches the first letter in part1 or part2. But not always the first letter, right? Once we match a letter in part1, we can't reuse that one.I'm going to add two variables which keeps track of which position is currently unchecked in part1 and part2. We will advance the position of the respective variable when either part matches.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}But really, I find that solution to be hard to reason about. If you dissect the scope of that function, you'll see many variables we have to keep track of in our heads: s, part1, part2, p1, p2, i, len. Not to mention i, p1, and p2 need to change as the loop runs, so you have to make sure you get all of that right. It's a lot to manage.We have some comments in there to help the reader understand our intent, but the code should be expressing our intent and not the other way around. In fact, I think comments often make it harder to read code because there's just more cruft in the way of the code.There's a better way …a better wayHey look ! We've already arrived at a better way. That was quick.This is a basic recursive procedure which checks first letter of s against first letter of x or y. If either is a match, it recurses using the remaining letters in the matching strings. Otherwise it returns false.We use several other small procedures which serve to help us describe our program more effectively. You'll see that there are no comments in this code and it remains quite readable – this time the code does the explaining …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}failureApparently you've found some conditions under which my last bit of code fails to meet certain criteria that you did not mention in your original post.I found the quiz on codewars and here's where the code failed the mostlet s = 'Bananas from Bahamas',let x = 'Bahas'let y = 'Bananas from am'isMerge(s,x,y); // should be trueI've edited the above code from …if (isEmpty(s) && isEmpty(x) && isEmpty(y)) return true… to …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))This will ensures that part1 and part2 have been completely consumed (emptied) at the same time s is consumed.And more importantly, it will ensure that if part1 and part2 match simultaneously, we fork the recursion and check that either branch of the fork results in a trueThe edited code passes all tests 这篇关于Javascript Codewars挑战赛(isMerge)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 10-12 01:38