二分查找
35. Search Insert Position
题目链接:https://leetcode.com/problems/search-insert-position/?tab=Description
题目大意:给定一个有序数组和一个目标值,如果目标值在数组中,则返回其所在的位置,如果不存在,则返回目标值的插入位置,该位置使得目标值插入后,数组仍旧保持有序
思路:二分查找,每次比较数组中间值和目标值的大小,如果目标值比中间值大,压缩数组的左半部分,如果目标值比中间值小,则压缩数组的右半部分。
算法步骤:(1)初始化low=0,high=nums.size()-1;(2)比较当前数组(由low和high表示数组范围)中间值和target的大小,如果target大,则令low=mid+1,若target小,则high=mid-1,否则直接返回index;(3)如果low<=high,重复步骤(2),否则返回low。(如果最后一次比较target值比中间值(即low位置的值)大,low所在位置为刚好大于target值得位置,如果target值比中间值(即high位置的值)小,更新low=mid+1,如果mid+1有值,则根据high的上一轮更新知道mid+1所在位置一定大于target,如果mid+1等于数组长度,则target插入此处,数组也是有序的)
算法复杂度:时间复杂度O(nlog(n)),空间复杂度O(1)
代码:
1 class Solution { 2 public: 3 int searchInsert(vector<int>& nums, int target) { 4 int low = 0, high = nums.size() - 1; 5 while (low <= high) { 6 int mid = (high - low) / 2 + low; 7 if (target < nums[mid]) 8 high = mid - 1; 9 else if (target > nums[mid]) 10 low = mid + 1; 11 else 12 return mid; 13 } 14 return low; 15 } 16 };
评测系统上运行结果:
153. Find Minimum in Rotated Sorted Array
题目链接:https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/?tab=Description
题目大意:给定一个按升序排好序的数组,数组在某处执行了一次旋转,请找出数组的最小元素,数组不存在重复值
思路:二分查找的变体,重要的是找到转折点发生的位置,转折点位置的值就是最小值
算法步骤:(1)初始化left=0,right=nums.size()-1;(2)比较当前数组(由left和right表示数组范围)中间值和nums[right]的大小,如果nums[right]大,说明转折点不在右侧,更新right=mid,若nums[right]小,说明转折点在右侧,更新left=mid+1;(3)如果left<right,重复步骤(2),若left==right,说明转折点已经找到,返回nums[left]。
算法复杂度:时间复杂度O(nlog(n)),空间复杂度O(1)
代码:
1 class Solution { 2 public: 3 int findMin(vector<int>& nums) { 4 int left = 0, right = nums.size() - 1; 5 while (left < right) { 6 int mid = left + (right - left) / 2; 7 if (nums[mid] < nums[right]) 8 right = mid; 9 else 10 left = mid + 1; 11 } 12 return nums[left]; 13 } 14 };
154. Find Minimum in Rotated Sorted Array II
链接:https://leetcode.com/problems/find-minimum-in-rotated-sorted-array-ii/?tab=Description
题目大意:给定一个按升序排好序的数组,数组在某处执行了一次旋转,请找出数组的最小元素,数组存在重复值
思路:二分查找的变体,重要的是找到转折点发生的位置,转折点位置的值就是最小值
算法步骤:(1)初始化left=0,right=nums.size()-1;(2)比较当前数组(由left和right表示数组范围)中间值和nums[right]的大小,如果nums[right]大,说明转折点不在右侧,更新right=mid,若nums[right]小,说明转折点在右侧,更新left=mid+1,若nums[right]==nums[mid],则最小值可能在左侧,也可能在右侧,但不论在哪侧,都可以通过--right,将数组范围缩小一点;(3)如果left<right,重复步骤(2),若left==right,说明转折点已经找到,返回nums[left]。
算法复杂度:时间复杂度O(nlog(n)),空间复杂度O(1)
代码:
1 class Solution { 2 public: 3 int findMin(vector<int>& nums) { 4 int left = 0, right = nums.size() - 1; 5 while (left < right) { 6 int mid = left + (right - left) / 2; 7 if (nums[mid] < nums[right]) 8 right = mid; 9 else if(nums[mid] > nums[right]) 10 left = mid + 1; 11 else 12 --right; 13 } 14 return nums[left]; 15 } 16 };