Недавно во время интервью меня попросили решить задачу кодирования, связанную со сжатием строк. По сути, функция должна принимать на вход строку, такую ​​как «a3b2c3c9b2», и возвращать сжатую версию строки, добавляя цифры, соответствующие букве, предшествующие цифрам. Если мы возьмем наш предыдущий пример, «a3b2c3c9b2», наш вывод должен выглядеть как «a3b4c12», поскольку «b2» + «b2» = «b4» и «c3» + «c9» = «c12». Предполагается, что функция также сортирует вывод, поэтому, если нам дано «d3a3b3a1d2», она должна вывести «a4b3d5». Для этого примера мы предполагаем, что все введенные символы будут в нижнем регистре. Цель этой статьи — описать мое решение и мыслительный процесс при решении этой проблемы.

Моим первым шагом к решению этой проблемы было разбить строку на массив, в котором символы и числа были разделены. Использование метода .split() здесь бесполезно, потому что если у нас есть двузначное значение в строке, оно разделит эту цифру. Это не то поведение, которое нам нужно. По сути, я инициализировал массив, содержащий первый элемент строки. Затем я инициализировал строку с именем numTemp. Целью numTemp является отслеживание чисел, следующих за символами в строковом формате. Мы перебираем строку и проверяем, является ли текущий элемент строки символом. Если это так, то текущее значение numTemp помещается в массив, затем символ, а затем numTemp сбрасывается до пустой строки. Оператор else учитывает элементы, являющиеся цифрами. После завершения цикла for последнее значение numTemp не помещается в массив. Поэтому мы делаем это вручную, как только оно будет завершено. Для строки "a1b12c3a4" массив будет иметь вид ['a','1','b','12','c','3','a','4'].

function stringComp(str){
let arr = [str.charAt(0)];
let numTemp = "";
for(let i = 1; i < str.length; i++){
let temp = str.charAt(i);
    
    if(temp.length === 1 && temp.match(/[a-z]/i)){
      arr.push(numTemp);
      arr.push(str.charAt(i));
      numTemp = "";
    }else{
      numTemp += str.charAt(i);
    }  
  }
arr.push(numTemp);
}

На данный момент я получил то, что хотел от предыдущего массива, но не знал, что с ним делать. Затем я подумал о создании отсортированного массива, содержащего каждый символ в массиве (без дубликатов), за которым следует счетчик для каждого символа. По сути, я хотел получить «d1a12b14c2d3» => [‘a’,12,’b’,14,’c’,2,’d’,4]. Таким образом, я могу просто пройтись по этому массиву, добавить элементы в строку и получить свое решение.

Моим первым шагом было создание массива с отсортированными символами. Я перебрал наш предыдущий массив и проверил, является ли каждый элемент символом. Затем я добавил условие, которое проверяет, находится ли этот элемент уже в нашем новом массиве. Это для учета дубликатов. Затем я использовал метод .sort() для этого массива, чтобы убедиться, что буквы отсортированы:

let charArr = [];
for(let i = 0; i < arr.length; i++){
    let temp = arr[i];
    if(temp.length === 1 && temp.match(/[a-z]/i) && !charArr.includes(temp)){
      charArr.push(temp);
    }
  }
resArr.sort();

В этот момент, если мы введем значение «d1a1b2c3» в функцию, charArr выдаст [‘a’,’b’,’c’,’d’]. Это хорошо, но не то, что мы хотим. Мы хотим убедиться, что за каждым символом следует счетчик. Простой способ сделать это — создать новый массив, перебрать charArr и поместить каждый элемент в новый массив, за которым следует 0. Используя наш предыдущий пример «d1a1b2c3», charArr2 теперь дает ['a',0,'b ',0,'c',0,'d',0].

let charArr2 = []
for(let i = 0; i < charArr.length; i++){
    charArr2.push(charArr[i]);
    charArr2.push(0);
  }
}

Чтобы заполнить значения счетчика, я перебрал этот первый массив и проверил наличие несимвольных значений. После того, как он найден, нам нужно найти правильный индекс charArr2, чтобы добавить значение temp. Я сделал это, вызвав метод .indexOf() для charArr2 и установив его для символа прямо перед temp. Затем мы добавляем к этому 1, потому что мы ищем индекс счетчика, а не символ. Поскольку мы разделили строку на массив так, как мы это сделали, это гарантирует, что элемент перед каждым несимвольным значением всегда будет символом. В этом случае искомый индекс содержит правильное значение счетчика в charArr2. Затем мы анализируем текущий элемент до целого числа и добавляем его к счетчику.

for(let i = 0; i < arr.length; i++){
    let temp = arr[i];
    if(!temp.match(/[a-z]/i)){
      let index = charArr2.indexOf(arr[i-1]) + 1;
      charArr2[index] += parseInt(arr[i]);
    }
  }

Теперь charArr2 показывает поведение, которое нам нужно. В этот момент строковое значение, которое мы рассматривали ранее, «d1a12b14c2d3», превратит charArr2 в [‘a’,12,’b’,14,’c’,2,’d’,4]. Наш последний шаг — перебрать charArr2, добавить каждый элемент в строку и вернуть эту строку.

let result = "";
for(let i = 0; i < charArr2.length;i++){
    result += charArr2[i].toString();
  }
  return result;