剑指offer 试题51~60

来源:互联网 发布:美国windows vps 编辑:程序博客网 时间:2024/06/05 13:23

试题51:数组中的逆序对

在归并排序的过程中统计逆序对,经典题目了,也可以用树状数组,这里就不写了

class Solution {public:    int InversePairs(vector<int> data) {        if(data.size() == 0)            return 0;        vector<int> temp(data.size());        return mergeSort(data, temp, 0, data.size()-1);    }private:    int mergeSort(vector<int> &data, vector<int> &temp, int l, int r)    {        int ans = 0;        if(l < r)        {            int mid = (l + r) >> 1;            ans += mergeSort(data, temp, l, mid);            ans %= 1000000007;            ans += mergeSort(data, temp, mid+1, r);            ans %= 1000000007;            ans += Merge(data, temp, l, r, mid);            ans %= 1000000007;        }        return ans;    }    int Merge(vector<int> &data, vector<int> &temp, int l, int r, int mid)    {        int index = l, index1 = l, index2 = mid+1;        int ans = 0;        while(index1 <= mid && index2 <= r)        {            if(data[index1] <= data[index2])                temp[index++] = data[index1++];            else            {                temp[index++] = data[index2++];                ans = (ans + mid - index1 + 1) % 1000000007;            }        }        while(index1 <= mid)            temp[index++] = data[index1++];        while(index2 <= r)            temp[index++] = data[index2++];        for(int i = l; i <= r; ++i)            data[i] = temp[i];        return ans;    }};

试题52:两个链表的第一个公共节点

方法一:
把两个链表的节点分别压入栈中,根据栈的性质,栈顶即链表的尾部,让两个栈同时弹出节点,直到两个栈弹出的节点不相等,那么最后一次相等的节点就是两个链表的公共节点

class Solution {public:    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {        if(pHead1 == nullptr || pHead2 == nullptr)            return nullptr;        stack<ListNode*> stk1, stk2;        inStack(pHead1, stk1);        inStack(pHead2, stk2);        ListNode *ans = nullptr;        while(!stk1.empty() && !stk2.empty() && stk1.top() == stk2.top())        {            ans = stk1.top();            stk1.pop();            stk2.pop();        }        return ans;    }private:    void inStack(ListNode *pHead, stack<ListNode*> &stk)    {        while(pHead != nullptr)        {            stk.emplace(pHead);            pHead = pHead->next;        }    }};

方法二:
先计算出两个链表的长度,让较长的链表先往前走一段距离,使两者距离链表尾部的距离相等,然后两者一起向尾部走,直到走到两者相等,此时这个节点就是两个链表的第一个公共节点

class Solution {public:    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {        if(pHead1 == nullptr || pHead2 == nullptr)            return nullptr;        int len1 = countLen(pHead1);        int len2 = countLen(pHead2);        ListNode *ans = nullptr;        ListNode *curNode1 = pHead1, *curNode2 = pHead2;        if(len1 > len2)        {            while(len1-- > len2)                curNode1 = curNode1->next;        }        else if(len1 < len2)        {            while(len2-- > len1)                curNode2 = curNode2->next;        }        while(curNode1 != nullptr && curNode2 != nullptr && curNode1 != curNode2)        {            curNode1 = curNode1->next;            curNode2 = curNode2->next;        }        if(curNode1 != nullptr && curNode2 != nullptr)            ans = curNode1;        return ans;    }private:    int countLen(ListNode *pHead)    {        int len = 0;        while(pHead != nullptr)        {            ++len;            pHead = pHead->next;        }        return len;    }};

试题53:在排序数组中查找数字

数组既然是有序的,那么二分查找找到数字的第一个位置,再二分查找找到第一个大于此数字的位置,两个位置之间都是此数字,两个位置作差就是答案

class Solution {public:    int GetNumberOfK(vector<int> data ,int k) {        return upper_bound(data.begin(), data.end(), k) - lower_bound(data.begin(), data.end(), k);    }};

0~n-1中缺失的数字

class Solution {public:    int GetNumberOfDefect(vector<int> data) {        if(data.size() == 0)            return -1;        int ans = -1;        int l = 0, r= data.size() - 1;        while(l <= r)        {            int mid = (l + r) >> 1;            if(data[mid] != mid)                ans = mid, r = mid - 1;            else                l = mid + 1;        }        if(ans == -1)            ans = data.size();        return ans;    }};

数组中数值和下标相等的元素

class Solution {public:    int GetNumber(vector<int> data) {        int l = 0, r = data.size() - 1;        int ans = -1;        while(l <= r)        {            int mid = (l + r) >> 1;            if(data[mid] == mid)            {                ans = mid;                break;            }            else if(data[mid] < mid)                l = mid + 1;            else                r = mid - 1;        }        return ans;    }};

试题54:二叉搜索树的第k大节点

二叉搜索树的中序遍历就是有序的,那么只需要中序遍历二叉搜索树,并记录当前遍历的节点是中序遍历的第几个节点,遍历到第k个的时候就是答案

class Solution {public:    TreeNode* KthNode(TreeNode* pRoot, int k)    {        if(pRoot == nullptr || k <= 0)            return nullptr;        return _KthNode(pRoot, k);    }private:    TreeNode* _KthNode(TreeNode *pRoot, int &k)    {        TreeNode *ans = nullptr;        if(pRoot->left != nullptr)            ans = _KthNode(pRoot->left, k);        if(ans == nullptr)        {            if(--k == 0)                ans = pRoot;        }        if(ans == nullptr && pRoot->right != nullptr)            ans = _KthNode(pRoot->right, k);        return ans;    }};

试题55:二叉树的深度

用递归函数,用一个变量记录当前节点到根节点的距离,最大距离就是答案。

class Solution {public:    int TreeDepth(TreeNode* pRoot)    {        return _TreeDepth(pRoot, 0);    }private:    int _TreeDepth(TreeNode *pRoot, int dep)    {        if(pRoot == nullptr)            return dep;        return max(_TreeDepth(pRoot->left, dep+1), _TreeDepth(pRoot->right, dep+1));    }};

平衡二叉树
在求树的深度的过程中,检查其左右子树深度之差是不是不超过1即可

class Solution {public:    bool IsBalanced_Solution(TreeNode* pRoot) {        bool IsBalanced = true;        check(pRoot, 0, IsBalanced);        return IsBalanced;    }private:    int check(TreeNode *pRoot, int dep, bool &IsBalanced)    {        if(pRoot == nullptr)            return dep;        int leftDep = check(pRoot->left, dep+1, IsBalanced);        int rightDep = check(pRoot->right, dep+1, IsBalanced);        if(abs(leftDep - rightDep) > 1)            IsBalanced = false;        return max(leftDep, rightDep);    }};

试题56:数组中只出现一次的两个数字

数组只有两个数字各出现一次,其余数字都出现两次。
按照剑指offer上写的,确实巧妙

class Solution {public:    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {        int xor_sum = 0;        for(int i = 0; i < data.size(); ++i)            xor_sum ^= data[i];        int num = 0;        while(!(xor_sum & (1<<num)))            ++num;        vector<int> data1, data2;        for(int i = 0; i < data.size(); ++i)            if(data[i] & (1<<num))                data1.emplace_back(data[i]);            else                data2.emplace_back(data[i]);        *num1 = 0;        for(int i = 0; i < data1.size(); ++i)            *num1 = *num1 ^ data1[i];        *num2 = 0;        for(int i = 0; i < data2.size(); ++i)            *num2 = *num2 ^ data2[i];    }};

数组中唯一只出现一次的数字
数组中有一个数字只出现一次,其余数字都出现三次
求出每个数字的二进制表示,并统计每个二进制位上有多少个二进制1,然后把每个二进制位上1的个数取余3,剩下的就是只出现一次的那个数字的二进制表示

class Solution {public:    int FindNumsAppearOnce(vector<int> data) {        const int N = 40;        int bit[N];        memset(bit, 0, sizeof bit);        for(int i = 0; i < data.size(); ++i)        {            for(int j = 0; j < 32; ++j)                if(data[i] & (1<<j))                    ++bit[j];        }        int ans = 0;        for(int i = 31; i >= 0; --i)        {            ans <<= 1;            ans += bit[i] % 3;        }        return ans;    }};

试题57:和为s的数字

class Solution {public:    vector<int> FindNumbersWithSum(vector<int> array,int sum) {        vector<int> ans;        if(array.size() < 2)            return ans;        int l = 0, r = array.size() - 1;        while(l < r)        {            if(array[l] + array[r] == sum)            {                ans.emplace_back(array[l]);                ans.emplace_back(array[r]);                break;            }            else if(array[l] + array[r] > sum)                --r;            else                ++l;        }        return ans;    }};

和为s的连续正数序列

class Solution {public:    vector<vector<int> > FindContinuousSequence(int sum) {        vector<vector<int>> ans;        if(sum <= 0)            return ans;        int temp = 0, index_l = 1, index_r = 1;        while(index_r < sum)        {            temp += index_r;            index_r++;            while(temp > sum)            {                temp -= index_l;                ++index_l;            }            if(temp == sum)            {                vector<int> vec;                for(int i = index_l; i < index_r; ++i)                    vec.emplace_back(i);                ans.emplace_back(vec);            }        }        return ans;    }};

试题58:翻转单词顺序

class Solution {public:    string ReverseSentence(string str) {        if(str.size() == 0)            return str;        reverse(str.begin(), str.end());        int l = 0, r = 0;        while(r < str.size())        {            while(r < str.size() && str[r] == ' ')                ++r;            l = r;            while(r < str.size() && str[r] != ' ')                ++r;            for(int i = l, j = r-1; i < j; ++i, --j)                swap(str[i], str[j]);        }        return str;    }};

左旋转字符串

class Solution {public:    string LeftRotateString(string str, int n) {        reverse(str.begin(), str.end());        int index = str.size() - n;        for(int i = 0, j = index-1; i < j; ++i, --j)            swap(str[i], str[j]);        for(int i = index, j = str.size()-1; i < j; ++i, --j)            swap(str[i], str[j]);        return str;    }};

试题59:滑动窗口的最大值

class Solution {public:    vector<int> maxInWindows(const vector<int>& num, unsigned int size)    {        deque<int> que;        vector<int> ans;        if(num.size() < size)            return ans;        for(int i = 0; i < num.size(); ++i)        {            while(!que.empty() && num[que.back()] < num[i])                que.pop_back();            que.push_back(i);            if(i >= size-1)            {                while(! que.empty() && que.front() < i - size + 1)                    que.pop_front();                ans.emplace_back(num[que.front()]);            }        }        return ans;    }};

试题60:n个骰子的点数

牛客上没有这题,剑指offer上讲的很详细,不写了

原创粉丝点击