HappyHands31
HappyHands31

Reputation: 4101

Longest Repeating Character In String - Javascript

I'm ultimately trying to solve this challenge on codewars.

I know how to find out how many times a character appears in a string, but not how many times it appears in order.

I.e. given the string bbbaaabaaaa, we see that the longest repeating character is a of length 4.

I tried a simple for-loop, comparing characters to previous characters to see if they're identical:

function longestRepetition (str) {
  let longestChunk = '';
  for (let i = 0; i < str.length; i++) {
    let chunk = '';
    if (i === 0) {
      if (str[i] === str[i + 1]) {
        chunk += str[i];
      }
    }
    if (i > 0) {
      if (str[i] === str[i - 1]) {
        chunk += str[i];
        console.log('chunk**', chunk);
      }
      if (chunk.length > longestChunk.length) {
        longest = chunk;
      }
    }
  }
  return longestChunk;
}

console.log(longestRepetition('bbbaaabaaaa'));

What's most concerning is that chunk is not increasing in size ever whenever I console.log it.

Shouldn't we be seeing:

'chunk**' b

'chunk**' bb

'chunk**' bbb

?

Instead, we're just seeing the single characters get logged. Then, my logic is to compare the chunk to the longestChunk and return the longestChunk outside of the for-loop.

Any ideas as to why this isn't working, or what other strategies I should try to return the longest repeating character from a string?

I realize that I will have to format what I return as an array with the character that repeats the most, and the length of it's longest repeat or chunk.

Upvotes: 1

Views: 4892

Answers (5)

HappyHands31
HappyHands31

Reputation: 4101

Here is my solution:

function longestRepetition (str) {
  if (str.length === 0) {
     return ['', 0]
  }
  let longest = '';
  let chunk = '';
  for (let i = 0; i < str.length; i++) {
    if (i === 0) {
      if (str[i] === str[i + 1]) {
        chunk += str[i];
      }
    }
    if (i > 0) {
      if (str[i] === str[i - 1]) {
        chunk += str[i];
        console.log('chunk**', chunk);
      }
      if (str[i] !== str[i - 1]) {
        chunk = str[i];
      }
      if (chunk.length > longest.length) {
        longest = chunk;
      }
    }
  }
  return [longest[0], longest.length];
}

console.log(longestRepetition("bbbaaabaaaa"))

Thank you everyone for helping me clean up my code! The key (as @NineBerry pointed out) was to define chunk as an empty string outside of the for-loop, and re-assign chunk as a new, single character when it's different from the previous.

Upvotes: 4

Rajib Hossain Khan
Rajib Hossain Khan

Reputation: 29

/** Hello, I have borrowed the idea from the last solution and then customized it to serve my purpose. Credit goes to the contributor. */

function largestConsecRepeatChar(inputStr) {
    let lrgConsRepChar = "";
    if (inputStr && typeof inputStr === 'string' && inputStr.trim()) {
        function reducerCallback(accumulator, currentValue) {
            if (accumulator.lastChar === currentValue) {
                accumulator.count += 1;
            } else {
                accumulator.count = 1;
            }
            accumulator.lastChar = currentValue;
            if (accumulator.count > accumulator.result.countTracker) {
                accumulator.result = { repeatingChar: currentValue, countTracker: accumulator.count };
            } else {
                accumulator.result = accumulator.result;
            }
            return accumulator;
        }
        const initialValue = {
            result: { repeatingChar: "", countTracker: 0 }
        };
        const { result } = inputStr.trim().split('').reduce(reducerCallback, initialValue);
        lrgConsRepChar = result.countTracker > 1 ? result.repeatingChar.repeat(result.countTracker) : "";
        return lrgConsRepChar;
    }
    return lrgConsRepChar;
}

console.log(largestConsecRepeatChar(" ybtyyrjpy "));

Upvotes: 1

MinusFour
MinusFour

Reputation: 14423

Just in case you'd want a shorter version of your idea:

function longestRepetition (str) {
  let longestChunk = '';
  let currentChunk = '';
  for(let i = 0; i < str.length; i++){
     if(currentChunk[0] !== str[i]){
        currentChunk = str[i];
     } else {
        currentChunk += str[i];
     }
     if(currentChunk.length > longestChunk.length){
        longestChunk = currentChunk;
     }
  }
  return [longestChunk[0] ?? '', longestChunk.length];
}

console.log(longestRepetition('bbbaaabaaaa'));
console.log(longestRepetition('b'));
console.log(longestRepetition(''));

Upvotes: 1

tao
tao

Reputation: 90038

You could solve this by using reduce on an array from your string:

function longestRepetition(s) {
  const reducer = (acc, value) => {
    acc.count = acc.last === value
      ? acc.count + 1
      : 1;
    acc.last = value;
    acc.result = acc.count > acc.result.count
      ? { count: acc.count, char: value }
      : acc.result;
    return acc;
  }
  const initAcc = {
    result: {
      char: '',
      count: 0
    }
  }
  const { result } = s.split('').reduce(reducer, initAcc);
  
  return [result.char, result.count];
}

console.log(longestRepetition('aaabbbabbaaaabba'));

Docs: Array.prototype.reduce().

It obviously depends on use-case but, in general, expect reducers to be cheap to run, as they only go through the collection once.

In this particular case, your solution (the for loop) runs all tests in ~230ms. The reducer function runs them in ~80ms (with slight variations - ran them 3 times each).
The reducer is almost three times faster.

Upvotes: 0

Carsten Massmann
Carsten Massmann

Reputation: 28196

You can simply use a regular expression to find the longest matching single letter sequence:

str.match(/(.)\1*/g).sort((a,b)=>b.length-a.length)[0]

Just play around with the following fiddle:

document.querySelector('#test').addEventListener('keyup',function(ev){
 var res=(ev.target.value.match(/(.)\1*/g)||['']).sort((a,b)=>b.length-a.length)[0];
 document.querySelector('#out').innerText=JSON.stringify([res[0],res.length]);
});
<input size="40" type="text" id="test" value="aaaabbbbbbbccddddzfffffklxxxaavvvv"><br>
<div id="out"></div>

Upvotes: 2

Related Questions