从有序数组中寻找元素

100 篇文章 0 订阅
6 篇文章 0 订阅

类型总结:二分
说明:利用数组有序的性质,使用二分实现快速查找


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
这个博主的几篇关于排序的文章很不错,值得一看。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值