旅游药都网站建设方案,电器网站制作价格,网站建设必学课程,怎样找外贸客户啊二分搜索算法核心代码模板 | labuladong 的算法笔记
1 温故而知新
题目
704. 二分查找
给定一个 n 个元素有序的#xff08;升序#xff09;整型数组 nums 和一个目标值 target #xff0c;写一个函数搜索 nums 中的 target#xff0c;如果 target 存在返回下标#…二分搜索算法核心代码模板 | labuladong 的算法笔记1 温故而知新题目704. 二分查找给定一个n个元素有序的升序整型数组nums和一个目标值target写一个函数搜索nums中的target如果target存在返回下标否则返回-1。你必须编写一个具有O(log n)时间复杂度的算法。示例 1:输入:nums [-1,0,3,5,9,12],target 9输出:4解释:9 出现在nums中并且下标为 4示例 2:输入:nums [-1,0,3,5,9,12],target 2输出:-1解释:2 不存在nums中因此返回 -1提示你可以假设nums中的所有元素是不重复的。n将在[1, 10000]之间。nums的每个元素都将在[-9999, 9999]之间。代码实现重新写的时候犯了个小错误贴上解答错误的代码class Solution { public: int search(vectorint nums, int target) { int left 0 ; int right nums.size() -1 ; while (left right){ int mid (right - left) / 2 left ; if (nums[mid] target){ return mid; }else if (nums[mid] target){ right mid - 1 ; }else{ left mid 1 ; } } return -1; } };错误循环条件left right 两个可以相等对于数组内只有单个元素的考虑否则会错误的跳出循环返回 -1class Solution { public: int search(vectorint nums, int target) { int left 0 ; int right nums.size() - 1; while(left right){ int mid left (right - left ) / 2 ; if(nums[mid] target ){ return mid ; }else if (nums[mid] target ){ left mid 1 ; }else if (nums[mid] target ){ right mid - 1; } } return -1; } };框架伪码int binarySearch(vectorint nums, int target) { int left 0, right nums.size() - 1; while (...) { int mid left (right - left) / 2; if (nums[mid] target) { ... } else if (nums[mid] target) { left ... } else if (nums[mid] target) { right ... } } }题目34. 在排序数组中查找元素的第一个和最后一个位置给你一个按照非递减顺序排列的整数数组nums和一个目标值target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值target返回[-1, -1]。你必须设计并实现时间复杂度为O(log n)的算法解决此问题。示例 1输入nums [5,7,7,8,8,10], target 8输出[3,4]示例 2输入nums [5,7,7,8,8,10], target 6输出[-1,-1]示例 3输入nums [], target 0输出[-1,-1]代码实现这个题目怎么觉得有点像滑动窗口直接看看以前提交的代码回顾一下。using namespace std ; class Solution { public: int left_bound(vectorint nums ,int target){ int left 0 , right nums.size() - 1 ; while (left right ){ int mid left (right - left ) / 2 ; if (nums[mid] target ){ left mid 1 ; }else if (nums[mid] target){ right mid - 1 ; }else if (nums[mid] target){ right mid - 1 ; } } if (left 0 || left nums.size() || nums[left] ! target){ return -1 ; } return left ; } int right_bound(vectorint nums ,int target){ int left 0 , right nums.size() - 1 ; while (left right ){ int mid left (right - left ) / 2 ; if (nums[mid] target ){ left mid 1 ; }else if (nums[mid] target){ right mid - 1 ; }else if (nums[mid] target){ left mid 1 ; } } if (right 0 || right nums.size() || nums[right] ! target){ return -1 ; } return right ; } vectorint searchRange(vectorint nums, int target) { int left left_bound(nums,target); int right right_bound(nums,target); return{ left , right }; } };我知道了一看这个题解我知道我当时根本不会这个题目我先记下来的。class Solution { public: vectorint searchRange(vectorint nums, int target) { // 直接调用原名称的左右边界查找函数 int left left_bound(nums, target); int right right_bound(nums, target); return {left, right}; } private: // 查找左边界 int left_bound(vectorint nums, int target) { int left 0, right nums.size()-1; while (left right) { int mid left (right - left) / 2; if (nums[mid] target) { left mid 1; } else if (nums[mid] target) { right mid - 1; } else if (nums[mid] target) { right mid - 1; // 锁定左侧边界 } } // 越界或值不匹配则返回-1 if (left 0 || left nums.size() || nums[left] ! target) { return -1; } return left; } // 查找右边界 int right_bound(vectorint nums, int target) { int left 0, right nums.size()-1; while (left right) { int mid left (right - left) / 2; if (nums[mid] target) { left mid 1; } else if (nums[mid] target) { right mid - 1; } else if (nums[mid] target) { left mid 1; // 锁定右侧边界 } } // 越界或值不匹配则返回-1 if (right 0 || right nums.size() || nums[right] ! target) { return -1; } return right; } };其实很清晰了就是在做一个左边界查找和右边界查找索引的工作根本没那么难。自己动手写的错的代码class Solution { private: int left_bound (vectorint nums, int target){ int left 0 ; int right nums.size() -1 ; while(right left){ int mid left (right - left) / 2 ; if(nums[mid] target){ right mid - 1; }else if (nums[mid] target){ right mid - 1; }else{ left mid 1 ; } } if (left 0 || left nums.size() || nums[left] ! target) { return -1; } return left; } int right_bound (vectorint nums, int target){ int left 0 ; int right nums.size() -1; while(right left){ int mid left (right - left) / 2 ; if(nums[mid] target){ left mid 1 ; }else if (nums[mid] target){ right mid - 1; }else{ left mid 1 ; } } if (left 0 || left nums.size() || nums[left] ! target) { return -1; } return right; } public: vectorint searchRange(vectorint nums, int target) { int left left_bound(nums,target); int right right_bound(nums,target); return{ left, right }; } };错误注释class Solution { private: int left_bound (vectorint nums, int target){ int left 0 ; int right nums.size() -1 ; while(right left){ int mid left (right - left) / 2 ; if(nums[mid] target){ right mid - 1; }else if (nums[mid] target){ right mid - 1; }else{ left mid 1 ; } } // 错误1非致命left初始为0且只增不减不可能0这个判断多余 if (left 0 || left nums.size() || nums[left] ! target) { return -1; } return left; // left_bound的返回值是正确的这里没问题 } int right_bound (vectorint nums, int target){ int left 0 ; int right nums.size() -1; while(right left){ int mid left (right - left) / 2 ; if(nums[mid] target){ left mid 1 ; }else if (nums[mid] target){ right mid - 1; }else{ left mid 1 ; } } // 错误2致命校验的是left但right_bound的结果存在right里left此时可能越界 // 比如nums[1,2,2,3], target2循环结束后left3nums[3]3≠2直接错误返回-1 // 正确应该校验right的合法性和值 if (left 0 || left nums.size() || nums[left] ! target) { return -1; } // 这里return right是正确的但上面的校验逻辑错了导致根本走不到这一步 return right; } public: vectorint searchRange(vectorint nums, int target) { int left left_bound(nums,target); int right right_bound(nums,target); return{ left, right }; } };修正后class Solution { private: int left_bound (vectorint nums, int target){ int left 0 ; int right nums.size() -1 ; while(right left){ int mid left (right - left) / 2 ; if(nums[mid] target){ right mid - 1; }else if (nums[mid] target){ right mid - 1; }else{ left mid 1 ; } } if (left nums.size() || nums[left] ! target) { return -1; } return left; } int right_bound (vectorint nums, int target){ int left 0 ; int right nums.size() -1; while(right left){ int mid left (right - left) / 2 ; if(nums[mid] target){ left mid 1 ; }else if (nums[mid] target){ right mid - 1; }else{ left mid 1 ; } } if (right nums.size() || nums[right] ! target) { return -1; } return right; } public: vectorint searchRange(vectorint nums, int target) { int left left_bound(nums,target); int right right_bound(nums,target); return{ left, right }; } };承认偷懒了校验逻辑这里直接复制粘贴了没有自己再好好核对一遍。2 二分查找归类第一个最基本的二分查找算法因为我们初始化 right nums.length - 1 所以决定了我们的「搜索区间」是 [left, right] 所以决定了 while (left right) 同时也决定了 left mid1 和 right mid-1 因为我们只需找到一个 target 的索引即可 所以当 nums[mid] target 时可以立即返回第二个寻找左侧边界的二分查找因为我们初始化 right nums.length 所以决定了我们的「搜索区间」是 [left, right) 所以决定了 while (left right) 同时也决定了 left mid 1 和 right mid 因为我们需找到 target 的最左侧索引 所以当 nums[mid] target 时不要立即返回 而要收紧右侧边界以锁定左侧边界第三个寻找右侧边界的二分查找因为我们初始化 right nums.length 所以决定了我们的「搜索区间」是 [left, right) 所以决定了 while (left right) 同时也决定了 left mid 1 和 right mid 因为我们需找到 target 的最右侧索引 所以当 nums[mid] target 时不要立即返回 而要收紧左侧边界以锁定右侧边界 又因为收紧左侧边界时必须 left mid 1 所以最后无论返回 left 还是 right必须减一三类代码合起来看int binary_search(vectorint nums, int target) { int left 0, right nums.size()-1; while(left right) { int mid left (right - left) / 2; if (nums[mid] target) { left mid 1; } else if (nums[mid] target) { right mid - 1; } else if(nums[mid] target) { // 直接返回 return mid; } } // 直接返回 return -1; } int left_bound(vectorint nums, int target) { int left 0, right nums.size()-1; while (left right) { int mid left (right - left) / 2; if (nums[mid] target) { left mid 1; } else if (nums[mid] target) { right mid - 1; } else if (nums[mid] target) { // 别返回锁定左侧边界 right mid - 1; } } // 判断 target 是否存在于 nums 中 if (left 0 || left nums.size()) { return -1; } // 判断一下 nums[left] 是不是 target return nums[left] target ? left : -1; } int right_bound(vectorint nums, int target) { int left 0, right nums.size()-1; while (left right) { int mid left (right - left) / 2; if (nums[mid] target) { left mid 1; } else if (nums[mid] target) { right mid - 1; } else if (nums[mid] target) { // 别返回锁定右侧边界 left mid 1; } } // 由于 while 的结束条件是 right left - 1且现在在求右边界 // 所以用 right 替代 left - 1 更好记 if (right 0 || right nums.size()) { return -1; } return nums[right] target ? right : -1; }3 总结一开始看上面的题目还是懵懵懂懂有很多语法的细节没有自己仔细注意。现在回头看无非就是3种情况对应上面的三种逻辑1.查找元素2.查找左边界3.查找右边界------------虽然自己写还是会有点小问题但是排查能力和自己修正的能力在不断提高总比一开始什么也看不懂好的多。我在进步和纵向的自己比不要浮躁不要焦虑慢慢来比较快。好巧看了这题的初次提交时间刚好是1个月以前。1个月从完全没思路到自己能理出框架和思路至少有深一些的理解我在进步不要放弃自己加油。加油加油