Проверка на палиндром
Условие
Напишите функцию на Swift, которая проверяет, является ли строка палиндромом.
Требования:
- Строка может содержать любые символы, но учитывать нужно только числа и латинские буквы
- Регистр не важен
- Решение должно работать за константную память O(1) и линейное время O(n)
Пример:
- "Madam I'm Adam" → true
- "race a car" → false
- "A man, a plan, a canal: Panama" → true
Подсказка: Строки в Swift не имеют индексации по целым числам, так как символы могут иметь разную длину.
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение
Подход
Для проверки палиндрома со сложностью O(1) по памяти нужно использовать двухпоинтерный подход (two-pointer technique). Сначала отфильтруем только буквы и цифры, затем сравниваем символы с обоих концов, двигаясь к центру.
Основное решение
func isPalindrome(_ s: String) -> Bool {
let filtered = s.lowercased()
.filter { $0.isLetter || $0.isNumber }
let chars = Array(filtered)
var left = 0
var right = chars.count - 1
while left < right {
if chars[left] != chars[right] {
return false
}
left += 1
right -= 1
}
return true
}
Оптимизированное решение без массива
Если нужна истинная O(1) память (без создания массива):
func isPalindromeOptimized(_ s: String) -> Bool {
var left = s.startIndex
var right = s.index(before: s.endIndex)
while left < right {
// Двигаем левый указатель, пропуская невалидные символы
while left < right && !s[left].isLetter && !s[left].isNumber {
left = s.index(after: left)
}
// Двигаем правый указатель, пропуская невалидные символы
while left < right && !s[right].isLetter && !s[right].isNumber {
right = s.index(before: right)
}
// Сравниваем символы без учёта регистра
if s[left].lowercased() != s[right].lowercased() {
return false
}
left = s.index(after: left)
right = s.index(before: right)
}
return true
}
Тестирование
print(isPalindrome("Madam I'm Adam")) // true
print(isPalindrome("race a car")) // false
print(isPalindrome("A man, a plan, a canal: Panama")) // true
print(isPalindrome("0P")) // false
print(isPalindrome("a.")) // true
Анализ сложности
Первое решение:
- Время: O(n) — проходим строку один раз для фильтрации, затем один раз для сравнения
- Память: O(n) — создаём новый массив символов
Оптимизированное решение:
- Время: O(n) — каждый символ проверяется максимум 2 раза
- Память: O(1) — используем только два указателя, никаких дополнительных структур
Особенности Swift
-
Индексация строк: В Swift нет прямой индексации по целому числу, используются
Index. Поэтому преобразование в массив часто проще и понятнее. -
lowercased()vslowercased()на Character: Нужно вызывать на Character, иначе сравнение может быть неправильным. -
isLetterиisNumber: Встроенные методы Character в Swift, работают с Unicode корректно.
Рекомендация
Для интервью рекомендую первое решение — оно проще, понятнее и по-прежнему имеет хорошую сложность. Оптимизированное решение можно упомянуть как альтернативу, если нужна истинная O(1) память.