-
Notifications
You must be signed in to change notification settings - Fork 0
solve: 283.Move Zeroes #54
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
Open
t9a-dev
wants to merge
1
commit into
main
Choose a base branch
from
283.-Move-Zeroes
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| // Step1 | ||
| // 目的: 方法を思いつく | ||
|
|
||
| // 方法 | ||
| // 5分考えてわからなかったら答えをみる | ||
| // 答えを見て理解したと思ったら全部消して答えを隠して書く | ||
| // 5分筆が止まったらもう一回みて全部消す | ||
| // 正解したら終わり | ||
|
|
||
| /* | ||
| 問題の理解 | ||
| - 整数からなる配列numsが与えられる。numsに含まれる0を配列の末尾に移動する。このとき、0以外の数値は並び順を変更しない。 | ||
| 新たに配列を作らずに(numsをコピーせず)処理を行う必要がある。 | ||
|
|
||
| 何を考えて解いていたか | ||
| - 配列を走査しながら0を見つけたらremove()して、push()すればin-placeで解けそう。 | ||
| n = nums.len() | ||
| 時間計算量: O(n) | ||
| 空間計算量: O(1) | ||
|
|
||
| テストケース nums=[0, 0, 1] out=[0, 1, 0]となり,wrong Answerとなった。 | ||
| ループ中に配列を変更するので、2つ目の0をループ中で飛ばしてしまうのが原因だと思った。 | ||
| for-loopではなく、while-loopにして0を見つけて移動させたときはインデックスをインクリメントしない方針で対応できそう。 | ||
| これまでに見た要素数を別でインクリメントしておいて、nums.len() - 1になったらループを抜けないと無限ループになる。 | ||
|
|
||
| 何がわからなかったか | ||
| - そのままループで解けると思い込んでしまい、エッジケースでWrong Answerとなった。 | ||
|
|
||
| 正解してから気づいたこと | ||
| - iter.remove(i)は時間計算量がO(n)なので、全体の時間計算量はO(n ^ 2)になる。 | ||
| */ | ||
|
|
||
| pub struct Solution {} | ||
| impl Solution { | ||
| pub fn move_zeroes(nums: &mut Vec<i32>) { | ||
| let mut i = 0; | ||
| let mut processed_nums_count = 0; | ||
|
|
||
| while processed_nums_count < nums.len() { | ||
| processed_nums_count += 1; | ||
|
|
||
| if nums[i] != 0 { | ||
| i += 1; | ||
| continue; | ||
| } | ||
|
|
||
| let zero = nums.remove(i); | ||
| nums.push(zero); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn step1_test() { | ||
| let mut before_nums = vec![0, 1, 0, 3, 12]; | ||
| let after_nums = vec![1, 3, 12, 0, 0]; | ||
| Solution::move_zeroes(&mut before_nums); | ||
| assert_eq!(before_nums, after_nums); | ||
|
|
||
| let mut before_nums = vec![0]; | ||
| let after_nums = vec![0]; | ||
| Solution::move_zeroes(&mut before_nums); | ||
| assert_eq!(before_nums, after_nums); | ||
|
|
||
| let mut before_nums = vec![0, 0, 1]; | ||
| let after_nums = vec![1, 0, 0]; | ||
| Solution::move_zeroes(&mut before_nums); | ||
| assert_eq!(before_nums, after_nums); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| // Step2 | ||
| // 目的: 自然な書き方を考えて整理する | ||
|
|
||
| // 方法 | ||
| // Step1のコードを読みやすくしてみる | ||
| // 他の人のコードを2つは読んでみること | ||
| // 正解したら終わり | ||
|
|
||
| // 以下をメモに残すこと | ||
| // 講師陣はどのようなコメントを残すだろうか? | ||
| // 他の人のコードを読んで考えたこと | ||
| // 改善する時に考えたこと | ||
|
|
||
| /* | ||
| コメント集、他の人のコードを読んで考えたこと | ||
| https://discord.com/channels/1084280443945353267/1210494002277908491/1211368894669787226 | ||
| - Erase-remove idiom というものが関係あるらしい。 | ||
| https://en.wikipedia.org/wiki/Erase%E2%80%93remove_idiom | ||
| - 実装例 | ||
| https://cplusplus.com/reference/algorithm/remove/ | ||
| C++のstd::removeでは指定された値を取り除くのにポインタによる操作を行っている。 | ||
| - 配列先頭のポインタfirst、配列末尾のポインタlast、削除対象の値valを引数に取っている。 | ||
| - result=firstとして同じアドレス位置を保持しておく。 | ||
| - firstがlastと等しくなるまでループを続ける。 | ||
| - firstポインタのアドレス位置に入っている値と、削除対象の値が等しくない時 | ||
| - resultとfirstのアドレスが異なるとき | ||
| - resultのアドレス位置にfirstのアドレス位置に入っている値を入れる。 | ||
| - resultのアドレス位置を次の位置にインクリメント | ||
| - firstのアドレス位置を次の位置にインクリメント | ||
| - resultは削除対象のvalを除いた配列末尾のアドレスを指すポインタとして返される | ||
| - ForwaredIteratorはConceptというC++の機能らしい。 | ||
| https://cpprefjp.github.io/reference/iterator/forward_iterator.html | ||
| このアルゴリズムだと0を一回のループで取り除いた後に、元の配列の長さになるまで0をpush()すれば時間計算量がO(N)になると理解した。 | ||
|
|
||
| https://github.com/rihib/leetcode/pull/50#discussion_r1888189547 | ||
| > nums[zeroIndex], nums[i] = nums[i], nums[zeroIndex] | ||
| > これ C++ だと zeroIndex == i の場合は未定義動作にあたるかと思いますが、Go では大丈夫でしょうか。 | ||
| > この質問は、本当に不安に思っているというよりは、言語仕様を調べたことがありますか、それとも漫然と経験上書いていますか、という質問です。 | ||
| 自分はこのコードを読んで不安を感じることができなかった。配列から値を取り出して代入しているだけなので大丈夫なのではと感じた。 | ||
|
|
||
| https://github.com/fhiyo/leetcode/pull/54#discussion_r1729230640 | ||
| > まとめて 0 fill は、loop unrolling できたりするのでちょっと嬉しいこともあるでしょう。 | ||
| loop unrollingを初めて聞いた。手作業による書き換えやコンパイラの最適化によって、同じ処理内容ではあるが処理回数を削減すること。 | ||
| CPUのレジスタをより多く使う必要がある、展開後のコードの方が長くなるのでコードサイズが増加するなどのトレードオフが発生する。 | ||
| https://ja.wikipedia.org/wiki/%E3%83%AB%E3%83%BC%E3%83%97%E5%B1%95%E9%96%8B | ||
|
|
||
| https://github.com/Yoshiki-Iwasa/Arai60/pull/59/changes#diff-8201a9b64da970a353f0eb106023266ce67230b908a5213848bdfa1793d8574c | ||
| - Erase-remove idiomのRust実装例。retain(), resize()メソッドどちらも使ったことがなく新しいメソッドを知れた。 | ||
|
|
||
| https://github.com/naoto-iwase/leetcode/pull/55/changes#diff-781326e99985e6db2eab57d073695b257877a3871c5b21a5e284c0dd82038c5dR128 | ||
| - 0と0ではない値を入れ替える(swap)実装。この実装を行っている人が多い印象だった。 | ||
|
|
||
| 改善する時に考えたこと | ||
| - Vec::remove()ではなく、swapによる実装に変更して時間計算量をO(nums.len())に改善する | ||
|
|
||
| 所感 | ||
| - 少しパズルに感じる。step2a.rsでErase-remove idiomを試してみる。 | ||
| */ | ||
|
|
||
| pub struct Solution {} | ||
|
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. 自分が面接官としてこの問題を出題するとしたら、 Erase-remove idiom を知っていて書けるかどうかを主題とすると思います。 |
||
| impl Solution { | ||
| pub fn move_zeroes(nums: &mut Vec<i32>) { | ||
| let mut swap_target_index = 0; | ||
|
|
||
| for i in 0..nums.len() { | ||
| if nums[i] != 0 { | ||
| nums.swap(i, swap_target_index); | ||
| swap_target_index += 1; | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn step2_test() { | ||
| let mut before_nums = vec![0, 1, 0, 3, 12]; | ||
| let after_nums = vec![1, 3, 12, 0, 0]; | ||
| Solution::move_zeroes(&mut before_nums); | ||
| assert_eq!(before_nums, after_nums); | ||
|
|
||
| let mut before_nums = vec![0]; | ||
| let after_nums = vec![0]; | ||
| Solution::move_zeroes(&mut before_nums); | ||
| assert_eq!(before_nums, after_nums); | ||
|
|
||
| let mut before_nums = vec![0, 0, 1]; | ||
| let after_nums = vec![1, 0, 0]; | ||
| Solution::move_zeroes(&mut before_nums); | ||
| assert_eq!(before_nums, after_nums); | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| // Step2a | ||
| // 目的: Erase-remove idiomの考え方で実装してみる。 | ||
|
|
||
| // 方法 | ||
| // Step1のコードを読みやすくしてみる | ||
| // 他の人のコードを2つは読んでみること | ||
| // 正解したら終わり | ||
|
|
||
| // 以下をメモに残すこと | ||
| // 講師陣はどのようなコメントを残すだろうか? | ||
| // 他の人のコードを読んで考えたこと | ||
| // 改善する時に考えたこと | ||
|
|
||
| /* | ||
| https://github.com/Yoshiki-Iwasa/Arai60/pull/59/changes#diff-8201a9b64da970a353f0eb106023266ce67230b908a5213848bdfa1793d8574c | ||
| - Erase-remove idiomのRust実装例。retain(), resize()メソッドどちらも使ったことがなく新しいメソッドを知れた。 | ||
|
|
||
| 所感 | ||
| - シンプルな考え方で一番わかりやすい。 | ||
| - 配列の順序を維持したまま0を取り除く。 | ||
| - 変更前の配列のサイズに等しくなるように配列末尾を0で埋める。 | ||
| - retainの実装(retain_mutを呼び出している)を少し読んだが、想定以上に長い実装だった。 | ||
| - 標準ライブラリで要求される効率性と安全性を担保しながら、配列をin-placeで読み書きするのは大変なんだなと思った。 | ||
| https://doc.rust-lang.org/nightly/src/alloc/vec/mod.rs.html#2432 | ||
| */ | ||
|
|
||
| pub struct Solution {} | ||
| impl Solution { | ||
| pub fn move_zeroes(nums: &mut Vec<i32>) { | ||
| let original_len = nums.len(); | ||
| // predicateに一致する値のみにする。0でない値を残す。 | ||
| nums.retain(|v| *v != 0); | ||
| // 元のサイズと同じになるように0を追加する。 | ||
| nums.resize(original_len, 0); | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn step2a_test() { | ||
| let mut before_nums = vec![0, 1, 0, 3, 12]; | ||
| let after_nums = vec![1, 3, 12, 0, 0]; | ||
| Solution::move_zeroes(&mut before_nums); | ||
| assert_eq!(before_nums, after_nums); | ||
|
|
||
| let mut before_nums = vec![0]; | ||
| let after_nums = vec![0]; | ||
| Solution::move_zeroes(&mut before_nums); | ||
| assert_eq!(before_nums, after_nums); | ||
|
|
||
| let mut before_nums = vec![0, 0, 1]; | ||
| let after_nums = vec![1, 0, 0]; | ||
| Solution::move_zeroes(&mut before_nums); | ||
| assert_eq!(before_nums, after_nums); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| // Step3 | ||
| // 目的: 覚えられないのは、なんか素直じゃないはずなので、そこを探し、ゴールに到達する | ||
|
|
||
| // 方法 | ||
| // 時間を測りながらもう一度解く | ||
| // 10分以内に一度もエラーを吐かず正解 | ||
| // これを3回連続でできたら終わり | ||
| // レビューを受ける | ||
| // 作れないデータ構造があった場合は別途自作すること | ||
|
|
||
| /* | ||
| n = nums.len() | ||
| 時間計算量: O(n) | ||
| 空間計算量: O(1) | ||
| */ | ||
|
|
||
| /* | ||
| 1回目: 1分14秒 | ||
| 2回目: 0分35秒 | ||
| 3回目: 0分33秒 | ||
| */ | ||
|
|
||
| pub struct Solution {} | ||
| impl Solution { | ||
| pub fn move_zeroes(nums: &mut Vec<i32>) { | ||
| let original_len = nums.len(); | ||
| nums.retain(|v| *v != 0); | ||
| nums.resize(original_len, 0); | ||
| } | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
|
|
||
| #[test] | ||
| fn step3_test() { | ||
| let mut before_nums = vec![0, 1, 0, 3, 12]; | ||
| let after_nums = vec![1, 3, 12, 0, 0]; | ||
| Solution::move_zeroes(&mut before_nums); | ||
| assert_eq!(before_nums, after_nums); | ||
|
|
||
| let mut before_nums = vec![0]; | ||
| let after_nums = vec![0]; | ||
| Solution::move_zeroes(&mut before_nums); | ||
| assert_eq!(before_nums, after_nums); | ||
|
|
||
| let mut before_nums = vec![0, 0, 1]; | ||
| let after_nums = vec![1, 0, 0]; | ||
| Solution::move_zeroes(&mut before_nums); | ||
| assert_eq!(before_nums, after_nums); | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
(してそうですが)新しいメソッドをみたら一応見ておきましょう。
https://doc.rust-lang.org/std/vec/struct.Vec.html#method.retain
https://doc.rust-lang.org/std/vec/struct.Vec.html#method.resize