Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions 392/392.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
## 何も見ずに解いてみる

```cpp
class Solution {
public:
bool isSubsequence(string s, string t) {
auto it = s.begin();
for (char c : t) {
if (c == *it) {
++it;
}
if (it == s.end()) {
break;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ここで return true、最後で return false してもよいと思います。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

実は最初そのように書いたのですが、leetcode上でs = "", t = ""のテストケースがあり、それに対応するためにこのようにしていました。

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

そのテストケース気付きませんでした。ありがとうございます。

}
}
return it == s.end();
}
};
```

## 他の人のコードを見てみる

https://github.com/tokuhirat/LeetCode/pull/57/files
https://github.com/KentaroJay/Leetcode/pull/9/files
https://github.com/ryosuketc/leetcode_arai60/pull/57/files
for文で回すとsが終わりまで到達したときにわざわざif文を入れてbreakしなければならなくなるのがいやだなと思っていたので、この書き方は結構いいと思った。
https://github.com/Ryotaro25/leetcode_first60/pull/62/files
https://github.com/usatie/leetcode/pull/5/files

Follow upあるの気づかなかった。
Follow up: Suppose there are lots of incoming s, say s1, s2, ..., sk where k >= 109, and you want to check one by one to see if t has its subsequence. In this scenario, how would you change your code?

tにおいてある文字が出てくるindexの配列を<char, vector<int>>の辞書として管理しておいて、現在の場所以降で一番最初にあるs中の文字が出てくる場所を二分探索で探す方法(1つのsあたりの時間計算量O(|s|log|s|))の他に、

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

一応、O(|s| log|t|))ですね。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

あ、ご指摘の通りですね。失礼しました。

この問題のように文字の種類が固定されている(26種類だけ)の場合は、tにおけるすべてのindexにおいて次にある文字が出てくるindexが書いてある配列を最初に構成してしまうことで、1つのsあたりの計算量をo(|s|)にすることもできる。(ただしその配列の構成にO(|t| × 文字の種類)の時間とメモリがかかるので大体のユースケースで見合ってなさそうな気はする)

変数名にit_tという名前を使おうとしたらleetcodeのエディター上で名前が水色になるのでなんだろうと思って調べてみたら、intまたはuintで始まって_tで終わるような名前はC++の予約語で、_tで終わるだけのものもPOSIX(Unix系のOSの国際標準?)では予約されているらしい。
少なくともPOSIXライブラリをincludeするようなときは避けたほうが良さそう?

https://stackoverflow.com/questions/56935852/does-the-iso-9899-standard-has-reserved-any-use-of-the-t-suffix-for-identifiers
https://www.iso-9899.info/n1570.html#7.31.10

C++の標準規格はドラフト版が無料で公開されているらしいが正式版は有料らしい。
<img width="674" height="764" alt="image" src="https://github.com/user-attachments/assets/263da838-db6e-425c-8c3c-f08db35b3329" />
というか、3年おきの更新だったのか。これも知らなかった。

## 最終コード

```cpp
class Solution {
public:
bool isSubsequence(string& s, string& t) {
auto s_it = s.begin();
auto t_it = t.begin();
while (s_it != s.end() && t_it != t.end()) {
if (*s_it == *t_it) {
++s_it;
}
++t_it;
}
return s_it == s.end();
}
};
```

イテレーターで書くよりintとかsize_tでインデックスを保存してoperator[]で要素比較したほうが読みやすいですかね?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

良いと思いました。
イテレーターで書くメリットは、string& 以外の型に拡張する時に楽、添字で配列外参照しない、ぐらいでしょうか。

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

確かに今回でいうs, tなどの変数名に応じてプログラムを変えなくていいのはメリットですね!