The task:
Given two strings A and B, return whether or not A can be shifted some number of times to get B.
For example, if A is abcde and B is cdeab, return true. If A is abc and B is acb, return false.
Solution 1:
const haveSameLength = (a, b) => a.length === b.length;
const isSame = (a, b) => a === b;
const isFullyShifted = a => a === 0;
const shiftStringBy = i => a => `${a.substring(i)}${a.substring(0, i)}`;
const isSameAfterShifting = (strA, strB, items) => {
if (strA.length === 0 || strB.length ===0) { return false }
if (!haveSameLength(strA, strB)) { return false }
if (isSame(strA, strB)) { return true }
if (isFullyShifted(items)) { return false }
return isSameAfterShifting(strA, shiftStringBy(1)(strB), --items)
}
const str1 = 'abcde';
const str2 = 'cdeab';
console.log(isSameAfterShifting(str1, str2, str2.length));
Solution 2
const isSameAfterShifting2 = (strA, strB) => {
if (strA.length === 0 || strB.length ===0) { return false }
if (!haveSameLength(strA, strB)) { return false }
const arrB = strB.split('');
const firstLetterA = strA.substring(0, 1);
let shiftIndex = arrB.indexOf(firstLetterA);
if (shiftIndex === -1) { return false }
while (shiftIndex < arrB.length) {
const strBShifted = `${strB.substring(shiftIndex)}${strB.substring(0, shiftIndex)}`;
if (strA === strBShifted) { return true }
shiftIndex++;
}
return false;
}
console.log(isSameAfterShifting2('abc', 'acb'));
Which one is more readable and easier to understand for you?
1 Answer 1
You can check if the String
is empty with !str
instead of strA.length === 0
,
console.log(''); // false
i think haveSameLength
and isSame
are extras, you can write srtA.length === strB.length
and it would still be readable,
you can get the first letter with a simpler strA[0]
instead of strA.substring(0, 1);
Which one is more readable and easier to understand for you?
a loop is easier to read and understand than a recursive function,
But the hole approach seems like it can be simpler using a for
loop, Array.some() , here's what i would suggest :
You can generate an array of combinations moving the letters one index at a time,
for a string abc
you would have ['abc, bca', 'cba']
, see if one of the resulting array entries euqals the second string :
const isSameAfterShifting = (str1, str2) => {
// check if the strings are empty or has different lengths
if (!str1 || !str2 || str1.length !== str2.length) return false;
// check if the strings are the same
if (str1 === str2) return true;
// generate the array
let combos = [];
for (let i = 0; i < str1.length; i++) {
let c = str1.slice(i) + str1.slice(0, i);
combos.push(c);
}
// for a string 'abc'
// combos = ['abc', bca', 'cab']
// check if the array has one of its entries equal to the second string
return combos.some(s => s === str2);
}
console.log( isSameAfterShifting('abc', 'cab') );
console.log( isSameAfterShifting('abc', 'cabaaa') );
console.log( isSameAfterShifting('abc', 'bac') );
you can replace the for
loop with Array.from()
const isSameAfterShifting = (str1, str2) => {
// check if the strings are empty or has different lengths
if (!str1 || !str2 || str1.length !== str2.length) return false;
// check if the strings are the same
if (str1 === str2) return true;
// generate the array
let combos = Array.from({
length: str1.length
}, (_, i) => str1.slice(i) + str1.slice(0, i));
// for a string 'abc'
// combos = ['abc', bca', 'cab']
// check if the array has one of its entries equal to the second string
return combos.some(s => s === str2);
};
console.log(isSameAfterShifting("abc", "cab"));
console.log(isSameAfterShifting("abc", "cabaaa"));
console.log(isSameAfterShifting("abc", "bac"));
Explore related questions
See similar questions with these tags.
const isShifted = (a, b) => a.length === b.length && a === b || (a + a).includes(b);
\$\endgroup\$