Substring with Concatenation of All Words & Median of Two Sorted Arrays & Divide Two Integers

(1) Substring with Concatenation of All Words 

事实上求解的是S中包含L中所有单词的index,换句话说,假设L中单词长度为wordLen,总长为wordLen*len,从index到距离为总长的这一段包含L中所有的单词。

假设L中的单位长度为n,依次从S中取长度为n的子串,如果在L中,就记下来。需要借助hash或map,如果整个L都匹配完了,就算是一个concatenation;当匹配错误的时候,S右移一个位置。[1]

class Solution {
public:
    vector<int> findSubstring(string S, vector<string> &L) {
        vector<int> ret;
        int n=L[0].size();
        if(L.size()*n>S.size())
            return ret;
        
        unordered_map<string,int> hashtable;
        
        for(int i=0;i<L.size();i++)
            hashtable[L[i]]++;
        
        int i=0;
        unordered_map<string,int> tmp;
        for(int i=0;i<=S.size()-L.size()*n;i++)
        {
            tmp.clear();
            bool flag=true;
            
            for(int j=i;j<i+L.size()*n;j+=n)
            {
                string str=S.substr(j,n);
                if(hashtable.count(str)==0)
                {
                    flag=false;
                    break;
                }
                    
                tmp[str]++;
                
                if(tmp[str]>hashtable[str])
                {
                    flag=false;
                    break; 
                }
            }
            
            if(flag)
                ret.push_back(i);
        }
        return ret;
    }
};
还有一种线性时间复杂度的滑动窗口方法[2]。

(2) Median of Two Sorted Arrays 

该方法的核心是将原问题转变成一个寻找第k小数的问题(假设两个原序列升序排列),这样中位数实际上是第(m+n)/2小的数。所以只要解决了第k小数的问题,原问题也得以解决。首先假设数组A和B的元素个数都大于k/2,我们比较A[k/2-1]和B[k/2-1]两个元素,这两个元素分别表示A的第k/2小的元素和B的第k/2小的元素。这两个元素比较共有三种情况:>、<和=。如果A[k/2-1]<B[k/2-1],这表示A[0]到A[k/2-1]的元素都在A和B合并之后的前k小的元素中。[3]

class Solution {
private:
    double recursive(int A[], int m, int B[], int n,int k) {
        if(m>n)
            return recursive(B,n,A,m,k);
        if(m==0)
            return B[k-1];
        if(k==1)
            return min(A[0],B[0]);
        
        int lenA=min(m,k/2),lenB=k-lenA;
        if(A[lenA-1]<B[lenB-1])
            return recursive(A+lenA,m-lenA,B,n,k-lenA);
        else if(A[lenA-1]>B[lenB-1])
            return recursive(A,m,B+lenB,n-lenB,k-lenB);
        else
            return A[lenA-1];
    }

public:
    double findMedianSortedArrays(int A[], int m, int B[], int n) {
        int len=m+n;
        
        if(len%2==1)
            return recursive(A,m,B,n,len/2+1);
        else
            return (recursive(A,m,B,n,len/2)+recursive(A,m,B,n,len/2+1))/2;
    }
};


(3) Divide Two Integers

任意一个整数可以表达为num=a0*2^0+a1*2^1+a2*2^2+...+an*2^n  (ai=0 or 1 , 0<=i<=n),所以a除以b的结果也可以用这个式子表达。基于以上这个公式以及左移一位相当于乘以2,我们先让除数左移直到大于被除数之前得到一个最大的基。然后接下来我们每次尝试减去这个基,如果可以则结果增加加2^k,然后基继续右移迭代,直到基为0为止。因为这个方法的迭代次数是按2的幂知道超过结果,所以时间复杂度为O(logn)。[4]

代码参考于[5],注意用位运算和long long,否则int会溢出:

class Solution {
public:
    int divide(int dividend, int divisor) {
        long long a=abs((long long)dividend);
        long long b=abs((long long)divisor);
        long long ret=0;
        bool flag=(dividend>0)^(divisor>0);
        
        while(a>=b)
        {
            long long t=b;
            for(int i=1;a>=t;t<<=1,i<<=1)
            {
                a-=t;
                ret+=i;
            }
        }
        return flag ? -ret :ret;
    }
};



参考:

[1] http://blog.csdn.net/ojshilu/article/details/22212703

[2] http://blog.csdn.net/linhuanmars/article/details/20342851

[3] http://blog.csdn.net/yutianzuijin/article/details/11499917

[4] http://blog.csdn.net/linhuanmars/article/details/20024907

[5] http://blog.csdn.net/kenden23/article/details/16986763

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值