Привет кодеры,

Сегодня мы будем решать задачу Первый уникальный символ в строке в JavaScript (ES6). Разбираемся в проблеме:

Имея строку s, найти в ней первый неповторяющийся символ и вернуть его индекс. Если он не существует, вернуть -1. Например:

Ввод: s = "ilovejavascript"

Выход: 1

Объяснение: l — это первый уникальный символ в данной строке, и он присутствует в индексе 1st, поэтому мы возвращаем 1.

Ввод: s = "aabbcc"

Выход: -1

Объяснение: в данной строке нет уникальных символов, поэтому мы возвращаем -1.

Подход:

Первый подход: временная сложность O(n)

Мы собираемся отслеживать все символы, встречающиеся в строке, и проверять, уникальна она или нет. Для этого мы можем перебрать строку и сохранить characters и их occurrences в строке как пару key-value в object.

//If the given string is:
s = "medium";

//the object will be:

obj = {m:2,e:1,d=1,i=1,u=1}

Затем мы пройдем через keys из object и вернем index из первого ключа, который будет иметь значение 1. В этом случае мы вернем индекс e в строке s, так как это первый уникальный символ в строке. Таким образом, наш вывод будет 1. Если уникального символа нет, возвращаем -1.

Второй подход: временная сложность O(n)

Мы собираемся перебрать строку и проверить, равен ли первый индекс символа в строке последнему индексу символа в строке. Затем мы вернем индекс символа, который удовлетворяет этому условию в первый раз, так как это будет первый уникальный символ. Если уникального символа нет, возвращаем -1.

Если заданная строка s = "medium" :

Первый индекс символа m0, а последний индекс — 5. А значит не уникальный.

Первый индекс символа e равен 1, а последний индекс - 1. Это означает, что это уникальный символ, и мы возвращаем его index в строке s.

Решение с использованием первого подхода:

Создадим функцию firstUniqueChar, которая принимает в качестве параметра строку s. Также мы объявим объект charObj, который будет хранить пары ключ-значение символов и их вхождения в строку.

const firstUniqueChar = (s) => {
  let charObj = {};
  //...
  //...
  //...
}

Теперь давайте создадим цикл, который будет использоваться для перебора строки s. Я использую здесь оператор for…in, вы также можете использовать обычный for loop.

const firstUniqueChar = (s) => {
  let charObj = {};
  for(i in s){
    //...
    //...
    //...
  }
  //...
}

Теперь мы проверим, присутствует ли уже в массиве key в объекте charObj, который является символом с индексом i,. Если он уже присутствует в массиве, мы увеличим его, иначе мы присвоим его значение как 1, так как это будет первое вхождение символа в строку. Я использовал для этого тернарный оператор, вы также можете использовать оператор if-else.

const firstUniqueChar = (s) => {
  let charObj = {};
  for(i in s){
    charObj[s[i]] ? charObj[s[i]]++ : charObj[s[i]]=1;
  }
  //...
  //...
}

Давайте пройдемся по объекту charObj и проверим values его keys. Если value равно 1, мы вернем index из key в строке s.

const firstUniqueChar = (s) => {
  let charObj = {};
  for(i in s){
    charObj[s[i]] ? charObj[s[i]]++ : charObj[s[i]]=1;
  }
  for(key of Object.keys(charObj)){
    if(charObj[key]===1){
     return s.indexOf(key); 
     }
  }
  //...
  //...
}

Метод indexOf() возвращает первый индекс, по которому данный элемент может быть найден в массиве, или -1, если он отсутствует.

А что если в строке s нет уникального символа. Для этого мы можем просто вернуть -1 вне циклов, потому что, если в строке будет присутствовать уникальный символ, цикл for...of, перебирающий объект, вернет его индекс. Единственный случай, когда последний оператор return будет выполнен, — это только в том случае, если в строке не будет уникального символа.

const firstUniqueChar = (s) => {
  let charObj = {};
  for(i in s){
    charObj[s[i]] ? charObj[s[i]]++ : charObj[s[i]]=1;
  }
  for(key of Object.keys(charObj)){
    if(charObj[key]===1){
     return s.indexOf(key); 
     }
  }
  return -1;
}

Вот и все! Это полная функция, использующая первый подход. Теперь рассмотрим второй подход.

Решение с использованием второго подхода:

Сначала мы создадим функцию firstUniqueChar, которая принимает строку s в качестве параметра.

const firstUniqueChar = (s) => {
  //...
  //...
  //...
}

Теперь мы пройдемся по строке s и проверим, равно ли first index символа last index символа, и если это так, мы вернем first index этого символа. Мы будем использовать метод indexof() для нахождения первого индекса символа и метод lastIndexOf() для нахождения последнего индекса символа. Мы вернем -1 вне цикла, как и в первом подходе, чтобы обработать случай отсутствия уникальных символов в строке.

const firstUniqueChar = (s) => {
  for(i in s){
    if(s.indexOf(s[i])===s.lastIndexOf(s[i])){
      return i;
    }
  }
  return -1;
}

Вот и все! Вот оно, решение той же проблемы, но с меньшим количеством строк кода и циклов.

Дайте мне знать, помогло ли это вам в разделе комментариев, а также дайте мне знать, как бы вы хотели решить эту проблему.

Большое спасибо, что пришли сюда!