牛客剑指offer刷题记录(二)

来源:互联网 发布:mfc编程实例 2008 编辑:程序博客网 时间:2024/05/21 04:23

旋转数组的最小数字

旋转数组是指有序数组进行右移之后的得到数组。

要求数组中的最小数字,O(n)复杂度就可以搞定,如果要高效一点,需要用到二分查找的思路。

事实上,除了处理简单45123这样的序列,还得考虑有重复数字出现的旋转数组,例如11000

class Solution {public:    int minNumberInRotateArray(vector<int> rotateArray) {        int l=0;        int r=rotateArray.size()-1;        int m=0;        while(l<r)        {            m=l+(r-l)/2;            if(rotateArray[m]<rotateArray[r])            {                r=m;            }            else if(rotateArray[m]>rotateArray[r])            {                l=m+1;            }            else//相等只有减小Upper Bound            {                --r;            }        }        return rotateArray[l];    }};

斐波拉切数列

f(n)=f(n1)+f(n2)
这是斐波拉切数列的方程,可以直接递归去做,也可以迭代计算,我这里用迭代的方式做:

class Solution {    public:    int Fibonacci(int n)     {        if(0==n)            return 0;        if(1==n)            return 1;        int a1=1;        int a0=0;        int res;        for(int i=2;i<=n;++i)        {            res=a0+a1;            a0=a1;            a1=res;        }        return res;    }};

跳台阶

理解一下题意的话,就是斐波拉切数列的变种。

class Solution {public:    int jumpFloor(int number) {        if(1==number)            return 1;        if(2==number)            return 2;        int n1=1;        int n2=2;        for(int i=0;i<number-2;++i){            int tmp=n2;            n2+=n1;            n1=tmp;        }        return n2;    }};

变态跳台阶

f(n)=f(n1)+...f(1)+f(0)
f(n1)=f(n2)+...f(1)+f(0)
推出:
f(n)=2f(n1)
推出:
f(n)=2(n1)

class Solution {public:    int jumpFloorII(int number) {        if(number<=0)            return 0;        return pow(2,number-1);    }};

矩形覆盖

同样是斐波拉契数列

class Solution {public:    int rectCover(int number) {        //number==1 1        //number==2 2        if(number<=0)            return 0;        if(number==1)            return 1;        if(number==2)            return 2;        int n1=1;        int n2=2;        for(int i=0;i<number-2;++i){            int tmp=n2;            n2+=n1;            n1=tmp;        }        return n2;    }};

二进制有多少个1

通过n&n-1这个操作可以把原来n所表示的二进制中最右边的1变成0,那么有多少次这样的操作,就表示有多少个1.

class Solution {public:     int  NumberOf1(int n) {         int count=0;         while(n)         {             ++count;             n=n&(n-1);         }         return count;     }};

数值的整数次方

这题就是自己实现一个pow函数,并不难,在于优化。

比如2的4次方,可以两组两组相乘,2的5次方可以两组两组相乘之后再乘以基数。这就是考虑奇数与偶数次幂的情况了。

class Solution {    double help(double base, int exponent)    {        if (exponent == 0)            return 1;        if (exponent == 1)            return base;        double tmp = help(base, exponent / 2);        tmp*=tmp;        if ((exponent & 1) == 1)            tmp *= base;        return tmp;    }public:    double Power(double base, int exponent) {        int flag = false;        if (exponent < 0)        {            exponent = -exponent;            flag = true;        }        double res = help(base, exponent);        if (flag)            res = 1 / res;        return res;    }};

奇数位于偶数之前

剑指offer上的解法不能保证原有次序,思路是:
1.从前往后找到第一个偶数
2.从后往前找到第一个奇数

交换之。

class Solution {public:    void reOrderArray(vector<int> &array) {        int odd = 0;        int even = array.size() - 1;        while (odd < even)        {            while (odd < even && (array[odd] & 1) == 1)                ++odd;            while (odd < even && (array[even] & 1) == 0)                --even;            if (odd < even)            {                swap(array[odd], array[even]);            }        }    }};

而牛客上面要求新的序列不改变原来的次序,这样的话,可以重新开辟一个新的数组来保存。

class Solution {public:    void reOrderArray(vector<int> &array) {        vector<int>tmp;        tmp.reserve(array.size());        for(int i=0;i<array.size();++i){            if((array[i]&0x1)==1)                tmp.push_back(array[i]);        }        for(int i=0;i<array.size();++i){            if((array[i]&0x1)==0)                tmp.push_back(array[i]);        }        array.swap(tmp);    }};

链表中的倒数第K个节点

一个简单的办法就是,倒数第K个节点实际上就是顺数第n-K+1个节点,于是需要遍历两次。

有一个思路是,需要两个指针,第一个指针先走k-1步到第k个节点,第二个指针不动,然后两个指针再一起往后直到链表结尾,那么第二个指针便是倒数第k个节点了。

因为第k个节点是倒数n-k+1个节点,走到头,需要走n-k步,第一个个指针同时走n-k步就到了n-k+1个节点了。

/*struct ListNode {    int val;    struct ListNode *next;    ListNode(int x) :            val(x), next(NULL) {    }};*/class Solution {public:    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {        ListNode*p=pListHead;        int i=k;        while(i--){            if(NULL==p)                return NULL;            p=p->next;        }        ListNode*r=pListHead;        while(p!=NULL){            p=p->next;            r=r->next;        }        return r;    }};