From 986895d8c320ddce731dd99b5c54b834cc946207 Mon Sep 17 00:00:00 2001 From: Ryohei Sato <130881456+Satorien@users.noreply.github.com> Date: Sun, 4 Jan 2026 12:54:39 +0900 Subject: [PATCH] Solved Arai60/392. Is Subsequence --- Python3/392. Is Subsequence.md | 100 +++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 Python3/392. Is Subsequence.md diff --git a/Python3/392. Is Subsequence.md b/Python3/392. Is Subsequence.md new file mode 100644 index 0000000..58fd2f4 --- /dev/null +++ b/Python3/392. Is Subsequence.md @@ -0,0 +1,100 @@ +## Step 1. Initial Solution + +- 最初に思い付いたのは subsequence の文字列を一つずつ見て行って、元文字列を前から線形に探索していく方法 + - 特に整序されているわけではないのでこの順番で見ていくのが良さそう +- 毎度文字列のコピーをするのは避けたいのでindexを動かしていく +- indexを動かしながら見つからない時の処理をする +- 本当はfind関数の方が最適化されていて速そうだが引数の順番とかを思い出せなかったのでfor文で実装 + +```python +class Solution: + def isSubsequence(self, s: str, t: str) -> bool: + last_char_index = 0 + char_index = 0 + for c in s: + for i in range(last_char_index, len(t)): + if c == t[i]: + char_index = i + 1 + break + if last_char_index == char_index: + return False + last_char_index = char_index + return True +``` + +- str.find(ch, index_from)のような形だった気がすると思って実装したら行けた + +```python +class Solution: + def isSubsequence(self, s: str, t: str) -> bool: + char_index = 0 + for c in s: + char_index = t.find(c, char_index) + 1 + if char_index == 0: + return False + return True +``` + +### Complexity Analysis + +- 時間計算量:O(n) + - n: tの長さ (=10^4)より10^8 Step/sならk*0.1ms +- 空間計算量:O(1) + +## Step 2. Alternatives + +- Follow upの「もし沢山の subsequences を確認するならどうするか」という点については、tから辞書を作って参照しながら進める方が速そう + - ただ、高々26分割して探せるだけなので大きな高速化には至らないか + + ```python + class Solution: + def isSubsequence(self, s: str, t: str) -> bool: + char_to_indices = defaultdict(list) + for i in range(len(t)): + char_to_indices[t[i]].append(i) + + char_to_next_index = {} + for ch in string.ascii_lowercase: + char_to_next_index[ch] = 0 + + last_index = -1 + for ch in s: + char_indices = char_to_indices[ch] + while True: + if char_to_next_index[ch] >= len(char_indices): + return False + + if char_indices[char_to_next_index[ch]] > last_index: + last_index = char_indices[char_to_next_index[ch]] + break + char_to_next_index[ch] += 1 + return True + ``` + +- https://github.com/tokuhirat/LeetCode/pull/57/files#diff-56d94b18dcde3860786d1548afc303826c1dd1b5174a1c5baf29ccdac65c935eR30-R42 + - シンプルに書くとこのようなindexをそれぞれで動かしていく方法もあり +- https://github.com/ryosuketc/leetcode_arai60/pull/57/files#diff-d4bf0ffef278eb91530487cdf19578095c7402d9ba6698ca2a48c8c9e32cffe9R12 + - subsequence … can be none のところを自分もちゃんと意識していなかったので気を付けたい +- https://github.com/fhiyo/leetcode/pull/55/files#diff-a6c7d5ff748fd033529b0b0a550ed2aa570e18edc3e2c61da5094aec0e23a91eR45 + - follow upについて、基本的な考え方は似ている + - bisectで探す方法は考えていなかった + - 確かにindexをlast_indexから探すのはあり + - そもそも一致する可能性があまりないものを二分探索で探す発想がなかった + - 昇順になっていることを考えると計算量的には二分探索の方が良さそうだが自分のやり方のように最後に見た場所から探し始める方がHeuristicな考えとして有効な気がしなくもない + - 最後に見た場所をbisectのloに入れておくというのもありか? + - この問題に対しては処理を複雑にし過ぎているような気もする + +## Step 3. Final Solution + +- 自分で最初に書いたやり方がしっくり来ていたのでちょっとだけ変えて練習 + +```python +class Solution: + def isSubsequence(self, s: str, t: str) -> bool: + char_index = -1 + for ch in s: + char_index = t.find(ch, char_index + 1) + if char_index == -1: + return False + return True +```