[Leetcode] 15, 81, 4

15. 3Sum

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note: The solution set must not contain duplicate triplets.

Solution: 去重之后使用二分查找

Code: 

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> answer;
        sort(nums.begin(),nums.end());
        
        for(int i=0; i<nums.size(); i++){
            if(i>0 && nums[i-1]==nums[i]) continue;//用于去重
            
            for(int t=i+1; t<nums.size()-1; t++){
                if(t>i+1 && nums[t-1]==nums[t]) continue; //用于去重
                
                vector<int>::iterator it;
                it = lower_bound (nums.begin()+t+1, nums.end(), -1*(nums[i]+nums[t]));
                //注意:find函数并不是使用二分法进行查找
                //二分查找的函数为:lower_bound 和 upper_bound
                
                if (it!=nums.end() && *it == -1*(nums[i]+nums[t])){
                    vector<int> a;
                    a.push_back(nums[i]);
                    a.push_back(nums[t]);
                    a.push_back(*it);
                    answer.push_back(a);
                }
            }
        }
        return answer;
    }
};

81. Search in Rotated Sorted Array II

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

Write a function to determine if a given target is in the array.

The array may contain duplicates.

Solution(1): 直接查找并不超时

Code: 

class Solution {
public:
    bool search(vector<int>& nums, int target) {
        for(int i=0; i<nums.size(); i++){
            if(nums[i]==target)
                return true;
        }
        return false;

    }
};


Solution(2): 如图二分,注意此情况结果不一定,需要往下多走一部


Code: 

class Solution {
public:
    bool search(vector<int>& nums, int target) {
        int start = 0;
        int end = nums.size();
        int mid = (start+end)/2;
        //使用循环实现的二分查找
        while(start<end){
            if(nums[mid]==target)
                return true;
            else if(nums[mid]<nums[end-1]){
                if(target==nums[end-1]) 
                    return end-1;
                else if(nums[mid]<target && target<nums[end-1])
                    start = mid+1;
                else
                    end = mid;
                    
            }
            else if(nums[start]<nums[mid]){
                if(target==nums[start]) 
                    return true;
                else if(nums[start]<target && target<nums[mid])
                    end = mid;
                else
                    start = mid+1;
            }
            else{
                mid = mid+1;
                if(mid>=end){
                    end = (start+end)/2;
                    mid = (start+end)/2;
                }
                continue;
            }
            mid = (start+end)/2;
        }
        return false;
    }
};


4. Median of Two Sorted Arrays

There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).


Solution(1): 归并(merge)之后输出中位数

Code:

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        vector<int> newnums;
        int i,j;
        for(i=0,j=0; i<nums1.size()&&j<nums2.size(); ){
            if(nums1[i]<nums2[j]){
            	newnums.push_back(nums1[i]);
            	i++;
            }
            else{
            	newnums.push_back(nums2[j]);
            	j++;
            }
            	
        }
		//注意边界的情况
        for(int t=i; t<nums1.size(); t++){
            newnums.push_back(nums1[t]);
        }
        for(int t=j; t<nums2.size(); t++){
            newnums.push_back(nums2[t]);
        }
        if(newnums.size()%2==1){
            return newnums[newnums.size()/2];
        }else{
            return (newnums[newnums.size()/2]+newnums[newnums.size()/2-1])*1.0/2;
        }
    }
};

Solution(2): 二分,这个题可以一般化为:找到两个有序数组中,第k小的元素。

首先这两个数组分别贡献出一部分的数据,组合成一个大小为k的新数组。如果两个数组比k/2要大的话,就各提供k/2个数,否则size小与k/2的数组将所有数据加入,不足的部分由大一些的数组提供。


然后比较a(nums[k/2-1])和b(nums[k/2-1])的大小,此时分为三种情况:

(1)a>b: 

此时比b小的数据一定在a之前,因此nums2[0]至nums2[k/2-1](b) 一定不包含我们需要找到的目标数,即第k小的数,如图所示:


此外,nums1[k/2]至nums1[size-1]中也一定不存在目标数:


因此我们可以排除掉一半的数据:nums1[k/2]-nums1[size-1] 和 nums2[0]至nums2[k/2-1]


(2)a<b: 同理,此情况可以排除掉nums2[k/2]-nums2[size-1] 和 nums1[0]至nums1[k/2-1];

(3)a==b: a和b一定是第k小的数,比a和b小的只有它们之前的k-2个数。


因为nums1和nums2中排除掉了一个用于比较的数据(即a或者b),因此无法继续排除的情况等同于无法选出a和b的情况,此时即为递归的边界条件:

(1)nums1和nums2中有一个数组为空,此时即全部数据有序,可以直接选出第k小的数;

(2)k==1,此时直接选出两个数组中最小的数据进行比较,更小的即为全局最小。


注意:因为除去了比目标数小的数据(nums1[0]-nums1[k/2-1]或者nums2[0]-nums2[k/2-1]),因此在下一次递归时要注意将k减掉这么多。

Code: 

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int size = nums1.size() + nums2.size();
        if(size%2!=0)
            return find_kth(nums1.begin(), nums1.size(), nums2.begin(), nums2.size(), (size/2)+1);
        else
            return (find_kth(nums1.begin(), nums1.size(), nums2.begin(), nums2.size(), size/2)
                   + find_kth(nums1.begin(), nums1.size(), nums2.begin(), nums2.size(), (size/2)+1))/2;
    }
private:
    double find_kth(vector<int>::iterator it1, int size1, vector<int>::iterator it2, int size2, int k){
        //cout<<size1<<" "<<size2<<" k="<<k<<endl;
        if(size1>size2) return find_kth(it2, size2, it1, size1, k);//避免分类讨论
        
        //递归终止条件
        if(size1==0) return *(it2+(k-1));
        if(k==1) return min(*it1, *it2);
        
        int p1 = min(size1, k/2);//避免数组越界
        int p2 = k - p1;
        int value1 = *(it1+(p1-1));
        int value2 = *(it2+(p2-1));
        
        if(value1<value2) return find_kth(it1+p1, size1-p1, it2, p2, k-p1);
        if(value1>value2) return find_kth(it1, size1, it2+p2, size2-p2, k-p2);
        if(value1==value2) return value2;
    }
};




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值