剑指offer 试题3~10

来源:互联网 发布:淘宝 授权怎么弄啊 编辑:程序博客网 时间:2024/05/22 01:28

所有试题代码都在牛客网上提交,牛客网的数据不算很强

试题3:数组中重复的数字

牛客网上此题是输出第一个重复的数字,排序后查找会错

class Solution{public:    // Parameters:    //        numbers:     an array of integers    //        length:      the length of array numbers    //        duplication: (Output) the duplicated number in the array number    // Return value:       true if the input is valid, and there are some duplications in the array number    //                     otherwise false    bool duplicate(int numbers[], int length, int* duplication)    {        bool flag = false;        for(int i = 0; i < length; ++i)        {            while(numbers[i] != i)            {                if(numbers[numbers[i]] == numbers[i])                {                    flag = true;                    *duplication = numbers[i];                    break;                }                swap(numbers[i], numbers[numbers[i]]);            }            if(flag) break;        }        return flag;    }};

试题4:二维数组中的查找

从右上角开始查找。当前位置数字大于被查找数字时,那么当前位置数字所在的列剩余数字都大于被查找数字,删掉。当前位置数字小于被查找数字时,那么当前位置数字所在的行剩余数字都小于被查找数字,删掉。重复这个过程,直到二维数组删尽或者找到被查找数字

class Solution {public:    bool Find(int target, vector<vector<int> > array) {        int row = array.size(), col = 0;        if(row != 0) col = array[0].size();        int x = 0, y = col-1;        while(x < row && y >= 0)        {            if(array[x][y] == target)            {                return true;            }            else if(array[x][y] > target)            {                --y;            }            else            {                ++x;            }        }        return false;    }};

试题5:替换空格

可以先计算出替换后字符串的长度,然后用双指针的方法从后往前开始替换,注意在新字符串末尾添加’\0’

class Solution {public:    void replaceSpace(char *str,int length) {        int cnt = 0;        int len = strlen(str);        for(int i = 0; i < len; ++i)        {            if(str[i] == ' ') cnt += 3;            else cnt += 1;        }        if(cnt + 1 > length) //+1是要在末尾添加一个'\0'            return;        str[cnt--] = '\0';        for(int i = len-1; i >= 0; --i)        {            if(str[i] == ' ')            {                str[cnt--] = '0';                str[cnt--] = '2';                str[cnt--] = '%';            }            else                str[cnt--] = str[i];        }    }};

试题6:从尾到头打印链表

最简单的是用递归,也可以用栈,或者先正序存进vector,然后翻转vector即可
用栈:

class Solution {public:    vector<int> printListFromTailToHead(ListNode* head) {        vector<int> ans;        stack<int> stk;        ListNode *ptr = head;        while(ptr != nullptr)        {            stk.emplace(ptr->val);            ptr = ptr->next;        }        while(! stk.empty())        {            ans.emplace_back(stk.top());            stk.pop();        }        return ans;    }};

翻转vector:

class Solution {public:    vector<int> printListFromTailToHead(ListNode* head) {        vector<int> ans;        ListNode *ptr = head;        while(ptr != nullptr)        {            ans.emplace_back(ptr->val);            ptr = ptr->next;        }        reverse(ans.begin(), ans.end());        return ans;    }};

试题7:重建二叉树

给定二叉树的先序和中序遍历,还原出二叉树。
对于一个子树的先序序列,第一个元素一定是子树的根,可以用这个元素把中序遍历划分成左右两个子树,然后递归处理

class Solution {public:    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {        int id = -1;        for(int i = 0; i < vin.size(); ++i)            if(vin[i] == pre[0])            {                id = i;                break;            }        if(id == -1) return nullptr;        TreeNode *ptr = new TreeNode(pre[0]);        if(id > 0)        {            vector<int> left_pre(pre.begin()+1, pre.begin()+id+1);            vector<int> left_vin(vin.begin(), vin.begin() + id);            ptr->left = reConstructBinaryTree(left_pre, left_vin);        }        if(id < vin.size() - 1)        {            vector<int> right_pre(pre.begin()+id+1, pre.end());            vector<int> right_vin(vin.begin()+id+1, vin.end());            ptr->right = reConstructBinaryTree(right_pre, right_vin);        }        return ptr;    }};

试题8:二叉树的下一个节点

求二叉树中序遍历的下一个节点。
分析可知:

  • 当前节点有右儿子的时候,分两种情况:其一,其右儿子没有左儿子,此时下一个节点就是其右儿子;其二,其右儿子有左儿子,那么就一直沿着左儿子往下走,走到不能走为止,此时得到的节点就是下一个节点。
  • 当前节点没有右儿子,那么沿着父节点往上走,直到遇到某个点不是其父亲的左儿子位置,那么这个父节点就是要求的下一个节点。
/*struct TreeLinkNode {    int val;    struct TreeLinkNode *left;    struct TreeLinkNode *right;    struct TreeLinkNode *next;    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {    }};*/class Solution {public:    TreeLinkNode* GetNext(TreeLinkNode* pNode)    {        if(pNode == nullptr)//当前节点为空,下一个节点元素空            return nullptr;        TreeLinkNode *ptr = nullptr;        if(pNode->right != nullptr)        {            pNode = pNode->right;            while(pNode->left != nullptr)                pNode = pNode->left;            ptr = pNode;        }        else if(pNode->next != nullptr)        {            while(pNode->next != nullptr && pNode->next->right == pNode)                pNode = pNode->next;            ptr = pNode->next;        }        return ptr;    }};

试题9:用两个栈实现队列

  • 入队:把元素直接压入栈1即可
  • 出队:如果栈2空,那么把栈1中的所有元素弹出并依次压入栈2。之后从栈2弹出一个元素即可
class Solution{public:    void push(int node) {        stack1.emplace(node);    }    int pop() {        int node;        if(! stack2.empty())        {            node = stack2.top();            stack2.pop();        }        else        {            while(! stack1.empty())            {                stack2.emplace(stack1.top());                stack1.pop();            }            node = stack2.top();            stack2.pop();        }        return node;    }private:    stack<int> stack1;    stack<int> stack2;};

两个队列实现一个栈

  • 压入:直接加入到队列1中
  • 弹出:把队列1中元素依次出队并依次加入到队列2中,当队列1只剩最后一个元素时,就是本次要弹出的元素。最后交换队列1和队列2,stl中可以实现O(1)交换
class Solution{public:    void push(int node) {        queue1.push(node);    }    int pop() {        int sz = queue1.size();        while(sz != 1)        {            queue2.emplace(queue1.front());            queue1.pop();            --sz;        }        int node = queue1.front();        queue1.pop();        queue1.swap(queue2);        return node;    }private:    queue<int> queue1;    queue<int> queue2;};

试题10:斐波那契数列

斐波那契数列:

  • fib[0] = 0
  • fib[1] = 1
  • fib[2] = fib[1] + fib[0] = 1
  • fib[n] = fib[n-1] + fib[n-2]

根据公式很好写出代码

class Solution {public:    int Fibonacci(int n) {        if(n == 0)            return 0;        else if(n == 1)            return 1;        else        {            int a = 0, b = 1, c;            for(int i = 2; i <= n; ++i)            {                c = a + b;                a = b;                b = c;            }            return c;        }    }};

跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法
分析可得:

  • f[1] = 1。显然只能从起点跳1级台阶到达,故一种方案
  • f[2] = f[1] + 1。可以从起点一次跳2级台阶,或者从台阶1跳1级台阶。
  • f[3] = f[2] + f[1]。可以从台阶1一次跳2级台阶,或者从台阶2跳1级台阶。
  • f[n] = f[n-1] + f[n-2]

可以发现递推式跟斐波那契数列一样

class Solution {public:    int jumpFloor(int number) {        if(number == 0)            return 0;        if(number == 1)            return 1;        int a = 1, b = 1, c;        for(int i = 2; i <= number; ++i)        {            c = a + b;            a = b;            b = c;        }        return c;    }};

变态跳台阶
跟跳台阶很类似,根据上述分析过程,可以发现,这题递推式:

  • f[0] = 0
  • f[1] = 1
  • f[2] = f[1] + 1
  • f[3] = f[2] + f[1] + 1
  • f[4] = f[3] + f[2] + f[1] + 1
  • f[n] = f[n-1] + f[n-2] + f[n-3] + … + f[2] + f[1] + 1
class Solution {public:    int jumpFloorII(int number) {        if(number == 0)            return 0;        int ans = 0, temp = 0;//temp是f[n-1] + f[n-2] + ... + f[2] + f[1]        for(int i = 1; i <= number; ++i)        {            ans = temp + 1;            temp += ans;        }        return ans;    }};

矩形覆盖
我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

分析如下:假设 n >= 2,那么如何得到f[n] ? 可以是从f[n-1]放一块1*2的小矩形,也可以是从f[n-2]放两块2*1的小矩形。那么递推式如下:

  • f[1] = 1
  • f[2] = 2
  • f[n] = f[n-1] + f[n-2]

跟跳台阶那题完全一样

class Solution {public:    int rectCover(int number) {        if(number == 0)            return 0;        if(number == 1)            return 1;        int a = 1, b = 1, c = 0;        for(int i = 2; i <= number; ++i)        {            c = a + b;            a = b;            b = c;        }        return c;    }};