Here is another challenge from Coderbyte. I found this one challenging, although not quite as much as the previous two I've posted. Based on the feedback I received on my earlier posts, I structured this solution as a function. It is probably better than my previous solutions but still could be improved.
In particular, I am wondering if there is a way to condense my while
loops, perhaps by determining the a
and b
indices at the same time or maybe by building a helper function? It seems like there is redundancy there. Resetting the index
variable strikes me as particular clumsy or inelegant, but it had to happen somehow. I'm also not to happy with splitting the string and then joining the modified array to deal with the spaces. Any feedback on these issues or other suggestions to improve the code would be greatly appreciated.
Here's the challenge, slightly modified:
Take a
str
parameter and returntrue
if there are any occurrences of characters "a" and "b" separated by exactly 3 places (i.e. "lane borrowed" would result intrue
because there is exactly three characters between a and b). Otherwise return the stringfalse
.
(While I was posting this, I realized I had not accounted for spaces. My interpretation of the instructions is that spaces do not count as characters. I have updated my code accordingly.)
var str = prompt("Please enter a string: ").split("");
function test(str){
var index = 0;
var arrayA = [];
var arrayB = [];
while (index >= 0){ //removes spaces
index = str.indexOf(" ");
if (index >= 0) {
str.splice(index, 1);
}
}
str=str.join("");
index = 0;
while(str.indexOf("a",index) != -1){ //Identifies indices of "a"
arrayA.push(str.indexOf("a",index));
index = str.indexOf("a", index)+1;
}
index=0;
while(str.indexOf("b",index) != -1){//Identifies indicies of "b"
arrayB.push(str.indexOf("b",index));
index = str.indexOf("b", index)+1;
}
for(var i=0; i<arrayA.length; i++){//determines if any a's and b's are 3 characters apart
for(var j=0; j<arrayB.length; j++){
if (Math.abs(arrayA[i]-arrayB[j]) === 3){
return true;
}
}
}
return false;
}
console.log(test(str));
Here's a revised version:
function ABCheck(str) {
str = str.split("");
for (var i = 0; i<str.length; i++){
if (str[i] === " "){
str.splice(i,1);
console.log(str);
}
}
for (var i = 0; i< str.length; i++){
if (str[i] === "a" && (str[i-3] === "b" || str[i+3] === "b")){
return true;
}
}
return false;
}
3 Answers 3
I would recommend using a regular expression. Regex is designed for solving pattern matching and string manipulation problems. Although it can look esoteric and terse it is well worth the effort to learn since it is very powerful and fairly ubiquitous. It is very likely your programming language/shell/editor of choice supports a flavor of regex.
var str = prompt("Please enter a string: ");
function test(str){
return /a\w{3}b/.test(str) || /b\w{3}a/.test(str);
}
console.log(test(str));
-
\$\begingroup\$ Correct me if I'm wrong but I think that will fail on
b123a
? \$\endgroup\$ChrisWue– ChrisWue2013年10月16日 20:31:30 +00:00Commented Oct 16, 2013 at 20:31 -
\$\begingroup\$ Common misconception. The character class \w includes both A..Z, a..z, 0..9, and the _ underscore character. \$\endgroup\$Scott Puleo– Scott Puleo2013年10月16日 20:36:39 +00:00Commented Oct 16, 2013 at 20:36
-
\$\begingroup\$ I didn't mean the character class. You check for an
a
follow by the characters followed by ab
. \$\endgroup\$ChrisWue– ChrisWue2013年10月16日 20:44:05 +00:00Commented Oct 16, 2013 at 20:44 -
\$\begingroup\$ Apologies, misread your question. Corrected my response. \$\endgroup\$Scott Puleo– Scott Puleo2013年10月16日 20:49:06 +00:00Commented Oct 16, 2013 at 20:49
-
\$\begingroup\$ Thanks, regex seems to be the correct approach for a number of the challenges I have attempted. I am reading up on it. \$\endgroup\$Nathan– Nathan2013年10月21日 04:03:08 +00:00Commented Oct 21, 2013 at 4:03
I would also use a regular expression match, similar to @ScottPuleo's approach. Regular expressions are just so perfectly suited for this kind of problem!
The difference is that I would construct the regular expression to cover both cases (either a
followed by b
, or b
followed by a
). I've interpreted "three places" in your problem to mean any three characters other than newline characters. (That is, a
and b
are also acceptable as intervening characters.)
var str = prompt("Please enter a string: ");
console.log(/a...b|b...a/.test(str));
I didn't bother with putting the code in a function this time, since it's just one line with no side effects.
- Your trimming of whitespaces is not the most efficient - you only remove one at a time.
replace
with a regular expression should do the trick:str = str.replace(/\s+/g, "");
If you rephrase the problem slightly you will find that a more efficient solution comes to mind: Any occurrence of
a
andb
separated by exactly three characters means "Is there ana
three characters on either side of anyb
or ab
three characters on either side of ana
. The algorithm is:- For every letter in
str
:- if current letter is an
a
check for ab
3 characters to left and to the right - else if current letter is an
b
check for aa
3 characters to left and to the right
- if current letter is an
This loops over the string once and you don't need to collect all the indices.
charAt
is your friend when implementing this.- For every letter in
-
\$\begingroup\$ I added a revised solution using some of your suggestions. I am using the loop to splice interior white space. I don't think trim will do that but will remember it for the future. I have used in java but not javascript. Thanks. \$\endgroup\$Nathan– Nathan2013年10月21日 04:04:50 +00:00Commented Oct 21, 2013 at 4:04
-
\$\begingroup\$ @Nathan: True, I misread the code. \$\endgroup\$ChrisWue– ChrisWue2013年10月21日 07:13:43 +00:00Commented Oct 21, 2013 at 7:13
Explore related questions
See similar questions with these tags.