Zenn
🖋

LeetCode 2108. Find First Palindromic String in the Array

2025/03/09に公開

はじめに

LeetCode 「2108. Find First Palindromic String in the Array」の問題をGoで解きました。

問題

https://leetcode.com/problems/find-first-palindromic-string-in-the-array/description/

問題文

Given an array of strings words, return the first palindromic string in the array. If there is no such string, return an empty string "".
A string is palindromic if it reads the same forward and backward.

和訳
文字列の配列 words が与えられた場合、その配列の最初の回文の文字列を返す。そのような文字列がない場合は、空の文字列 "" を返す。
文字列が回文であるのは、前後に同じ読み方をする場合である。

Input: words = ["abc","car","ada","racecar","cool"]
Output: "ada"
Explanation: The first string that is palindromic is "ada".
Note that "racecar" is also palindromic, but it is not the first.
Input: words = ["notapalindrome","racecar"]
Output: "racecar"
Explanation: The first and only string that is palindromic is "racecar".
Input: words = ["def","ghi"]
Output: ""
Explanation: There are no palindromic strings, so the empty string is returned.

制約

  • 1 <= words.length <= 100
  • 1 <= words[i].length <= 100
  • words[i] consists only of lowercase English letters.

解答1(Two Pointers)

今回の問題では、文字列が回文かどうかを判定する処理が必要となります。
回文かどうかの判定は、文字列の先頭・末尾から中央に向かって1文字ずつ文字を比較していくことで実現できます。
Two Pointers パターンが使えそうです。

Two Pointers パターン

Two Pointers は、2つの異なる位置からポインタを動かしながら探索を行う方法です。
主に配列や文字列操作を効率化するために使われ、時間計算量をO(n)に抑えることができるのがメリットです。

回文判定では 1回のループで 2文字をチェックできるため、対称性を活かして無駄な計算を減らせます。

コード

func firstPalindrome(words []string) string {
    for _, word := range words {
            if isPalindromic(word) {
            return word
        }
    }
    return ""
}

// 文字列が回文かどうかを判定する
func isPalindromic(s string) bool {
    left, right := 0, len(s)-1
    for left < right {
        if s[left] != s[right] {
            return false
        }
        left++
        right--
    }
    return true
}

isPalindromicで、leftは左から探索を行うポインタ、rightは右から探索を行うポインタです。
ポインタを動かしながら両端から1文字ずつ比較していき、ループを抜けた場合にtrueを返しています。

計算量

  • 時間的計算量: O(n * m)
    • mword の長さ、nwords の長さ
  • 空間的計算量: O(1)

解答2(reverse を使う方法)

最適解ではないものの、別のアプローチもあるので紹介します。
文字列を反転させる処理を作り、文字列が回文かどうかを判定する方法です。

コード

func firstPalindrome(words []string) string {
    for _, word := range words {
        if word == reverse(word) {
            return word
        }
    }
    return ""
}

// 文字列を反転させる(ASCII のみなので `[]byte` を使用)
// Unicode 文字(漢字・絵文字など)が含まれる場合は `[]rune` を使う
func reverse(s string) string {
    arr := []byte(s)
    left, right := 0, len(arr)-1
    for left < right {
        arr[left], arr[right] = arr[right], arr[left]
        left++
        right--
    }
    return string(arr)
}

計算量

  • 時間的計算量: O(n * m)
    • mword の長さ、nwords の長さ
  • 空間的計算量: O(m)

reverseを使う方法では、新しいスライスを作成して文字列を逆順に格納するため、追加のメモリが必要となります。
そのため、メモリ効率を考えるなら Two Pointers の方法の方が良い選択肢になります。

参考

Two Pointers パターンを使用する別の問題を以下の記事で紹介しています。

GitHubで編集を提案

Discussion

ログインするとコメントできます