From e885fdc28d73ddc92af3abd702b5ecaf8826f659 Mon Sep 17 00:00:00 2001 From: Ryotaro Kurita Date: Tue, 3 Dec 2024 18:28:31 +0900 Subject: [PATCH 1/6] finish --- 35.SearchInsertPosition/for.cpp | 11 ++++++ 35.SearchInsertPosition/memo.md | 63 +++++++++++++++++++++++++++++++ 35.SearchInsertPosition/step1.cpp | 24 ++++++++++++ 35.SearchInsertPosition/step2.cpp | 23 +++++++++++ 35.SearchInsertPosition/step3.cpp | 23 +++++++++++ 35.SearchInsertPosition/while.cpp | 23 +++++++++++ 6 files changed, 167 insertions(+) create mode 100644 35.SearchInsertPosition/for.cpp create mode 100644 35.SearchInsertPosition/memo.md create mode 100644 35.SearchInsertPosition/step1.cpp create mode 100644 35.SearchInsertPosition/step2.cpp create mode 100644 35.SearchInsertPosition/step3.cpp create mode 100644 35.SearchInsertPosition/while.cpp diff --git a/35.SearchInsertPosition/for.cpp b/35.SearchInsertPosition/for.cpp new file mode 100644 index 0000000..5fbb617 --- /dev/null +++ b/35.SearchInsertPosition/for.cpp @@ -0,0 +1,11 @@ +class Solution { +public: + int searchInsert(vector& nums, int target) { + for (int i = 0; i < nums.size(); i++) { + if (nums[i] >= target) { + return i; + } + } + return nums.size(); + } +}; diff --git a/35.SearchInsertPosition/memo.md b/35.SearchInsertPosition/memo.md new file mode 100644 index 0000000..9aedf95 --- /dev/null +++ b/35.SearchInsertPosition/memo.md @@ -0,0 +1,63 @@ +## ステップ1 +制約にO(log n)とあったので思いついたのは、バイナリーサーチツリーを用いた +探索した結果端に辿り着いた場合の処理に時間がかかった +acceptまで34分 +制約がなければforループO(n)で実装していた + +時間計算量 +O (log n) +空間計算量 +O(1) + +## ステップ2 +elseを使った方がスッキリしそう +・forループバージョンでも念の為書いてみた。すごくシンプルに書けるしLeetCode上でもacceptされた +・whileループバージョンでも書いてみた。 + +命名について +start endが個人的にしっくりきているが、right leftとどっちがいいのだろう +調べていたhighとlowも出てきた。middleを使うならこれが英語的にしっくりきそう。 + +left < right VS left <= rightはどちらも間違いではない +要素数が偶数の場合、前者は2つの真ん中の左側、後者は右側がmiddleとなる +>From a readability perspective, it might be slightly better (in my opinion) to use the exclusive one in languages with 0-based arrays and either one in languages with 1-based arrays, in order to minimise the number of -1's in the code. An argument could also be made to just stick to a single version in all languages, as to not require that people understand both versions or get confused between the two. +チーム間で決めておくことなのかな。 +https://stackoverflow.com/questions/44231413/binary-search-using-start-end-vs-using-start-end + +## ステップ3 +**3回書き直しやりましょう、といっているのは、不自然なところや負荷の高いところは覚えられないからです。** + +## 他の方の解法 +自分は再帰で書いたけど、わざわざ再帰を使わずwhileで処理可能 +https://github.com/Mike0121/LeetCode/pull/43 + +>CPU 周りでぱっと目に付いた単語はこんな感じなのですが、 +パイプライン +スーパースカラー +マイクロアーキテクチャ +命令セット +マイクロコード +レジスタ +実行ユニット +キャッシュメモリ +アウトオブオーダー +マルチコア +同時マルチスレッディング +スループット +常識の範囲のようなので要チェック +https://github.com/Yoshiki-Iwasa/Arai60/pull/34 + +>課題の制約でnums contains distinct values sorted in ascending order.とあるので問題ないですが、たとえばnums = [3, 3, 3, 3], target = 3の場合とかの答えが違うくないですか? +middleを使わないforループの探索だとこの左端が回答となってしまう。。。ので今回はたまたまacceptされただけか + +>条件を満たすものを1つ探している場合、 +>条件を満たすもののうち左端を探している場合、 +>条件を満たすところと満たさないところの切れ目を探している場合(上とほぼ同じ)、 +>あと、閉区間か、開閉区間か、などがあって、これは、「条件を満たすもののうち左端を探している場合に満たすものを1つ見つかったら中止するコードがついた」 +この辺りの目線はなかった。 +今回はたまたまnumsがユニークであったので問題が無かったが実際は要件定義必須 +https://github.com/fhiyo/leetcode/pull/42 +https://github.com/sakupan102/arai60-practice/pull/42 + +## Discordなど + diff --git a/35.SearchInsertPosition/step1.cpp b/35.SearchInsertPosition/step1.cpp new file mode 100644 index 0000000..cd930a7 --- /dev/null +++ b/35.SearchInsertPosition/step1.cpp @@ -0,0 +1,24 @@ +class Solution { +public: + int searchInsert(vector& nums, int target) { + return SearchInsertIndex(0, nums.size() - 1, nums, target); + } + +private: + int SearchInsertIndex(int start, int end, vector& nums, int target) { + // 端にいってしまった場合の処理 + if (start > end) { + return start; + } + int middle = (start + end) / 2; + if (nums[middle] == target) { + return middle; + } + + if (nums[middle] < target) { + return SearchInsertIndex(middle + 1, end, nums, target); + } + + return SearchInsertIndex(start, middle - 1, nums, target); + } +}; diff --git a/35.SearchInsertPosition/step2.cpp b/35.SearchInsertPosition/step2.cpp new file mode 100644 index 0000000..4cf806f --- /dev/null +++ b/35.SearchInsertPosition/step2.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + int searchInsert(vector& nums, int target) { + return SearchInsertIndex(0, nums.size() - 1, nums, target); + } + +private: + int SearchInsertIndex(int start, int end, vector& nums, int target) { + if (start > end) { + return start; + } + int middle = (start + end) / 2; + if (nums[middle] == target) { + return middle; + } + + if (nums[middle] < target) { + return SearchInsertIndex(middle + 1, end, nums, target); + } else { + return SearchInsertIndex(start, middle - 1, nums, target); + } + } +}; diff --git a/35.SearchInsertPosition/step3.cpp b/35.SearchInsertPosition/step3.cpp new file mode 100644 index 0000000..4cf806f --- /dev/null +++ b/35.SearchInsertPosition/step3.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + int searchInsert(vector& nums, int target) { + return SearchInsertIndex(0, nums.size() - 1, nums, target); + } + +private: + int SearchInsertIndex(int start, int end, vector& nums, int target) { + if (start > end) { + return start; + } + int middle = (start + end) / 2; + if (nums[middle] == target) { + return middle; + } + + if (nums[middle] < target) { + return SearchInsertIndex(middle + 1, end, nums, target); + } else { + return SearchInsertIndex(start, middle - 1, nums, target); + } + } +}; diff --git a/35.SearchInsertPosition/while.cpp b/35.SearchInsertPosition/while.cpp new file mode 100644 index 0000000..3e31e29 --- /dev/null +++ b/35.SearchInsertPosition/while.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + int searchInsert(vector& nums, int target) { + int start = 0; + int end = nums.size(); + + while (start < end) { + int middle = (start + end) / 2; + + if (nums[middle] == target) { + return middle; + } + if (nums[middle] < target) { + start++; + } + if (nums[middle] > target) { + end = middle; + } + } + + return end; + } +}; From 2804e3ac63d2603f37288f258243cbe74a5639e0 Mon Sep 17 00:00:00 2001 From: Ryotaro Kurita Date: Tue, 10 Dec 2024 22:26:11 +0900 Subject: [PATCH 2/6] mod --- 35.SearchInsertPosition/while_step2.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 35.SearchInsertPosition/while_step2.cpp diff --git a/35.SearchInsertPosition/while_step2.cpp b/35.SearchInsertPosition/while_step2.cpp new file mode 100644 index 0000000..b4eac53 --- /dev/null +++ b/35.SearchInsertPosition/while_step2.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + int searchInsert(vector& nums, int target) { + int start = 0; + int end = nums.size(); + + while (start < end) { + int middle = (start + end) / 2; + + if (nums[middle] == target) { + return middle; + } + if (nums[middle] < target) { + start = middle + 1; + } + if (nums[middle] > target) { + end = middle; + } + } + + return end; + } +}; From 049a0f6f45700814724a8696ec4f9e57a126c431 Mon Sep 17 00:00:00 2001 From: Ryotaro Kurita Date: Tue, 17 Dec 2024 00:10:18 +0900 Subject: [PATCH 3/6] add steo4 --- 35.SearchInsertPosition/memo.md | 41 ++++++++++++++++++- 35.SearchInsertPosition/step4.cpp | 66 +++++++++++++++++++++++++++++++ 35.SearchInsertPosition/step5.cpp | 21 ++++++++++ 3 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 35.SearchInsertPosition/step4.cpp create mode 100644 35.SearchInsertPosition/step5.cpp diff --git a/35.SearchInsertPosition/memo.md b/35.SearchInsertPosition/memo.md index 9aedf95..4d31f1c 100644 --- a/35.SearchInsertPosition/memo.md +++ b/35.SearchInsertPosition/memo.md @@ -1,5 +1,7 @@ ## ステップ1 -制約にO(log n)とあったので思いついたのは、バイナリーサーチツリーを用いた +制約にO(log n)とあったので思いついたのは、~~バイナリーサーチツリー~~を用いた +※指摘があったため訂正(木構造は使っていない) + 探索した結果端に辿り着いた場合の処理に時間がかかった acceptまで34分 制約がなければforループO(n)で実装していた @@ -61,3 +63,40 @@ https://github.com/sakupan102/arai60-practice/pull/42 ## Discordなど +middleについれleet codeの解説より +>If left + right is greater than the maximum int value 2^31 −1, it overflows to a negative value. In Java, it would trigger an exception of ArrayIndexOutOfBoundsException, and in C++ it causes an illegal write, which leads to memory corruption and unpredictable results. + +## step4.cpp +### 閉区間 [start, end] +* 探索空間、初期値の設定 +start = 0、end = nums.size() - 1 + +* ループ終了条件 +start == end + +* 更新操作 +nums[middle] < targetがtrueの場合[middle + 1, end] +nums[middle] < targetがfalseの場合[start, middle] + +## 半開区間 [start, end) or (start, end] +[start, end)でstep5.cppに実装 +* 探索空間、初期値の設定 +start = 0, end = nums.size() + +* ループ終了条件 +start >= end + +* 更新操作 +nums[middle] < targetがtrueの場合[middle + 1, end] +nums[middle] < targetがfalseの場合[start, middle] +形で覚えるのではなく、下記の考え方を理解する +https://github.com/Yoshiki-Iwasa/Arai60/pull/35/commits/f279dd98a68111954a02344b20b47512ebffafc4#r1699552857 + + +>二分探索を、 [false, false, false, ..., false, true, true, ture, ..., true] と並んだ配列があったとき、 false と true の境界の位置を求める問題、または一番左の true の位置を求める問題と捉えているか? +>位置を求めるにあたり、答えが含まれる範囲を狭めていく問題と捉えているか? +>範囲を考えるにあたり、閉区間・開区間・半開区間の違いを理解できているか? +>用いた区間の種類に対し、適切な初期値を、理由を理解したうえで、設定できるか? +>用いた区間の種類に対し、適切なループ不変条件を、理由を理解したうえで、設定できるか? +>用いた区間の種類に対し、範囲を狭めるためのロジックを、理由を理解したうえで、適切に記述できるか? +https://discord.com/channels/1084280443945353267/1196498607977799853/1269532028819476562 diff --git a/35.SearchInsertPosition/step4.cpp b/35.SearchInsertPosition/step4.cpp new file mode 100644 index 0000000..37c5f38 --- /dev/null +++ b/35.SearchInsertPosition/step4.cpp @@ -0,0 +1,66 @@ +/* +1.問題のモデル化 +num[middle] < targetとなる区間をfalse、num[middle] >= targetとなる部分をtrueとすると +問題を2つ以上の相補的な状態に分類することができる。 + +2.探索空間の定義 +今回は閉区間として探索を行う。 + +3.初期値の設定 +startを0、endを配列の最後の要素nums.size() - 1として探索する。 +配列の全要素を探索するイメージ。 + +4.ループ不変条件の設定 +>閉区間の探索では、範囲が無効(start > end)になる前に終了するのが基本(chat gpt) +start~endの中に挿入位置が存在すること=閉区間である +start > endを終了条件にすると、探索の範囲が[2, 1]であったり[0, -1]のような状態となり +start~endの中に挿入位置が存在することと矛盾する + +5.探索ロジックの設計 +nums[mid] < targetがtrueなら、startをmiddle + 1に更新 +nums[mid] >= targetがtrueなら、endをmiddleに更新 + endをmiddle - 1に更新してしまうと、start > endが発生しうる + +6.検証 +・targetがnumsのいずれよりも小さい場合 + nums[middle] < targetが常にfalseとなり、startは最初の位置のままendが狭まりstartの位置が解となる + +・targetがnumsのいずれよりも大きい場合 + nums[middle] < targetが常にtrueとなり、startがendに近づきstart + 1 + +・targetが複数存在する場合 + 最小のインデックスを返却 + +7.実行 +leet codeにて動作確認 + +*/ +class Solution { +public: + int searchInsert(vector& nums, int target) { + return SearchInsertIndex(0, nums.size() - 1, nums, target); + } + +private: + int SearchInsertIndex(int start, int end, vector& nums, int target) { + if (start == end) { + if (nums[start] >= target) { + return start; + } else { + return start + 1; + } + } + int middle = start + (end - start) / 2; + // [2, 4, 4, 4, 6] target = 4の場合 + // 問題が最小のインデックスを探すであれば誤ってしまうので以下の部分は削除 + // if (nums[middle] == target) { + // return middle; + // } + + if (nums[middle] < target) { + return SearchInsertIndex(middle + 1, end, nums, target); + } else { + return SearchInsertIndex(start, middle, nums, target); + } + } +}; diff --git a/35.SearchInsertPosition/step5.cpp b/35.SearchInsertPosition/step5.cpp new file mode 100644 index 0000000..31afda4 --- /dev/null +++ b/35.SearchInsertPosition/step5.cpp @@ -0,0 +1,21 @@ +class Solution { +public: + int searchInsert(vector& nums, int target) { + return SearchInsertIndex(0, nums.size(), nums, target); + } + +private: + int SearchInsertIndex(int start, int end, vector& nums, int target) { + if (start >= end) { + return start; + } + int middle = start + (end - start) / 2; + + // 右側を狭める場合 + if (nums[middle] < target) { + return SearchInsertIndex(middle + 1, end, nums, target); + } else { + return SearchInsertIndex(start, middle, nums, target); + } + } +}; From f1f955ba2ee174fbee541c07be90d53323102607 Mon Sep 17 00:00:00 2001 From: Ryotaro Kurita Date: Wed, 18 Dec 2024 22:29:02 +0900 Subject: [PATCH 4/6] add step5 --- 35.SearchInsertPosition/step4.cpp | 19 +++++--------- 35.SearchInsertPosition/step5.cpp | 43 +++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/35.SearchInsertPosition/step4.cpp b/35.SearchInsertPosition/step4.cpp index 37c5f38..e8d23d8 100644 --- a/35.SearchInsertPosition/step4.cpp +++ b/35.SearchInsertPosition/step4.cpp @@ -1,7 +1,7 @@ /* 1.問題のモデル化 -num[middle] < targetとなる区間をfalse、num[middle] >= targetとなる部分をtrueとすると -問題を2つ以上の相補的な状態に分類することができる。 +ターゲットより大きいのか、以下なのか2つ以上の相補的な状態に分類することができるのでfalseとtrueの問題とみなす。 +記問題を解くにあたり、対象の位置を含む区間をstartからendとして定義する。 2.探索空間の定義 今回は閉区間として探索を行う。 @@ -11,15 +11,13 @@ startを0、endを配列の最後の要素nums.size() - 1として探索する 配列の全要素を探索するイメージ。 4.ループ不変条件の設定 ->閉区間の探索では、範囲が無効(start > end)になる前に終了するのが基本(chat gpt) -start~endの中に挿入位置が存在すること=閉区間である -start > endを終了条件にすると、探索の範囲が[2, 1]であったり[0, -1]のような状態となり -start~endの中に挿入位置が存在することと矛盾する +startとendの真ん中をmiddleとして、ループの普遍条件は +・start <= middle < end 5.探索ロジックの設計 nums[mid] < targetがtrueなら、startをmiddle + 1に更新 -nums[mid] >= targetがtrueなら、endをmiddleに更新 - endをmiddle - 1に更新してしまうと、start > endが発生しうる +nums[mid] >= target の場合、 mid の位置に対象がある場合があるため、 +区間を狭めつつ mid を区間内に含めるため、end = mid とする 6.検証 ・targetがnumsのいずれよりも小さい場合 @@ -51,11 +49,6 @@ class Solution { } } int middle = start + (end - start) / 2; - // [2, 4, 4, 4, 6] target = 4の場合 - // 問題が最小のインデックスを探すであれば誤ってしまうので以下の部分は削除 - // if (nums[middle] == target) { - // return middle; - // } if (nums[middle] < target) { return SearchInsertIndex(middle + 1, end, nums, target); diff --git a/35.SearchInsertPosition/step5.cpp b/35.SearchInsertPosition/step5.cpp index 31afda4..d442e3a 100644 --- a/35.SearchInsertPosition/step5.cpp +++ b/35.SearchInsertPosition/step5.cpp @@ -1,3 +1,42 @@ +/* +1.問題のモデル化 +ターゲットより大きいのか、以下なのか2つの状態に分類することができるのでtrueとfalseの問題とみなす。 +記問題を解くにあたり、対象の位置を含む区間をstartからendとして定義する。 + +2.探索空間の定義 +探索範囲を0からnとして、半開区間とみなし探索を行う。 +ターゲットより大きい場合をtrueとして[true)となる箇所を探す。 + +3.初期値の設定 +startを0、endをnums.size()として探索する。 + +4.ループ不変条件の設定 +startとendの真ん中をmiddleとして、ループの普遍条件は +・start <= middle < end +・start <= target < end + +5.探索ロジックの設計 +nums[middle] < targetがtrueであれば、middleより左側にtargetは存在しないので +startをmiddle + 1に更新 + +nums[middle] >= targetがtrueであれば、middleを含めmiddle以下のどこかにtargetは存在するので +ループ不変条件を守るように[start, middle)となるように範囲を狭める。 + +6.検証 +・targetがnumsのいずれよりも小さい場合 + nums[middle] < targetが常にfalseとなり、startは最初の位置のままendが狭まりstartの位置が解となる + +・targetがnumsのいずれよりも大きい場合 + nums[middle] < targetが常にtrueとなり、startがendに近づく、start <= target < endとなっているので + startの位置が解となる + +・targetが複数存在する場合 + 最小のインデックスを返却 + +7.実行 +leet codeにて動作確認 + +*/ class Solution { public: int searchInsert(vector& nums, int target) { @@ -6,15 +45,15 @@ class Solution { private: int SearchInsertIndex(int start, int end, vector& nums, int target) { - if (start >= end) { + if (start == end) { return start; } int middle = start + (end - start) / 2; - // 右側を狭める場合 if (nums[middle] < target) { return SearchInsertIndex(middle + 1, end, nums, target); } else { + // nums[middle] >= target return SearchInsertIndex(start, middle, nums, target); } } From 25ac1e8485350169457022d17d95f945f3c71685 Mon Sep 17 00:00:00 2001 From: Ryotaro Kurita Date: Wed, 18 Dec 2024 22:40:15 +0900 Subject: [PATCH 5/6] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=8F=8D=E6=98=A0?= =?UTF-8?q?=E3=82=82=E3=82=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 35.SearchInsertPosition/step4.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/35.SearchInsertPosition/step4.cpp b/35.SearchInsertPosition/step4.cpp index e8d23d8..0f708fb 100644 --- a/35.SearchInsertPosition/step4.cpp +++ b/35.SearchInsertPosition/step4.cpp @@ -15,7 +15,9 @@ startとendの真ん中をmiddleとして、ループの普遍条件は ・start <= middle < end 5.探索ロジックの設計 -nums[mid] < targetがtrueなら、startをmiddle + 1に更新 +nums[middle] < targetがtrueであれば、middleより左側にtargetは存在しないので +startをmiddle + 1に更新 + nums[mid] >= target の場合、 mid の位置に対象がある場合があるため、 区間を狭めつつ mid を区間内に含めるため、end = mid とする From 33fef01c7def837b8fed996429259fa5ea9702ae Mon Sep 17 00:00:00 2001 From: Ryotaro Kurita Date: Thu, 13 Feb 2025 00:24:13 +0900 Subject: [PATCH 6/6] mod comment and add solution using while_step3 --- 35.SearchInsertPosition/step4.cpp | 21 +++++---- 35.SearchInsertPosition/step5.cpp | 3 +- 35.SearchInsertPosition/while_step3.cpp | 61 +++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 35.SearchInsertPosition/while_step3.cpp diff --git a/35.SearchInsertPosition/step4.cpp b/35.SearchInsertPosition/step4.cpp index 0f708fb..00fa300 100644 --- a/35.SearchInsertPosition/step4.cpp +++ b/35.SearchInsertPosition/step4.cpp @@ -1,25 +1,28 @@ /* 1.問題のモデル化 -ターゲットより大きいのか、以下なのか2つ以上の相補的な状態に分類することができるのでfalseとtrueの問題とみなす。 -記問題を解くにあたり、対象の位置を含む区間をstartからendとして定義する。 +numsの各要素をターゲット未満かターゲット以上であるかの2種類に分類する +ターゲット未満であればfalse、ターゲット以上であればtrueと見なす。 + +例えばnums = [1,3,5,6], target = 5 を用いると +nums = [false, false, true, true]と表すことができる +この中で一番左の true の位置を探す。 2.探索空間の定義 今回は閉区間として探索を行う。 3.初期値の設定 -startを0、endを配列の最後の要素nums.size() - 1として探索する。 -配列の全要素を探索するイメージ。 +startを0、endを配列の最後の要素nums.size() - 1とする。 4.ループ不変条件の設定 -startとendの真ん中をmiddleとして、ループの普遍条件は -・start <= middle < end +startとendの真ん中をmiddleとして、ループの不変条件は +start < end、start <= middle、middle <= end 5.探索ロジックの設計 -nums[middle] < targetがtrueであれば、middleより左側にtargetは存在しないので -startをmiddle + 1に更新 +nums[middle] < target の場合、middleおよびその左側にtargetは存在しないので +startをmiddle + 1に更新する。 nums[mid] >= target の場合、 mid の位置に対象がある場合があるため、 -区間を狭めつつ mid を区間内に含めるため、end = mid とする +区間を狭めつつ mid を区間内に含めるため、end = mid とする。 6.検証 ・targetがnumsのいずれよりも小さい場合 diff --git a/35.SearchInsertPosition/step5.cpp b/35.SearchInsertPosition/step5.cpp index d442e3a..ec818a1 100644 --- a/35.SearchInsertPosition/step5.cpp +++ b/35.SearchInsertPosition/step5.cpp @@ -12,8 +12,7 @@ startを0、endをnums.size()として探索する。 4.ループ不変条件の設定 startとendの真ん中をmiddleとして、ループの普遍条件は -・start <= middle < end -・start <= target < end + start < end、start <= middle、middle <= end 5.探索ロジックの設計 nums[middle] < targetがtrueであれば、middleより左側にtargetは存在しないので diff --git a/35.SearchInsertPosition/while_step3.cpp b/35.SearchInsertPosition/while_step3.cpp new file mode 100644 index 0000000..b3dc4e2 --- /dev/null +++ b/35.SearchInsertPosition/while_step3.cpp @@ -0,0 +1,61 @@ +/* +1.問題のモデル化 +numsの各要素をターゲット未満かターゲット以上であるかの2種類に分類する +ターゲット未満であればfalse、ターゲット以上であればtrueと見なす。 + +例えばnums = [1,3,5,6], target = 5 を用いると +nums = [false, false, true, true]と表すことができる +この中で一番左の true の位置を探す。 + +2.探索空間の定義 +今回は半開区間として探索を行う。 + +3.初期値の設定 +leftを0、rightを配列の最後の要素nums.size()とする。 + +4.ループ不変条件の設定 +left < right、[left, right)に解が含まれている。 + +5.探索ロジックの設計 +leftとrightの真ん中をmiddleと置く。 +nums[middle] < target の場合、middleおよびその左側にtargetは存在しないので +leftをmiddle + 1に更新する。 + +nums[mid] >= target の場合、 mid の位置に対象がある場合があるため、 +区間を狭めつつ mid を区間内に含めるため、right = mid とする。 + +6.検証 +・targetがnumsのいずれよりも小さい場合 + nums[middle] < targetが常にfalseとなり、leftは最初の位置のままrightが狭まりleftの初期位置が解となる + +・targetがnumsのいずれよりも大きい場合 + nums[middle] < targetが常にtrueとなり、leftがrightに近づきnumsの外側が挿入位置となる。 + +・targetに該当するnumが複数存在する場合 + 最小のインデックスを返却 + +7.実行 +leet codeにて動作確認 + +*/ +class Solution { + public: + int searchInsert(vector& nums, int target) { + int left = 0; + // numsの最後の要素の右側が挿入位置になる可能性がある + int right = nums.size(); + + // leftに挿入位置を寄せていく + while (left < right) { + int middle = left + (right - left) / 2; + + if (nums[middle] < target) { + left = middle + 1; + } else { + right = middle; + } + } + + return left; + } + };