-
Notifications
You must be signed in to change notification settings - Fork 0
287. find the duplicate number #3
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,163 @@ | ||
| # 287. find-the-duplicate-number | ||
|
|
||
| https://leetcode.com/problems/find-the-duplicate-number/description/ | ||
|
|
||
| ## Comments | ||
| 09:32 | ||
| 空間計算量がO(1)であることがめっちゃだるそう。配列の値をそのまま使う。。。? | ||
| 2分探索ならうまくいくのかなぁ。 | ||
| 時間計算量はO(nlogn)になって実行可能ではありそう。 | ||
| 空間計算量はO(1)になる。 | ||
|
|
||
| 具体的な二分探索方法 | ||
| 1-n/2の数が、n/2 + 1個あるなら、前半側の数字に重複がある。 | ||
| 逆もしかり。 | ||
|
|
||
| 1 - n/4の数が、n/4 + 1個あるなら、前半側の数字に重複がある。 | ||
| を繰り返す。 | ||
|
|
||
| のかなぁ。 | ||
| 再帰でやる?itereationでやる? | ||
| iterationでやると、while文の中で配列の値を使うことになるので、ちょっとだるい。 | ||
| 再帰でやるなら、回数を継続していきたい。どうやって引数に渡すのか。 | ||
| whileで回すほうが楽か。 | ||
|
|
||
| ### step1 | ||
| ```c | ||
| // 1. 配列の値をそのまま使う | ||
| int findDuplicate(int* nums, int numsSize) | ||
| { | ||
| int i; | ||
| int first; | ||
|
|
||
| i = 0; | ||
| first = 0; | ||
| while (i < numsSize) | ||
| { | ||
| if (nums[i] < numsSize / 2) | ||
| first++; | ||
| else | ||
| first--; | ||
| i++; | ||
| } | ||
| if (first > 0) | ||
| { | ||
| // 前半側に重複がある | ||
| return findDuplicate(nums, numsSize / 2); | ||
| } | ||
| else | ||
| { | ||
| // 後半側に重複がある | ||
| return findDuplicate(nums + numsSize / 2, numsSize - numsSize / 2); | ||
| } | ||
| } | ||
|
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. 再帰の場合に気になるのはどんな条件の時に終了して再帰を抜けてくか、です。ぱっとこのコードを見たときにもこれ、再帰の終了条件はどこだ?と迷いました。 |
||
| ``` | ||
| * | ||
| うーんnumSizeは固定にしたい。。。 | ||
| Static変数にして、再帰のたびにnumsSizeを渡すのはどうだろう。 | ||
|
|
||
| ### step2 | ||
| ```c | ||
| // 1. 配列の値をそのまま使う | ||
| int findDuplicate(int* nums, int numsSize) | ||
| { | ||
| int i; | ||
| int first; | ||
| static int numSize_copy = numsSize; | ||
|
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. まだstatic変数を使う意図をつかめていないのですが、static変数は普通の変数とは違い静的領域に場所が確保されます。なのでそれを再帰で使う場合、何度も何度も同じ関数を再帰している間に、その再帰全体から自由にアクセスできるある種のグローバル変数がほしいって感じでしょうか? |
||
|
|
||
| i = 0; | ||
| first = 0; | ||
|
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. firstという命名の意図が若干分かりづらい気はします。 |
||
| while (i < numsSize_copy) | ||
| { | ||
| if (nums[i] < numsSize / 2) | ||
| first++; | ||
| else | ||
| first--; | ||
| i++; | ||
| } | ||
| if (first > 0) | ||
| { | ||
| // 前半側に重複がある | ||
| return findDuplicate(nums, numsSize / 2); | ||
| } | ||
| else | ||
| { | ||
| // 後半側に重複がある | ||
| return findDuplicate(nums + numsSize / 2, numsSize - numsSize / 2); | ||
| } | ||
| } | ||
| ``` | ||
| * | ||
| いけんちゃうかなぁ。main関数を作成して、テストしてみよう。 | ||
|
|
||
| ```c | ||
| #include <stdio.h> | ||
|
|
||
| int main(void) | ||
| { | ||
| int nums[] = {1, 2, 3, 3}; | ||
| int numsSize = 4; | ||
|
|
||
| printf("%d\n", findDuplicate(nums, numsSize)); | ||
| return (0); | ||
| } | ||
| ``` | ||
| うごかんなぁ。 | ||
| セグフォがでる。 | ||
|
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. 再帰したときに nums が変わっているので、numsSize_copy までループを回しても動きませんね。 |
||
| static変数を仮引数で初期化するのはだめらしい。 | ||
| なんでなんやろう。 | ||
| 一旦固定値でやろう。 | ||
| やったけど無理そう。セグフォがでる。 | ||
| indexとかめんどくさいなぁ。やっぱwhileでやるほうが楽そう。 | ||
| while文に変更しよう。 | ||
| ### step3 | ||
| ```c | ||
|
|
||
| int findDuplicate(int *nums, int numsSize) | ||
| { | ||
| int left; | ||
| int mid; | ||
| int right; | ||
| int i; | ||
| int count; | ||
|
|
||
| left = 0; | ||
| right = numsSize - 1; | ||
| while (left < right) | ||
| { | ||
| mid = (left + right) / 2; | ||
| count = 0; | ||
| i = 0; | ||
| while (i < numsSize) | ||
| { | ||
| if (nums[i] <= mid) | ||
| count++; | ||
| i++; | ||
| } | ||
| if (count > mid) | ||
| right = mid; | ||
| else | ||
| left = mid + 1; | ||
| } | ||
| return (left); | ||
| } | ||
|
|
||
| #include <stdio.h> | ||
|
|
||
| int main(void) | ||
| { | ||
| int nums[] = {1, 2, 4, 5, 3, 2}; | ||
| int numsSize = 6; | ||
|
|
||
| printf("%d\n", findDuplicate(nums, numsSize)); | ||
| return (0); | ||
| } | ||
|
|
||
| ``` | ||
| めっちゃきれいに実装できた。 | ||
|
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. はい、このコードを、自然言語で説明してくれませんか。 |
||
| mainのテスト何個か試しても行けた | ||
| 行けてそう!! | ||
|  | ||
| いけた!! | ||
| なんかめちゃ早の人たちいる。 | ||
|
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. フロイドのうさぎとかめといわれるアルゴリズムを応用した方法がありますね。 この配列を「ゲームブック」だと思いましょう。 まず、0ページ目に戻ってくることはありません。 そうすると、0から開始して、このゲームブックを進めていくと、あるところから循環が始まるということです。その循環の開始点は0ではないことから、「(循環開始の)ページに行け」と書かれたページが少なくとも2つあったことを示しています。 これはフロイドのアルゴリズムで解けます。 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. |
||
| 何なんやろ。 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| /* ************************************************************************** */ | ||
| /* */ | ||
| /* ::: :::::::: */ | ||
| /* step1.c :+: :+: :+: */ | ||
| /* +:+ +:+ +:+ */ | ||
| /* By: kjikuhar <kjikuhar@student.42tokyo.jp> +#+ +:+ +#+ */ | ||
| /* +#+#+#+#+#+ +#+ */ | ||
| /* Created: 2025/06/02 09:47:39 by kjikuhar #+# #+# */ | ||
| /* Updated: 2025/06/02 09:55:16 by kjikuhar ### ########.fr */ | ||
| /* */ | ||
| /* ************************************************************************** */ | ||
|
|
||
| // 1. 配列の値をそのまま使う | ||
| int findDuplicate(int* nums, int numsSize) | ||
| { | ||
| int i; | ||
| int first; | ||
| static int numsSize_copy = 4; | ||
|
|
||
| i = 0; | ||
| first = 0; | ||
| while (i < numsSize_copy) | ||
| { | ||
| if (nums[i] < numsSize / 2) | ||
| first++; | ||
| else | ||
| first--; | ||
| i++; | ||
| } | ||
| if (first > 0) | ||
| { | ||
| // 前半側に重複がある | ||
| return findDuplicate(nums, numsSize / 2); | ||
| } | ||
| else | ||
| { | ||
| // 後半側に重複がある | ||
| return findDuplicate(nums, numsSize - numsSize / 2); | ||
| } | ||
| } | ||
|
|
||
| #include <stdio.h> | ||
|
|
||
| int main(void) | ||
| { | ||
| int nums[] = {1, 2, 3, 3}; | ||
| int numsSize = 4; | ||
|
|
||
| printf("%d\n", findDuplicate(nums, numsSize)); | ||
| return (0); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| /* ************************************************************************** */ | ||
| /* */ | ||
| /* ::: :::::::: */ | ||
| /* step2.c :+: :+: :+: */ | ||
| /* +:+ +:+ +:+ */ | ||
| /* By: kjikuhar <kjikuhar@student.42tokyo.jp> +#+ +:+ +#+ */ | ||
| /* +#+#+#+#+#+ +#+ */ | ||
| /* Created: 2025/06/02 09:47:39 by kjikuhar #+# #+# */ | ||
| /* Updated: 2025/06/02 14:19:49 by kjikuhar ### ########.fr */ | ||
| /* */ | ||
| /* ************************************************************************** */ | ||
|
|
||
|
|
||
| int findDuplicate(int *nums, int numsSize) | ||
| { | ||
| int left; | ||
| int mid; | ||
| int right; | ||
| int i; | ||
| int count; | ||
|
|
||
| left = 0; | ||
| right = numsSize - 1; | ||
| while (left < right) | ||
| { | ||
| mid = (left + right) / 2; | ||
| count = 0; | ||
| i = 0; | ||
| while (i < numsSize) | ||
| { | ||
| if (nums[i] <= mid) | ||
| count++; | ||
| i++; | ||
| } | ||
| if (count > mid) | ||
| right = mid; | ||
| else | ||
| left = mid + 1; | ||
| } | ||
| return (left); | ||
| } | ||
|
|
||
| #include <stdio.h> | ||
|
|
||
| int main(void) | ||
| { | ||
| int nums[] = {1, 2, 4, 5, 3, 2}; | ||
| int numsSize = 6; | ||
|
|
||
| printf("%d\n", findDuplicate(nums, numsSize)); | ||
| return (0); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| /* ************************************************************************** */ | ||
| /* */ | ||
| /* ::: :::::::: */ | ||
| /* step3.c :+: :+: :+: */ | ||
| /* +:+ +:+ +:+ */ | ||
| /* By: kjikuhar <kjikuhar@student.42tokyo.jp> +#+ +:+ +#+ */ | ||
| /* +#+#+#+#+#+ +#+ */ | ||
| /* Created: 2025/06/02 15:04:50 by kjikuhar #+# #+# */ | ||
| /* Updated: 2025/06/02 15:16:38 by kjikuhar ### ########.fr */ | ||
| /* */ | ||
| /* ************************************************************************** */ | ||
|
|
||
| // Floyd's Toroise & Hare algorithm | ||
| // Cycle detection | ||
|
|
||
| int findDuplicate(int* nums, int n) | ||
| { | ||
| int tortoize; | ||
| int hare; | ||
|
|
||
| tortoize = 0; | ||
| hare = 0; | ||
| while (1) | ||
| { | ||
| tortoize = nums[tortoize]; | ||
| hare = nums[nums[hare]]; | ||
| if (tortoize == hare) | ||
| break ; | ||
| } | ||
| tortoize = 0; | ||
| while (1) | ||
| { | ||
| tortoize = nums[tortoize]; | ||
| hare = nums[hare]; | ||
| if (tortoize == hare) | ||
| break ; | ||
| } | ||
| return (hare); | ||
| } | ||
|
|
||
|
|
||
| #include <stdio.h> | ||
|
|
||
| int main(void) | ||
| { | ||
| int nums[] = {3, 1, 3, 4, 2}; | ||
| int numsSize = 5; | ||
|
|
||
| printf("%d\n", findDuplicate(nums, numsSize)); | ||
| return (0); | ||
| } |
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.
この問題を見て真っ先に二分探索を着想するのはすごいですね!自分は思いつかなかったです。