剑指offer——优化时间和空间效率

来源:互联网 发布:用matlab求矩阵方程 编辑:程序博客网 时间:2024/05/29 07:09

剑指offer——优化时间和空间效率

1. 时间效率

面试题29:数组中出现次数超过一半的数字

/*解法一思想:排序后位于中间的数字就是所求数字,中位数(数组第n/大数字)*///基于快排Partition函数的O(n)算法int MoreThanHalfNum(int* numbers,int length){    if (CheckInvalidArray(numbers,length))        return 0;    int middle = lenght >> 1;    int start = 0;    int end = length - 1;    int index = Partition(numbers,length,start,end);    while (index != middle) {        if (index > middle){            end = middle - 1;            index = Partition(numbers,length,start,end);        }        else{            start = middle + 1;            index = Partition(numbers,length,start,end);        }    }    int result = numbers(middle);       if (!CheckMoreThanHalf(number,length,result))        result = 0;    return result;}bool g_bInputInvalid = false;bool CheckInvalidArray(int* numbers,int length){    g_bInputInvalid = false;    if (numbers == NULL || lenght<=0 )        g_bInputInvalid = true;    return g_bInputInvalid;}int Partition(int* numbers,int length,int start,int end){    if (numbers == NULL ||  lenght<=0 || start <0 || end>= length)        throw new exception("Invalid Parameters");    int index = RandomInRange(start,end);//生成一个start到end之间的随机数    Swap(&numbers[index],&numbers[end]);    int small = start - 1;    for (index = start;index<end;++index){        if (numbers[index] < numbers[end]){            ++small;            if (small != index)                Swap(&numbers[index],&numbers[small]);        }    }    ++small;    Swap(&numbers[small],&numbers[end]);    return small;}//判断中位数出现的次数是否超过一半bool CheckMoreThanHalf(int *number,int length,int result){    int times = 0;    for (int i = 0;i< length;i++){        if (numbers[i] == numbers)            times++;    }    bool isMoreThanHalf = true;    if (times*2 <= length){        g_bInputInvalid = true;        isMoreThanHalf = false;    }    return isMoreThanHalf;}/*解法二思想:所求数字出现的次数比其他所有数字出现的次数的和还要大;遍历数组并保存两个数字:一个数组数字,一个次数(若下一个数组元素与当前数字相同,次数加一,否则次数减一;若次数为0,则保存下一个数组元素并设置次数为一。所求数字就是最后保存的数组元素)*/int MoreThanHalfNum(int* numbers,int length){    if (CheckInvalidArray(numbers,length))        return 0;    int result = numbers[0];    int times = 1;    for (int i=1;i<length;++i){        if (times == 0){            result = numbers[i];            times = 1;        }        else if (numbers[i] == result)            times++;        else            times--;    }    if (!CheckMoreThanHalf(number,length,result))        result = 0;    return result;}//注意:解法一会修改输入的数组!!!

面试题30:最小的k个数

//解法一:基于Partition函数的O(n)算法,会修改输入数组,不适合海量数据*/void GetLeastNumbers(int *input,int n,int* output,int k){    if (input == NULL || output==NULL || k>n ||n<=0 || k<=0)        return;    int start = 0;    int end = length - 1;    int index = Partition(numbers,length,start,end);    while (index != k-1)    {        if (index > k-1){            end = middle - 1;            index = Partition(numbers,length,start,end);        }        else{            start = middle + 1;            index = Partition(numbers,length,start,end);        }    }    for (int i=0;i<k;++i)        output[i] = input[i];}//基于堆或红黑树的O(nlogk)算法,适合海量数据且不会修改输入数组*//*创建一个大小为k的数据容器,遍历数组,若容器内元素少于k个,直接将读取的数组元素存入容器;若容器元素是k个,比较读取的数组元素和容器最大元素,将较小者存入容器。红黑树种查找,删除和插入操作都是O(logk)*/typedef multiset<int,greater<int>> inSet;typedef multiset<int,greater<int>>::iterator setIterator;void GetLeastNumbers(const vector<int>& data,inSet& leastNumbers,int k){    leastNumbers.clear();       if (k<1 || data.size()<k)        return;    vector<int>::const_iterator iter = data.begin();    for(;iter!=data.end();++iter){        if ((leastNumbers.size()) < k)            leastNumbers.insert(*iter);        else{            setIterator iterGreatest = leastNumbers.begin();                if (*iter < *(leastNumbers.begin())){                leastNumbers.erase(iterGeatest);                leastNumbers.insert(*iter);            }        }    }}

面试题31:连续子数组的最大和

//解法一:举例分析数组规律bool g_InvalidInput = false;int FindGreatestSumOfSunArray(int *pData,int nLength){    if ((pData == NULL) || (nLength<=0)){         g_InvalidInput = true;        return 0;    }    g_InvalidInput = false;    int nCurSum = 0;    int nGreatestSum = -INF;    int cur_low = 0;    int low,high;//最大子数组的位置    for (int i=0;i<nLength;++i){        nCurSum += pData[i];        if (nCurSum <= 0){            nCurSum = 0;            cur_low = i+1;        }        else if (nCurSum > nGreatestSum){            nGreatestSum = nCurSum;            low = cur_low;            high = i;        }     }    if (nGreatestSum > -INF) return(low,high,nGreatestSum);}//解法二:应用动态规划法/*f(i)表示以第i个数字结尾的子数组的最大和,目标就是max(f(i)),0<=i<n  若i=0或f(i-1)<=0,则f(i)=pData[i];  若i!=0且f(i-1)>0,则f(i)=f(i-1)+pData[i];*///代码与上面一致//解法三:分治法求解最大子数组/*数组分为两个子数组,最大子数组有三种情况:完全位于左边数组或右边数组,跨越分布于两个子数组*/int FindMaxSubArray(int* data,int low,int high){    if (low==high)        return (low,high,data[low]);    else{        int mid = (low+high)/2;        (left_low,left_high,left_sum) = FindMaxSubArray(data,low,mid);        (right_low,right_high,right_sum) = FindMaxSubArray(data,mid+1,high);        (cross_left,cross_high,cross_sum) = FindMaxCrossArray(data,low,mid,high);        //比较left_sum,right_sum和cross_sum返回最大值    }}int FindMaxCrossArray(int* data,int low, int mid,int high){    int left_sum = -INF;    int sum = 0;    int max_left,max_right;    for (int i=mid;i>=low;--mid){        sum = sum + data[i];        if (sum > left_sum){            left_sum = sum;            max_left = i;        }    }    sum=0;    int right)sum=-INF;    for (int i=mid;i<high;++mid){        sum = sum + data[i];        if (sum > right_sum){            right_sum = sum;            max_right = i;        }    }    return(max_left,max_right,left_sum+right_sum);}

面试题32:从1到n整数中包含1出现的次数

/*解法一:计算每个整数1的次数,需要大量计算不可取*///解法二:int NumberOf1Between1AndN(int n){    if (n<=0)        return 0;    char strN[50];    sprintf(strN,"%d",n);//把格式化的数据写入字符串中,123->"123"    return NumberOf1(strN);}int NumberOf1(const char *strN){    if (strN==NULL || *strN < '0' || *strN >'9' || *strN == '\0')        return 0;    int first = *strN-'0';//最高位    unsigned int length = static_cast<unsigned int>(strlen(strN));    if (length == 1 && first == 0)        return 0;    if (length == 1 && first > 0)        return 1;    int numFirstDigit = 0;    if (first>1)        //numFirstDigit是10000~19999最高位1的个数        numFirstDigit = PowerBase10(length-1);    else if (first==1)        ////numFirstDigit是10000~n最高位1的个数        numFirstDigit = atoi(strN+1)+1;//atoi将字符串转换成整型数    //假设n=21345,numOtherDigits是1346~21345除最高位外的数位中1的个数    int numOtherDigits = first*(length-1)*PowerBase10(length-2);    //逐个求解1~1345中1的个数    int numRecursive = NumberOf1(strN+1);    return numFirstDigit+numOtherDigits+numRecursive;}int PowerBase10(unsigned int n){    int result = 1;    for (unsigned int i=0;i<n;i++)        result *= 10;    return result;}

面试题33:把数组排成最小的数

const int g_MaxNumberLength = 10;char *g_StrCombine1 = new char[g_MaxNumberLength*2+1];char *g_StrCombine2 = new char[g_MaxNumberLength*2+1];void PrintMinNumber(int *numbers,int length){    if (numbers == NILL || length <=0)        return;    char **strNumbers = char(**)(new int[length]);    for (int i=0;i<length;++i){        strNumbers[i] = new char[g_MaxNumberLength+1];        sprintf(strNumbers[i],"%d",numbers[i]);    }    //qsort根据你给的比较条件给一个快速排序,排序之后的结果仍然放在原来数组中    /*void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )    int compare (const void *elem1, const void *elem2 ) );    第一个参数 base 是 需要排序的目标数组名(或者也可以理解成开始排序的地址,因为可以写&s[i]这样的表达式)    第二个参数 num 是 参与排序的目标数组元素个数    第三个参数 width 是单个元素的大小(或者目标数组中每一个元素长度),推荐使用sizeof(s[0])这样的表达式    第四个参数 compare 就是让很多人觉得非常困惑的比较函数啦*/    qsort(strNUmbers,length,sizeof(char*),compare);    for (int i=0;i<length;++i)        printf("%s",strNumbers[i]);    printf("\n");    for (int i=0;i<length;++i)        delete[] strNumbers[i];    delete[] strNumbers;}int compare(const void *strNumber1,const void* strNumber2){    strcpy(g_StrCombine1,*(const char **)strNumber1);    strcat(g_StrCombine1,*(const char **)strNumber2);    strcpy(g_StrCombine2,*(const char **)strNumber2);    strcat(g_StrCombine2,*(const char **)strNumber1);    return strcmp(g_StrCombine1,g_StrCombine2);}

2. 时间效率与空间效率的平衡

面试题34:第k个丑数(只包含因子2,3,5的数)

//解法一:/*逐个判断每个整数是不是丑数,不高效*/int GetUglyNumber_Solution1(int index){    if (index <=0)        return 0;    int number = 0;    int uglyFount = 0;    while (uglyFound < index){        ++number;        if (IsUgly(number))            ++uglyFound;    }    return number;}bool IsUgly(int number){    while (number%2==0)        number = number/2;    while (number%3==0)        number = number/3;    while (number%5==0)        number = number/5;    return (number==1)? true:false;}//解法二:创建数组保存已找到的丑数int GetUglyNumber_Solution2(int index){    if (index <=0)        return 0;    int *pUglyNumbers = new int[index];    pUglyNumbers[0] = 1;    int nextUglyIndex = 1;    int *pMultiply2 = pUglyNumbers;    int *pMultiply3 = pUglyNumbers;    int *pMultiply5 = pUglyNumbers;    while (nextUglyIndex<index){        int min = Min(*pMultiply2*2,*pMultiply3*3,*pMultiply5*5);        pUglyNumbers[nextUglyIndex] = min;        while (*pMultiply2*2 <= pUglyNumbers[nextUglyIndex])            ++pMultiply2;        while (*pMultiply3*3 <= pUglyNumbers[nextUglyIndex])            ++pMultiply3;        while (*pMultiply5*5 <= pUglyNumbers[nextUglyIndex])            ++pMultiply5;        ++nextUglyIndex;    }    int ugly = pUglyNumbers[nextUglyIndex-1];    delete[] pUglyNumbers;    return ugly;}int Min(int number1,int number2,int number3){    int min = (number1<number2)?number1:number2;    min = (min<number3)?min:number3;    return min;}

面试题:第一个只出现一次的字符

char FirstNotRepeatingChar(char *pString){    if (pString==NULL)        return '\0';    const int tableSize = 256;//ACSII 8位,Unicode 16位    unsigned int hashTable[tableSize];    for (unsigned int i=0;i<tableSize;++i)        hashTable[i] = 0;    char *pHashKey = pString;    while (*(pHashKey) !='\0')        hashTable[*(pHashKey++)]++;    char *pHashKey = pString;    while (*(pHashKey) !='\0'){        if (hashTable[*pHashKey] == 1)             return *pHashKey;        ++pHashKey;    }    return '\0';}/*举一反三:如果需要判断字符在字符串中出现的次数,可以考虑基于数组创建一个哈希表,以较小的空间消耗换取时间效率*/

面试题36:数组中的逆序对

/*基于归并排序*/int InversePairs(int *data,int length){    if (data == NULL || length <= 0)        return 0;    int *copy = new int[length];    for (int i=0;i<length;++i)        copy[i] = data[i];    int count = InversePairsCore(data,copy,0,length-1);    delete[] copy;    return count;}int InversePairsCore(int *data,int *copy,int start,int end) {    if (start == end){        copy[start] = data[end];        return 0;    }    int length = (end-start)/2;    int left = InversePairsCore(data,copy,start,start+length);    int right = InversePairsCore(data,copy,start+length+1,end);;    int i = start+length;    int j = end;    int indexCopy = end;    int count = 0;    while (i>=start && j>=start+length+1){        if (data[i] > copy[j]){            copy[indexCopy--] = data[i--];            count += j-start-length;        }        else{            copy[indexCopy--] = data[j--];        }    }    for (;i>=start;--i)        copy[indexCopy--] = data[i];    for (;j>=start+length;--i)        copy[indexCopy--] = data[j];    return left+right+count;}

面试题37:两个链表的第一个公共结点

struct ListNode{    int m_nValue;    ListNode *m_pNext;};ListNode* FindFirstCommonNode(ListNode *pHead1,ListNode *pHead2){    unsigned int nLength1 = GetListLength(pHead1);    unsigned int nLength2 = GetListLength(pHead2);    int nLengthDif = nLength1 - nLength2;    ListNode *pListHeadLong = pHead1;       ListNode *pListHeadShort = pHead2;    if (nLength1 < nLength2 ){        pListHeadLong = pHead2;         pListHeadShort = pHead1;        nLengthDif = nLength2 - nLength1;    }    for (int i=0;i<nLengthDif;++i)        pListHeadLong = pListHeadLong->m_pNext;    while ((pListHeadLong !=NULL) && (pListHeadShort !=NULL) && (pListHeadLong !=pListHeadShort)){        pListHeadLong = pListHeadLong->m_pNext;        pListHeadShort = pListHeadShort->m_pNext;    }    ListNode *pFirstCommonNode = pListHeadLong;    return pFirstCommonNode;}int GetListLength(ListNode *pHead){    unsigned int nLength = 0;    ListNode *pNode = pHead;    while (pNode->m_pNext != NULL){        nLength++;        pNode = pNode->m_pNext;    }    return nLength;}
阅读全文
0 0
原创粉丝点击