1
\$\begingroup\$

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?

\$\endgroup\$
2
  • \$\begingroup\$ I think this needs only a one liner const isShifted = (a, b) => a.length === b.length && a === b || (a + a).includes(b); \$\endgroup\$
    – Blindman67
    Commented Feb 12, 2019 at 21:15
  • \$\begingroup\$ This is quite genius. Lol \$\endgroup\$ Commented Feb 14, 2019 at 17:55

1 Answer 1

1
\$\begingroup\$

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"));

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.