类型总结:二分
说明:利用数组有序的性质,使用二分实现快速查找
3、33. Search in Rotated Sorted Array
题目的大意是一个顺序的数组,但是在某个地方被反转了,例如
(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).
那么给出一个数,问找到这个数的下标。
实际上是一个变相的二分,只是在进行二分之前,不能仅仅按照target
class Solution {
public:
int search(vector<int>& nums, int target) {
int left=0,right=nums.size();
while(left<right){
int mid=(left+right)/2;
if(nums[mid]==target) return mid;
if(nums[left]<nums[mid]){
if(nums[left]<=target && target<nums[mid]){
right=mid;
}
else{
left=mid+1;
}
}
else{
if(nums[mid]<=target && target<=nums[right-1]){
left=mid+1;
}
else{
right=mid;
}
}
}
return -1;
}
};
另外:81. Search in Rotated Sorted Array II
这个里面有重复的数字。
这时候nums[left]==nums[right]的时候
这时候不应当再从中间切分。
而是left++;将整个区间减小1
4、4. Median of Two Sorted Arrays
明确要求复杂度O(log(m+n));
Example 1:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5
//一般化问题,其实就是求两个有序数组里第k大的数据
//于是我用了两个数组放在一块依次数数的方式写…..代码量好大,还是too young啊
而且这种方法的复杂度为O(k),而且由于有很多判断操作,可能接近O(m+n)
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int n1=nums1.size();
int n2=nums2.size();
int count=0,i=0,j=0,k,val;
if(special(n1,n2)){
k=(n1+n2)/2+1;
}
else{
k=(n1+n2)/2;
}
for(i=0,j=0;i<n1 && j<n2; ){
if(nums1[i]<nums2[j]){
count++;
if(count==k){
if(special(n1,n2)){
return nums1[i];
}
else{
if(i==n1-1)
return (nums1[i]+nums2[j])/2.0;
else{
return (nums1[i]+min(nums1[i+1],nums2[j]))/2.0;
}
}
}
i++;
}
else{
count++;
if(count==k){
if(special(n1,n2)){
return nums2[j];
}
else{
if(j==n2-1)
return (nums2[j]+nums1[i])/2.0;
else{
return (nums2[j]+min(nums2[j+1],nums1[i]))/2.0;
}
}
}
j++;
}
}
//第一个遍历完了
if(i==n1){
for(;j<n2;j++){
count++;
if(count==k){
if(special(n1,n2)){
return nums2[j];
}
else{
return (nums2[j]+nums2[j+1])/2.0;
}
}
}
}
else{
for(;i<n1;i++){
count++;
if(count==k){
if(special(n1,n2)){
return nums1[i];
}
else{
return (nums1[i]+nums1[i+1])/2.0;
}
}
}
}
return 0;
}
static int special(int n1,int n2){
if((n1+n2) & 0x1 == 1){
return 1;
}
else{
return 0;
}
}
};
改进的思路是每次计算A的(k/2) B的(k/2),如果(A+k/2-1)<(B+k/2-1) 嗯这意味着A中k/2-1之前的数据可以全部剔除,嗯
剔除的思想很重要,不需要从vector中一次删除并移位。由于我们剔除的是从头开始的k/2个,那么就可以利用指针的方式,将指针的开始位置向后移动相应的距离
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m=nums1.size();
int n=nums2.size();
if(special(m,n)){
return get_kth(nums1.begin(),m,nums2.begin(),n,(m+n)/2+1);
}
else{
return (get_kth(nums1.begin(),m,nums2.begin(),n,(m+n)/2)+
get_kth(nums1.begin(),m,nums2.begin(),n,(m+n)/2+1))/2.0;
}
}
static int get_kth(vector<int>::iterator A,int m,vector<int>::iterator B,int n,int k){
//强制m<=n;
if(m>n) return get_kth(B,n,A,m,k);
if(m==0) return *(B+k-1);
if(k==1) return min(*A,*B);
int ia=min(k/2,m),ib=k-ia;
if(*(A+ia-1)<*(B+ib-1)){
return get_kth(A+ia,m-ia,B,n,k-ia);
}
else if(*(A+ia-1)>*(B+ib-1)){
return get_kth(A,m,B+ib,n-ib,k-ib);
}
else return *(A+ia-1);
}
static int special(int n1,int n2){
if((n1+n2) & 0x1 == 1){
return 1;
}
else{
return 0;
}
}
};
补充:快排思想的回顾:
挖坑填数+分治
http://blog.csdn.net/morewindows/article/details/6684558
归并排序:
http://blog.csdn.net/morewindows/article/details/6678165
这个博主的几篇关于排序的文章很不错,值得一看。