1 35. 搜索插入位置
AC代码:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int l = 0;
int r = nums.size()-1;
while(l < r)
{
int mid = (l+r) >> 1;
if(nums[mid] >= target)r = mid;
else l = mid + 1;
}
if(nums[l] >= target)return l;
else return l+1;
}
};
2 74. 搜索二维矩阵
一次AC代码:
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
// 先第一列二分再 某一行二分
int l = 0;
int r = matrix.size() - 1;
while(l < r)
{
int mid = (l+r) >> 1;
if(matrix[mid][0] >= target)r = mid; // 找到大于等于target的第一个
else l = mid + 1;
}
if(matrix[l][0] == target)return 1;
else if(matrix[l][0] < target)
{
// 最后一行
int i = 0;
int j = matrix[matrix.size() - 1].size() - 1;
while(i < j)
{
int mid = (i+j) >> 1;
if(matrix[matrix.size() - 1][mid] >= target)j = mid; // 找到大于等于target的第一个
else i = mid + 1;
}
if(matrix[matrix.size() - 1][i] == target)return 1;
else return 0;
}
else
{
if(l == 0)return 0;
int i = 0;
int j = matrix[l-1].size() - 1;
while(i < j)
{
int mid = (i+j) >> 1;
if(matrix[l-1][mid] >= target)j = mid; // 找到大于等于target的第一个
else i = mid + 1;
}
if(matrix[l-1][i] == target)return 1;
else return 0;
}
}
};
3 34. 在排序数组中查找元素的第一个和最后一个位置
常规的两次二分。AC代码:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target)
{
// 二分
vector<int> ans;
// 【1】大于等于target的第一个下标
int l = 0;
int r = nums.size()-1;
while(l < r)
{
int mid = (l + r) >> 1;
if(nums[mid] >= target)r = mid;
else l = mid + 1;
}
if(nums.size() == 0 || nums[r] != target){
ans.push_back(-1);
ans.push_back(-1);
return ans;
}
else ans.push_back(l);
l = 0;
r = nums.size()-1;
while(l < r)
{
int mid = (l + r + 1) >> 1;
if(nums[mid] <= target)l = mid;
else r = mid - 1;
}
ans.push_back(l);
return ans;
}
};
4 33. 搜索旋转排序数组(更好的一次二分解法有空补)
我O(2*logn)用了两次二分的解法,AC代码:
看了题解其实也可以写成一个二分的,就是O(logn)的解法。有空再补把
class Solution {
public:
int erfen(vector<int> nums,int l,int r,int target)
{
while(l < r)
{
int mid = (l+r+1) >> 1;
if(nums[mid] <= target)l = mid;
else r = mid - 1;
}
if(target == nums[l])return l;
else return -1;
}
int search(vector<int>& nums, int target) {
// 先O(logn)找到右边升序序列的起点
int l = 0;
int r = nums.size()-1;
if(nums[0] <= nums[nums.size()-1])
{
return erfen(nums,l,r,target);
}
else{
while(l < r)
{
int mid = (l + r) >> 1;
if(nums[mid] < nums[0])r = mid;
else l = mid + 1;
}
int ans1 = -1;
int ans2 = -1;
if(target >= nums[0] && target <= nums[l-1])ans1 = erfen(nums,0,l-1,target);
else if(target >= nums[l] && target <= nums[nums.size()-1])ans2 = erfen(nums,l,nums.size()-1,target);
if(ans1 == -1 && ans2 == -1)return -1;
else return ans1 == -1?ans2:ans1;
}
}
};
5 153. 寻找旋转排序数组中的最小值
半暴力,AC:
class Solution {
public:
int findMin(vector<int>& nums) {
if(nums[0] <= nums[nums.size()-1])return nums[0];
for(int i = 0; i < nums.size();i++)
if(i+1 < nums.size() && nums[i] > nums[i+1])return nums[i+1];
return 0;
}
};
解法2——二分:(搬运自题解)
竖直虚线左边的数满足 nums[i]≥nums[0]nums[i]≥nums[0]nums[i]≥nums[0],而竖直虚线右边的数满足nums[i]<nums[0]nums[i]< nums[0]nums[i]<nums[0],分界点就是整个数组的最小值。数组具有二分性,所以我们可以二分出最小值的位置。
用了二分,AC代码:
class Solution {
public:
int findMin(vector<int>& nums) {
if(nums[0] <= nums[nums.size()-1])return nums[0];
int l = 0;
int r = nums.size()-1;
while(l < r)
{
int mid = (l+r) >> 1;
if(nums[mid] < nums[0])r=mid; //找到第一个小于nums[0]的数
else l = mid+1;
}
return nums[l];
}
};
6 4. 寻找两个正序数组的中位数
不理解这题怎么标到困难的,我感觉很简单,两个数列都是有序的 就是找第k大数(这个k就是两个数组长度和/2 ,数组长度和按照奇数偶数分类,最后算中位数时候分类讨论,奇数只要第k个数 ,偶数就是k大和它前面那个数的二数平均)就行,只用到了双指针归并排序中间归并的那一步。一次AC代码:(ps:前几天pat也做过两个数列有序的 就是找第k大数的题目)
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2)
{
int mid = nums1.size() + nums2.size();
mid /= 2;
int i = 0;
int j = 0;
int k = 0;
vector<int> ans;
while(i < nums1.size() && j < nums2.size() && k <= mid)
{
if(nums1[i] <= nums2[j])
{
ans.push_back(nums1[i]);
i++;
k++;
}
else
{
ans.push_back(nums2[j]);
j++;
k++;
}
}
while(i < nums1.size() && k <= mid)
{
ans.push_back(nums1[i]);
i++;
k++;
}
while(j < nums2.size() && k <= mid)
{
ans.push_back(nums2[j]);
j++;
k++;
}
if((nums1.size() + nums2.size())% 2 == 1) return ans[mid];
else return (double)(ans[mid]+ans[mid-1])/2;
}
};