-
Notifications
You must be signed in to change notification settings - Fork 0
6. Zigzag Conversion #60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| ## 何も見ずに解いてみる | ||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| string convert(string s, int numRows) { | ||
| if (numRows == 1) { | ||
| return s; | ||
| } | ||
| vector<string> strings_by_line(numRows); | ||
| int pos = 0; | ||
| int dir = 1; | ||
| for (char c : s) { | ||
| strings_by_line[pos].push_back(c); | ||
| if (pos == 0) { | ||
| dir = 1; | ||
| } | ||
| if (pos == numRows - 1) { | ||
| dir = -1; | ||
| } | ||
| pos += dir; | ||
| } | ||
| return accumulate(strings_by_line.begin(), strings_by_line.end(), string()); | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
| ## 他の人のコードを見てみる | ||
|
|
||
| https://github.com/tokuhirat/LeetCode/pull/60/files | ||
| https://github.com/ryosuketc/leetcode_arai60/pull/60/files | ||
| https://github.com/Ryotaro25/leetcode_first60/pull/66/files | ||
| https://github.com/philip82148/leetcode-swejp/pull/5/files | ||
|
|
||
| https://cpprefjp.github.io/reference/numeric/reduce.html | ||
| https://cpprefjp.github.io/reference/numeric/accumulate.html | ||
| 今回の場合はaccumulateの方が良さそう。 | ||
|
|
||
| https://www.geeksforgeeks.org/cpp/stl-ropes-in-c/ | ||
| ropeという不思議なデータ構造があるらしい。 | ||
|
|
||
| indexを直接求める方式のコードも書いてみた。 | ||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| string convert(string s, int numRows) { | ||
| if (numRows == 1) { | ||
| return s; | ||
| } | ||
| string result; | ||
| int cycle_length = (numRows - 1) * 2; | ||
| for (int row = 0; row < numRows; ++row) { | ||
| for (int cycle_start = 0; cycle_start < s.size(); cycle_start += cycle_length) { | ||
| int first_index = cycle_start + row; | ||
| if (first_index < s.size()) { | ||
| result.push_back(s[first_index]); | ||
| } | ||
| if (row == 0 || row == numRows - 1) { | ||
| continue; | ||
| } | ||
| int second_index = cycle_start + cycle_length - row; | ||
| if (second_index < s.size()) { | ||
| result.push_back(s[second_index]); | ||
| } | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
| goto文なるものを使って書いてみたバージョン | ||
| https://en.cppreference.com/w/cpp/language/goto.html | ||
| (ちなみにこのコード上のやつに比べて結構遅かったです、おそらくvectorの中をfor文でいちいち回してるせい?) | ||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| string convert(string s, int numRows) { | ||
| if (numRows == 1) { | ||
| return s; | ||
| } | ||
| string result; | ||
| int cycle_length = (numRows - 1) * 2; | ||
| for (int row = 0; row < numRows; ++row) { | ||
| vector<int> indexes = {row}; | ||
| if (row != 0 && row != numRows - 1) { | ||
| indexes.push_back(cycle_length - row); | ||
| } | ||
| while (true) { | ||
| for (int& index : indexes) { | ||
| if (index < s.size()) { | ||
| result.push_back(s[index]); | ||
| index += cycle_length; | ||
| } else { | ||
| goto next_row; | ||
| } | ||
| } | ||
| } | ||
| next_row: ; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ラベルのインデントは一番浅い位置にする印象があります(例:CPython)。ただスタイルガイドに記載はないようです。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ラベルのインデントスタイルは意識していませんでした。ありがとうございます。 |
||
| } | ||
| return result; | ||
| } | ||
| }; | ||
| ``` | ||
|
|
||
| そういえば最初のコードの最後の部分で、 | ||
| ```cpp | ||
| string result; | ||
| for (string str : strings_by_line) { | ||
| result.append_range(str); | ||
| } | ||
| return result; | ||
| ``` | ||
| こういう風にstd::basic_string::append_rangeを使って構築しようとしたら、次のコンパイルエラーが出てできなかった。 | ||
| ``` | ||
| Line 22: Char 20: error: no member named 'append_range' in 'std::basic_string<char>' | ||
| 22 | result.append_range(str); | ||
| | ~~~~~~ ^ | ||
| 1 error generated. | ||
| ``` | ||
| append_rangeはc++23から追加されたメソッドとあり、leetcodeは下の画像にあるようにc++23の環境で動いているものと思っていたのですが、なぜなんでしょうか?(わかる方教えてください。。) | ||
| <img width="670" height="357" alt="image" src="https://github.com/user-attachments/assets/ec20eac5-6656-45a1-8033-32e2abbaafef" /> | ||
|
|
||
| ## 最終コード | ||
|
|
||
| こっちの方が結構早かったのでこっちにしてみました。 | ||
| `numRows <= 0`の挙動は書いているときには考えてなかったですが、見返してみると空文字列を返すようになってるのでいい感じな気がします。 | ||
|
|
||
| ```cpp | ||
| class Solution { | ||
| public: | ||
| string convert(string s, int numRows) { | ||
| if (numRows == 1) { | ||
| return s; | ||
| } | ||
| string result; | ||
| int cycle_length = (numRows - 1) * 2; | ||
| for (int row = 0; row < numRows; ++row) { | ||
| for (int cycle_start = 0; cycle_start < s.size(); cycle_start += cycle_length) { | ||
| int first_index = cycle_start + row; | ||
| if (first_index < s.size()) { | ||
| result.push_back(s[first_index]); | ||
| } | ||
| if (row == 0 || row == numRows - 1) { | ||
| continue; | ||
| } | ||
| int second_index = cycle_start + cycle_length - row; | ||
| if (second_index < s.size()) { | ||
| result.push_back(s[second_index]); | ||
| } | ||
| } | ||
| } | ||
| return result; | ||
| } | ||
| }; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 各行でindexを計算するの面白いですね。ですがやや複雑で、個人的には一番上に書かれたパターンが読みやすいと思いました。 |
||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
goto はあまり見ないように思います。理由として、濫用するとスパゲティコードになりやすいからだと思います。かなり深い最内周ループから関数の最後に飛びたいといった極めて限定的な個所では、使う場合もあるかもしれません。原則避けたほうが無難だと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
goto を使いたくなったら、大抵、もう少し整えられます。
たとえば、この場合だったら while (true) を関数にして、goto を return にしたほうがいいのではないでしょうか。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
あ、たしかにその方がよさそうですね。ありがとうございます。