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
158 changes: 158 additions & 0 deletions 6/6.md
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;
Copy link

Choose a reason for hiding this comment

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

goto はあまり見ないように思います。理由として、濫用するとスパゲティコードになりやすいからだと思います。かなり深い最内周ループから関数の最後に飛びたいといった極めて限定的な個所では、使う場合もあるかもしれません。原則避けたほうが無難だと思います。

Copy link

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 にしたほうがいいのではないでしょうか。

Copy link
Owner Author

Choose a reason for hiding this comment

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

あ、たしかにその方がよさそうですね。ありがとうございます。

}
}
}
next_row: ;

Choose a reason for hiding this comment

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

ラベルのインデントは一番浅い位置にする印象があります(例:CPython)。ただスタイルガイドに記載はないようです。

Copy link
Owner Author

Choose a reason for hiding this comment

The 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;
}
};

Choose a reason for hiding this comment

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

各行でindexを計算するの面白いですね。ですがやや複雑で、個人的には一番上に書かれたパターンが読みやすいと思いました。

```