Огляд Проблеми
Дано рядок s
, що складається зі слів та пробілів. Потрібно повернути довжину останні слова в рядку._
Слово — це максимальна підстрічка (безперервна непорожня послідовність символів в рядку), що складається лише з не-пробільних символів.
Приклад 1:
Вхід: s = “Hello World” Вихід: 5 Пояснення: Останнє слово — “World”, його довжина 5.
Приклад 2:
Вхід: s = “ fly me to the moon “ Вихід: 4 Пояснення: Останнє слово — “moon”, його довжина 4.
Приклад 3:
Вхід: s = “luffy is still joyboy” Вихід: 6 Пояснення: Останнє слово — “joyboy”, його довжина 6.
Обмеження:
1 <= s.length <= 104
s
складається лише з англійських літер та пробілів' '
.- В рядку буде хоча б одне слово.
Основні методи JavaScript, які використовуються
1.
split()
: для розділення рядка за вказаним роздільником
Як працює split? string.split(separator, [, limit])
- separator, як символ, підрядок чи регулярний вираз, і розділяє рядок там, де знаходиться роздільник
- результатом є масив підрядків
s+/) - розділяє за одним чи кількома пробілами
```
\s+
— це регулярний вираз, який відповідає одному або більше пробільним символам. Використовуючи цей вираз, ми можемо розділити рядок за пробілами та отримати масив з окремими словами в реченні.
filter()
- для фільтрації на основі заданих критеріїв
Огляд рішення
Проблема 1: Початкове завдання полягало в тому, щоб розділити підрядки з усього речення та видалити зайві пробіли на початку, в середині та в кінці речення.
Рішення: використовуючи метод split(/\s+/)
в JavaScript
Проблема 2: Як видалити порожні рядки? Рішення: використати метод filter()
, щоб повернути валідні значення, що не є пустими.
Спроби вирішення
Спроба 1
/**
* @param {string} s
* @return {number}
*/
var lengthOfLastWord = function (s) {
const substring = s.split(/\s+/);
const fullSubstring = substring.filter(val => val !== " ");
const lastWord = fullSubstring[fullSubstring.length - 1];
const lengthOfLastWord = lastWord.length;
return lengthOfLastWord;
};
Після виконання цього коду він дав неправильну відповідь, оскільки не пройшов тестовий випадок " fly me to the moon "
. Очікуваний результат — 4 для слова "moon", але мій алгоритм повернув "0". З цього можна зробити висновок, що алгоритм врахував порожній рядок і повернув його довжину як 0.
Моя фільтрація порожнього рядка має проблему.
Спроба 2 — Остаточне рішення
/**
* @param {string} s
* @return {number}
*/
var lengthOfLastWord = function (s) {
const substring = s.split(/\s+/);
const fullSubstring = substring.filter(val => val);
const lastWord = fullSubstring[fullSubstring.length - 1];
const lengthOfLastWord = lastWord.length;
return lengthOfLastWord;
};
Хоча моє попереднє рішення було переважно правильним з точки зору логіки, виникла невелика проблема, яка проявляється у певних крайніх випадках, коли рядок s
завершується пробілами.
Проблеми:
Метод split(/\s+/)
розділяє рядок на масив слів, збігаючись з одним або кількома пробілами. Однак:
- Якщо рядок має трейлінгові пробіли (пробіли в кінці), наприклад,
"Hello world "
, тоsplit(/\s+/)
створить масив, де останнім елементом може бути порожній рядок (["Hello", "world", ""]
).
2.
Фільтрація за допомогоюfilter(val => val !== " ")
неправильно обробляє порожні рядки, оскільки порожній рядок (""
) не є строго рівним пробілу (" "
).
приклад: const s = "Hello world ";
Кроки призведуть до наступного:
s.split(/\s+/)
→["Hello", "world", ""]
substring.filter(val => val !== " ")
→["Hello", "world", ""]
(без змін, оскільки порожній рядок не є" "
)fullSubstring[fullSubstring.length - 1]
→""
(порожній рядок як останній елемент)lastWord.length
→0
, що є неправильним.
Виправлення:
Щоб правильно обробити це, потрібно:
- Забезпечити видалення всіх порожніх рядків з масиву після розбиття.
- Використовувати
filter(val => val)
замістьfilter(val => val !== " ")
, оскількиfilter(val => val)
виключає порожні рядки (""
) та інші "фальшиві" значення.
Що означає val => val
?
Метод filter()
приймає функцію зворотного виклику, яка визначає, чи має кожен елемент масиву бути включений в результатуючий масив.
У цьому випадку val => val
є скороченням для:
function(val) { return val; }
- Функція перевіряє, чи є
val
правдивим значенням. - Якщо
val
є правдивим значенням, воно включається до масивуfullSubstring
. - Якщо
val
є неправдивим значенням, воно виключається з масивуfullSubstring
.
Що таке "правдиві" (truthy) та "неправдиві" (falsy) значення?
У JavaScript:
-
Правдиві значення — це значення, які оцінюються як
true
в булевому контексті. Приклади:- Непорожні рядки (наприклад,
"hello"
,"world"
) - Ненульові числа (наприклад,
1
,-42
) - Об'єкти, масиви тощо.
- Непорожні рядки (наприклад,
-
Неправдиві значення — це значення, які оцінюються як
false
в булевому контексті. Приклади:""
(порожній рядок)0
null
undefined
NaN
false
Чому ця лінія корисна у вашому коді?
У контексті вашої функції lengthOfLastWord
, метод s.split(/\s+/)
може створювати масив, який містить порожні рядки (""
), особливо коли вхідний рядок містить кілька пробілів.
Використання filter(val => val)
видаляє ці порожні рядки.
Остаточне рішення:
- 59/59 тестів пройдено!**
- Часова складність:
O(N)
(лінійний прохід по рядку). - Просторова складність:
O(N)
(розмір стеку залежить від довжини вхідних даних). - Час виконання:
0ms
. - Пам'ять:
49.37MB
.
Ключові висновки з остаточного рішення
- важливість знання регулярних виразів для розуміння, коли і де розділяти підрядки
Перекладено з: Leetcode Daily Series : Solving Length of Last Word