From 2822593c460fcca5ec586637b98d98fafa75d3d7 Mon Sep 17 00:00:00 2001 From: Sainnhe Park Date: Thu, 24 Nov 2022 16:44:36 +0800 Subject: [PATCH] Bin search --- ...st_position_of_element_in_sorted_array.hpp | 7 +- include/s0035_search_insert_position.hpp | 8 +- include/s0704_binary_search.hpp | 18 ++++ notes/src/SUMMARY.md | 10 +- notes/src/bin_search.md | 95 ++++++++++--------- ...st_position_of_element_in_sorted_array.cpp | 84 ++++++++++------ src/s0035_search_insert_position.cpp | 58 +++++------ src/s0704_binary_search.cpp | 37 ++++++++ ...st_position_of_element_in_sorted_array.cpp | 18 ++-- tests/s0035_search_insert_position.cpp | 18 ++-- tests/s0704_binary_search.cpp | 23 +++++ 11 files changed, 256 insertions(+), 120 deletions(-) create mode 100644 include/s0704_binary_search.hpp create mode 100644 src/s0704_binary_search.cpp create mode 100644 tests/s0704_binary_search.cpp diff --git a/include/s0034_find_first_and_last_position_of_element_in_sorted_array.hpp b/include/s0034_find_first_and_last_position_of_element_in_sorted_array.hpp index b891ecc..1527800 100644 --- a/include/s0034_find_first_and_last_position_of_element_in_sorted_array.hpp +++ b/include/s0034_find_first_and_last_position_of_element_in_sorted_array.hpp @@ -2,13 +2,16 @@ #define S0034_FIND_FIRST_AND_LAST_POSITION_OF_ELEMENT_IN_SORTED_ARRAY_HPP #include -#include using namespace std; -class Solution { +class Solution1 { public: vector searchRange(vector& nums, int target); }; +class Solution2 { + public: + vector searchRange(vector& nums, int target); +}; #endif diff --git a/include/s0035_search_insert_position.hpp b/include/s0035_search_insert_position.hpp index 34a443a..b55edad 100644 --- a/include/s0035_search_insert_position.hpp +++ b/include/s0035_search_insert_position.hpp @@ -2,11 +2,15 @@ #define S0035_SEARCH_INSERT_POSITION_HPP #include -#include using namespace std; -class Solution { +class Solution1 { + public: + int searchInsert(vector& nums, int target); +}; + +class Solution2 { public: int searchInsert(vector& nums, int target); }; diff --git a/include/s0704_binary_search.hpp b/include/s0704_binary_search.hpp new file mode 100644 index 0000000..805e66a --- /dev/null +++ b/include/s0704_binary_search.hpp @@ -0,0 +1,18 @@ +#ifndef S0704_BINARY_SEARCH_HPP +#define S0704_BINARY_SEARCH_HPP + +#include + +using namespace std; + +class Solution1 { + public: + int binSearch(vector& nums, int target); +}; + +class Solution2 { + public: + int binSearch(vector& nums, int target); +}; + +#endif diff --git a/notes/src/SUMMARY.md b/notes/src/SUMMARY.md index 50d07d6..26fba9d 100644 --- a/notes/src/SUMMARY.md +++ b/notes/src/SUMMARY.md @@ -1,9 +1,9 @@ -# 思路 +# 数组 -- [深度优先遍历](./dfs.md) -- [广度优先遍历](./bfs.md) +- [二分查找](./bin_search.md) -## 经典代码 +# 经典代码 - [合并两个有序链表](./merge_two_sorted_linked_lists.md) -- [二分查找](./bin_search.md) +- [深度优先遍历](./dfs.md) +- [广度优先遍历](./bfs.md) diff --git a/notes/src/bin_search.md b/notes/src/bin_search.md index f758205..aae8a89 100644 --- a/notes/src/bin_search.md +++ b/notes/src/bin_search.md @@ -1,57 +1,64 @@ # 二分查找 -非递归: +适用于数组有序的情况下查找目标值。 + +## 写法一 + +针对左闭右闭区间(即 `[left, right]`): ```cpp -/** - * 二分查找普通实现。 - * @param srcArray 有序数组 - * @param key 查找元素 - * @return 不存在返回-1 - */ -public -static int binSearch(int srcArray[], int key) { - int mid; - int start = 0; - int end = srcArray.length - 1; - while (start <= end) { - mid = (end - start) / 2 + start; - if (key < srcArray[mid]) { - end = mid - 1; - } else if (key > srcArray[mid]) { - start = mid + 1; - } else { - return mid; +class Solution { + public: + int search(vector& nums, int target) { + int left = 0; + int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right] + while (left <= + right) { // 当left==right,区间[left, right]依然有效,所以用 <= + int middle = + left + ((right - left) / 2); // 防止溢出 等同于(left + right)/2 + if (nums[middle] > target) { + right = middle - 1; // target 在左区间,所以[left, middle - 1] + } else if (nums[middle] < target) { + left = middle + 1; // target 在右区间,所以[middle + 1, right] + } else { // nums[middle] == target + return middle; // 数组中找到目标值,直接返回下标 + } } + // 未找到目标值 + return -1; } - return -1; -} +}; ``` -递归: +## 写法二 + +针对左闭右开(即 `[left, right)`): ```cpp -/** - * 二分查找递归实现。 - * @param srcArray 有序数组 - * @param start 数组低地址下标 - * @param end 数组高地址下标 - * @param key 查找元素 - * @return 查找元素不存在返回-1 - */ -public -static int binSearch(int srcArray[], int start, int end, int key) { - int mid = (end - start) / 2 + start; - if (srcArray[mid] == key) { - return mid; - } - if (start >= end) { +class Solution { + public: + int search(vector& nums, int target) { + int left = 0; + int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right) + while (left < right) { // 因为left == right的时候,在[left, + // right)是无效的空间,所以使用 < + int middle = left + ((right - left) >> 1); + if (nums[middle] > target) { + right = middle; // target 在左区间,在[left, middle)中 + } else if (nums[middle] < target) { + left = middle + 1; // target 在右区间,在[middle + 1, right)中 + } else { // nums[middle] == target + return middle; // 数组中找到目标值,直接返回下标 + } + } + // 未找到目标值 return -1; - } else if (key > srcArray[mid]) { - return binSearch(srcArray, mid + 1, end, key); - } else if (key < srcArray[mid]) { - return binSearch(srcArray, start, mid - 1, key); } - return -1; -} +}; ``` + +## 相关题目 + +- [704. 二分查找](https://programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html#_704-%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE) +- [35. 搜索插入位置](https://programmercarl.com/0035.%E6%90%9C%E7%B4%A2%E6%8F%92%E5%85%A5%E4%BD%8D%E7%BD%AE.html#_35-%E6%90%9C%E7%B4%A2%E6%8F%92%E5%85%A5%E4%BD%8D%E7%BD%AE) +- [34. 在排序数组中查找元素的第一个和最后一个位置](https://programmercarl.com/0034.%E5%9C%A8%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E6%9F%A5%E6%89%BE%E5%85%83%E7%B4%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%92%8C%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E4%BD%8D%E7%BD%AE.html#_34-%E5%9C%A8%E6%8E%92%E5%BA%8F%E6%95%B0%E7%BB%84%E4%B8%AD%E6%9F%A5%E6%89%BE%E5%85%83%E7%B4%A0%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E5%92%8C%E6%9C%80%E5%90%8E%E4%B8%80%E4%B8%AA%E4%BD%8D%E7%BD%AE) diff --git a/src/s0034_find_first_and_last_position_of_element_in_sorted_array.cpp b/src/s0034_find_first_and_last_position_of_element_in_sorted_array.cpp index d6fae5e..0b4b2e1 100644 --- a/src/s0034_find_first_and_last_position_of_element_in_sorted_array.cpp +++ b/src/s0034_find_first_and_last_position_of_element_in_sorted_array.cpp @@ -1,38 +1,66 @@ #include "s0034_find_first_and_last_position_of_element_in_sorted_array.hpp" -vector Solution::searchRange(vector& nums, int target) { - int size = nums.size(); - if (size <= 0) { - return vector {-1, -1}; - } else if (size == 1) { - if (nums[0] == target) { - return vector {0, 0}; +// 闭区间写法 +vector Solution1::searchRange(vector& nums, int target) { + int len = nums.size(); + int l{0}; + int r = len - 1; + while (l <= r) { + int m = (l + r) >> 1; + if (target < nums[m]) { + r = m - 1; + } else if (nums[m] < target) { + l = m + 1; } else { - return vector {-1, -1}; - } - } - int left{0}; - int right = size - 1; - int mid; - while (left <= right) { - mid = static_cast(floor((left + right) / 2)); - if (nums[mid] == target) { - int resultLeft, resultRight; - for (int i = mid; i < size; ++i) { - if (nums[i] == target) { - resultRight = i; + l = r = m; + while (l >= 0) { + if (nums[l] == target) { + --l; + } else { + break; } } - for (int i = mid; i >= 0; --i) { - if (nums[i] == target) { - resultLeft = i; + while (r <= len - 1) { + if (nums[r] == target) { + ++r; + } else { + break; } } - return vector {resultLeft, resultRight}; - } else if (nums[mid] > target) { - right = mid - 1; - } else { - left = mid + 1; + return vector {l + 1, r - 1}; + } + } + return vector {-1, -1}; +} + +// 开区间写法 +vector Solution2::searchRange(vector& nums, int target) { + int len = nums.size(); + int l{0}; + int r = len; + while (l < r) { + int m = (l + r) >> 1; + if (target < nums[m]) { + r = m; + } else if (nums[m] < target) { + l = m + 1; + } else { + l = r = m; + while (l >= 0) { + if (nums[l] == target) { + --l; + } else { + break; + } + } + while (r <= len - 1) { + if (nums[r] == target) { + ++r; + } else { + break; + } + } + return vector {l + 1, r - 1}; } } return vector {-1, -1}; diff --git a/src/s0035_search_insert_position.cpp b/src/s0035_search_insert_position.cpp index 8aa881f..a376baa 100644 --- a/src/s0035_search_insert_position.cpp +++ b/src/s0035_search_insert_position.cpp @@ -1,33 +1,37 @@ #include "s0035_search_insert_position.hpp" -int Solution::searchInsert(vector& nums, int target) { - int size = nums.size(); - if (size == 0) { - return 0; - } - int left{0}; - int right = size - 1; - int mid; - while (left <= right) { - mid = static_cast(floor((left + right) / 2)); - if (nums[mid] == target) { - return mid; - } else if (nums[mid] > target) { - right = mid - 1; +// 闭区间写法 +int Solution1::searchInsert(vector& nums, int target) { + int len = nums.size(); + int l{0}; + int r = len - 1; + while (l <= r) { + int m = (l + r) >> 1; + if (target < nums[m]) { + r = m - 1; + } else if (nums[m] < target) { + l = m + 1; } else { - left = mid + 1; + return m; } } - if (right < 0) { - return 0; - } else if (left > size - 1) { - return size; - } - if (target < nums[right]) { - return right; - } else if (target > nums[left]) { - return left + 1; - } else { - return left; - } + return r + 1; +} + +// 开区间写法 +int Solution2::searchInsert(vector& nums, int target) { + int len = nums.size(); + int l{0}; + int r = len; + while (l < r) { + int m = (l + r) >> 1; + if (target < nums[m]) { + r = m; + } else if (nums[m] < target) { + l = m + 1; + } else { + return m; + } + } + return r; } diff --git a/src/s0704_binary_search.cpp b/src/s0704_binary_search.cpp new file mode 100644 index 0000000..c0f9711 --- /dev/null +++ b/src/s0704_binary_search.cpp @@ -0,0 +1,37 @@ +#include "s0704_binary_search.hpp" + +// 闭区间写法 +int Solution1::binSearch(vector& nums, int target) { + int len = nums.size(); + int l{0}; + int r = len - 1; + while (l <= r) { + int m = (l + r) >> 1; + if (target < nums[m]) { + r = m - 1; + } else if (nums[m] < target) { + l = m + 1; + } else { + return m; + } + } + return -1; +} + +// 开区间写法 +int Solution2::binSearch(vector& nums, int target) { + int len = nums.size(); + int l{0}; + int r = len; + while (l < r) { + int m = (l + r) >> 1; + if (target < nums[m]) { + r = m; + } else if (nums[m] < target) { + l = m + 1; + } else { + return m; + } + } + return -1; +} diff --git a/tests/s0034_find_first_and_last_position_of_element_in_sorted_array.cpp b/tests/s0034_find_first_and_last_position_of_element_in_sorted_array.cpp index ff6142f..9ea6184 100644 --- a/tests/s0034_find_first_and_last_position_of_element_in_sorted_array.cpp +++ b/tests/s0034_find_first_and_last_position_of_element_in_sorted_array.cpp @@ -6,22 +6,28 @@ TEST(Problem34, Case1) { vector nums{5, 7, 7, 8, 8, 10}; int target{8}; vector o{3, 4}; - Solution solution; - EXPECT_EQ(solution.searchRange(nums, target), o); + Solution1 solution1; + Solution2 solution2; + EXPECT_EQ(solution1.searchRange(nums, target), o); + EXPECT_EQ(solution2.searchRange(nums, target), o); } TEST(Problem34, Case2) { vector nums{5, 7, 7, 8, 8, 10}; int target{6}; vector o{-1, -1}; - Solution solution; - EXPECT_EQ(solution.searchRange(nums, target), o); + Solution1 solution1; + Solution2 solution2; + EXPECT_EQ(solution1.searchRange(nums, target), o); + EXPECT_EQ(solution2.searchRange(nums, target), o); } TEST(Problem34, Case3) { vector nums{}; int target{0}; vector o{-1, -1}; - Solution solution; - EXPECT_EQ(solution.searchRange(nums, target), o); + Solution1 solution1; + Solution2 solution2; + EXPECT_EQ(solution1.searchRange(nums, target), o); + EXPECT_EQ(solution2.searchRange(nums, target), o); } diff --git a/tests/s0035_search_insert_position.cpp b/tests/s0035_search_insert_position.cpp index 537661a..c7d59a1 100644 --- a/tests/s0035_search_insert_position.cpp +++ b/tests/s0035_search_insert_position.cpp @@ -6,22 +6,28 @@ TEST(Problem35, Case1) { vector nums{1, 3, 5, 6}; int target{5}; int o{2}; - Solution solution; - EXPECT_EQ(solution.searchInsert(nums, target), o); + Solution1 solution1; + Solution2 solution2; + EXPECT_EQ(solution1.searchInsert(nums, target), o); + EXPECT_EQ(solution2.searchInsert(nums, target), o); } TEST(Problem35, Case2) { vector nums{1, 3, 5, 6}; int target{2}; int o{1}; - Solution solution; - EXPECT_EQ(solution.searchInsert(nums, target), o); + Solution1 solution1; + Solution2 solution2; + EXPECT_EQ(solution1.searchInsert(nums, target), o); + EXPECT_EQ(solution2.searchInsert(nums, target), o); } TEST(Problem35, Case3) { vector nums{1, 3, 5, 6}; int target{7}; int o{4}; - Solution solution; - EXPECT_EQ(solution.searchInsert(nums, target), o); + Solution1 solution1; + Solution2 solution2; + EXPECT_EQ(solution1.searchInsert(nums, target), o); + EXPECT_EQ(solution2.searchInsert(nums, target), o); } diff --git a/tests/s0704_binary_search.cpp b/tests/s0704_binary_search.cpp new file mode 100644 index 0000000..00be0bf --- /dev/null +++ b/tests/s0704_binary_search.cpp @@ -0,0 +1,23 @@ +#include "s0704_binary_search.hpp" + +#include + +TEST(Problem704, Case1) { + vector nums{-1, 0, 3, 5, 9, 12}; + int target{9}; + int o{4}; + Solution1 solution1; + Solution2 solution2; + EXPECT_EQ(solution1.binSearch(nums, target), o); + EXPECT_EQ(solution2.binSearch(nums, target), o); +} + +TEST(Problem704, Case2) { + vector nums{-1, 0, 3, 5, 9, 12}; + int target{2}; + int o{-1}; + Solution1 solution1; + Solution2 solution2; + EXPECT_EQ(solution1.binSearch(nums, target), o); + EXPECT_EQ(solution2.binSearch(nums, target), o); +}