-
Notifications
You must be signed in to change notification settings - Fork 0
153. Find Minimum in Rotated Sorted Array #39
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
c8b7cbc
dacfa19
0403a03
339b453
1d71627
7dffa1e
8e7ca39
a604453
cd908f5
0c50204
683d2b2
3c22475
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,157 @@ | ||
| # 153. Find Minimum in Rotated Sorted Array | ||
|
|
||
| LeetCode URL: https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/description/ | ||
|
|
||
| この問題は Java で解いています。 | ||
| 各解法において、メソッドが属するクラスとして `Solution` を定義していますが、これは Java の言語仕様に従い、コードを実行可能にするために必要なものです。このクラス自体には特定の意味はなく、単にメソッドを組織化し、実行可能にするためのものです。 | ||
|
|
||
| ## Step 1 | ||
|
|
||
| 答えを知っていたので書けはしたのですが、手癖ではなく充分な理解を持った上で解けているか自信がないので、この解法に対する理解を以下に書き出します。フィードバックいただけますと嬉しいです。 | ||
|
|
||
| - 閉区間で二分探索を行い、最小の値から始まる範囲とそうでない範囲の境目を探す | ||
| - 例えば `[3,4,5,1,2]` の場合、最小の値から始まる範囲に属する値を T 、そうでないものを F とすると `[F, F, F, T, T]` となるが、この T の中で一番左側にあるものを探していくイメージ | ||
|
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. これの意図として、仮に先頭が最小だった場合は、全部 T ですかね? 下の方の条件との関係では、そうなのだとしたら、一番うしろとの比較になりそうです。 あと、nums が空だったときはどうなるかも一応考えておきますか。
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.
はい、そうです。
確かにそうですね。改めて読み返すと Step 2 の右端の値を用いて比較を行うパターンの説明として書かれていた方がしっくり来るように思いました。 より適切な説明にするため、12行目と13行目をまとめて次の文にしようかと考えたのですが、違和感ありませんでしょうか。
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.
次のように配列のチェックを実装し、Javadoc も記載してみました。 import org.apache.commons.lang3.ArrayUtils;
class Solution {
/**
* Find minimum value in rotated sorted array.
* If the array is not sorted, the results are undefined.
*/
public int findMin(int[] nums) {
if (ArrayUtils.isEmpty(nums)) {
throw new IllegalArgumentException("Argument nums must not be empty");
}
int left = 0, right = nums.length - 1;
while (left < right) {
int middle = left + (right - left) / 2;
if (nums[middle] <= nums[right]) {
right = middle;
} else {
left = middle + 1;
}
}
return nums[left];
}
}Step 4 に残しています。 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.
「最小の値を探す」ならともかく、日本語としてあまり自然だとは思いませんが、書くならば入力がどのようなものであるかの制限から丁寧に書かないと伝わらないでしょう。
空かどうかの判定は、素直に .length 使ったほうがいいのではないでしょうか。 あ、いや、どっちかというとこの話をしている理由は、二分探索が回るための条件などを考えていると、自然と気になりそうだと思ったんですね。
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.
ありがとうございます。
次のようなイメージでしょうか。 if (nums == null || nums.length == 0) {
throw new IllegalArgumentException("Argument nums must not be empty");
}元のコードは ArrayUtils.isEmpty() の仕様を知らないと処理内容、特に null チェックも行っているという点を推測するのが難しそうなので、確かにこちらの方が素直でわかりやすい実装に思いました。
すいません、気にならなかったわけではないのですがプルリクエストには書き漏らしてしまっていました。今後ちゃんと書くように気をつけます。いつもご指摘ありがとうございます。 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. ArrayUtils.isEmpty は周りで使われているか次第だと思います。 |
||
| - 各イテレーションで探索範囲の中央 (以下 middle) を確認し、次のどちらかの処理を行う: | ||
| - middle の位置にある値が right の位置にある値よりも小さい場合、最小の値はそこかそれよりも左の位置にあるため、right を middle の位置に移動させる | ||
| - 上の条件に当てはまらない場合、最小の値は middle よりも右の位置にあるため、middle のひとつ右の位置に left を移動させる | ||
| - 各ポインタは以下示しているため、同じ位置を指したら即ちその位置に存在する値が最小の値であると判断する: | ||
| - left: これが指す位置よりも左には最小の値が存在しないことを示す | ||
| - right: これが指す位置にある値が、最小の値かそれよりも右に存在するものであることを示す | ||
|
Comment on lines
+14
to
+19
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. これ説明の順序として制約から出てきて欲しい気がしますね。
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. @oda
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. ありがとうございます。 いや、実は違和感が払拭されていないのですが、しかし、このまま文章を生成され続けていたとしても解消されない気がしています。 どのあたりに違和感を感じているのか、なんですが、まず 「2で割る処理がありますがこれは切り捨てでも切り上げでも構わないのでしょうか。」 これ、組み合わせて16通りのソースコードが生成できますが、どれが動いてどれが動かないか答えられますか。
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. @oda
上記に対する返答としてはこれだけですが、実は全パターン試し、それぞれの結果について考えていました。その中で大事だと思ったものを書き出しておきます。
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. ありがとうございます。これが答えられるならば、少なくとも正しいモデルにはなってそうですね。 違和感の原因をさぐったところ「意味と操作がごちゃごちゃになっていて、自分が書いていないソースコードを日本語に変えたように見える」ということかなと思いました。 ただ、全体から違和感が出ていて、 「切り捨てているので、left <= midle < right」は今回のような協会の表現の仕方をするならば大事な情報なんですがないとか。
これ、境界の表現の仕方が色々あるでしょうから、そこはっきりさせないと閉区間といわれてもと思います。 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. 補足すると、目的を設定し、目的に必要な手段を決め、手段を粒度の大きい部分から小さい部分に向かって検討していく、という思考ができていないように感じました。また、粒度の大きい部分を、木構造のように再帰的に小さい部分に分割して思考するということもできていないように感じました。この辺りを意識しながら思考の仕方を改善されることをおすすめいたします。 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. そういうわけで閉区間というような専門用語によって、分かっていないのか伝わらないのかを迷うんですかねえ。 他に、自主性みたいなものがないようには思っていて、変数の意味は書いた人が決めるんですよ。
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. すいません、返信が大変遅くなりました。
ご指摘ありがとうございます。引き続きこれら意識して取り組んでいきます。
ご指摘ありがとうございます。仰るとおりだと思います。
こちらも仰るとおりだと思います。全体通してこの傾向があるので引き続き改善できるように意識して取り組んで行こうと思います。 |
||
|
|
||
| ```java | ||
| /** | ||
| * 時間計算量: O(log n) | ||
| * 空間計算量: O(1) | ||
| */ | ||
| class Solution { | ||
| public int findMin(int[] nums) { | ||
| int left = 0, right = nums.length - 1; | ||
| while (left < right) { | ||
| int middle = left + (right - left) / 2; | ||
| if (nums[middle] <= nums[right]) { | ||
| right = middle; | ||
| } else { | ||
| left = middle + 1; | ||
| } | ||
| } | ||
| return nums[left]; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Step 2 | ||
|
|
||
| ### 右端の値を用いて比較を行うパターン | ||
|
|
||
| 何人か他の方が書かれていたので書いてみました。 | ||
| 右端の値が、最小の値かそれよりも右にあるいずれかの値であることを利用した条件判定により二分探索を行います。 | ||
|
|
||
| ```java | ||
| class Solution { | ||
| public int findMin(int[] nums) { | ||
| int left = 0, right = nums.length - 1; | ||
| while (left < right) { | ||
| int middle = left + (right - left) / 2; | ||
| if (nums[middle] <= nums[nums.length - 1]) { | ||
| right = middle; | ||
| } else { | ||
| left = middle + 1; | ||
| } | ||
| } | ||
| return nums[left]; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### While 文終了前に return させるパターン | ||
|
|
||
| Step 1 の解法の処理効率向上のため、最小の値が存在する位置が見つかったらその時点で return させるよう修正します。 | ||
|
|
||
| ```java | ||
| /** | ||
| * 時間計算量: O(log n) | ||
| * 空間計算量: O(1) | ||
| */ | ||
| class Solution { | ||
| public int findMin(int[] nums) { | ||
| int left = 0, right = nums.length - 1; | ||
| while (left < right) { | ||
| if (nums[left] <= nums[right]) { | ||
| return nums[left]; | ||
| } | ||
|
|
||
| int middle = left + (right - left) / 2; | ||
| if (nums[middle] <= nums[right]) { | ||
| right = middle; | ||
| } else { | ||
| left = middle + 1; | ||
| } | ||
| } | ||
| return nums[left]; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Step 3 | ||
|
|
||
| 処理効率の良さで while 文終了前に return させるパターンを選びました。 | ||
| 好みかもしれませんが、右端の値を用いて比較を行うパターンよりも直感的にも思えます。 | ||
|
|
||
| ```java | ||
| /** | ||
| * 時間計算量: O(log n) | ||
| * 空間計算量: O(1) | ||
| */ | ||
| class Solution { | ||
| public int findMin(int[] nums) { | ||
| int left = 0, right = nums.length - 1; | ||
| while (left < right) { | ||
| if (nums[left] < nums[right]) { | ||
| return nums[left]; | ||
| } | ||
|
|
||
| int middle = left + (right - left) / 2; | ||
| if (nums[middle] <= nums[right]) { | ||
| right = middle; | ||
| } else { | ||
| left = middle + 1; | ||
| } | ||
| } | ||
| return nums[left]; | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ## Step 4 | ||
|
|
||
| ### 引数のチェックを行う | ||
|
|
||
| [oda さんの指摘](https://github.com/seal-azarashi/leetcode/pull/39/files#r1846154143)を受けて不正な引数が渡されることを考慮した実装を用意しました。 | ||
| Leetcode では使えないですが、The Apache Commons Lang 3 library の [ArrayUtils.isEmpty()](https://commons.apache.org/proper/commons-lang/javadocs/api-3.6/index.html?org/apache/commons/lang3/ArrayUtils.html) を使って配列が null ないし空でないかチェックしています。加えて、ソートされていなければ返す値が正しい保証もないことをコメントに追記しました。 | ||
|
|
||
| ```java | ||
| import org.apache.commons.lang3.ArrayUtils; | ||
|
|
||
| class Solution { | ||
| /** | ||
| * Find minimum value in rotated sorted array. | ||
| * If the array is not sorted, the results are undefined. | ||
| */ | ||
| public int findMin(int[] nums) { | ||
| if (ArrayUtils.isEmpty(nums)) { | ||
| throw new IllegalArgumentException("Argument nums must not be empty"); | ||
| } | ||
|
|
||
| int left = 0, right = nums.length - 1; | ||
| while (left < right) { | ||
| int middle = left + (right - left) / 2; | ||
| if (nums[middle] <= nums[right]) { | ||
| right = middle; | ||
| } else { | ||
| left = middle + 1; | ||
| } | ||
| } | ||
| return nums[left]; | ||
| } | ||
| } | ||
| ``` | ||
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.
合っていると思います。
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.
ありがとうございます!