剑指offer刷题记录2

来源:互联网 发布:python财经数据接口包 编辑:程序博客网 时间:2024/05/17 08:11

第二篇是后面的30题,不是那么容易做出来

1.统计一个数字在排序数组中出现的次数。

这个是两次binary search

class Solution {public:    int GetNumberOfK(vector<int> data ,int k) {        int number=0;        int length=data.size();        if(data.empty()!=true&&length>0){            int first=getfirstk(data,length,k,0,length-1);            int last=getlastk(data,length,k,0,length-1);            if(first>-1&&last>-1){                number=last-first+1;                        }        }            return number;    }    int getfirstk(vector<int>data,int length,int k,int start,int end){        if(start>end) return -1;        int middleIndex=(start+end)/2;        int middleData=data[middleIndex];        if(middleData==k){            if((middleIndex>0&&data[middleIndex-1]!=k)||middleIndex==0){                return middleIndex;            }            else                end=middleIndex-1;        }            else if(middleData>k)                end=middleIndex-1;            else                start=middleIndex+1;            return                 getfirstk(data,length,k,start,end);        }    int getlastk(vector<int>data,int length,int k,int start,int end){        if(start>end)            return -1;        int middleIndex=(start+end)/2;        int middleData=data[middleIndex];        if(middleData==k){            if((middleIndex<length-1&&data[middleIndex+1]!=k)||middleIndex==length-1)                return middleIndex;            else                start=middleIndex+1;        }        else if(middleData<k)            start=middleIndex+1;                else             end=middleIndex-1;        return getlastk(data,length,k,start,end);      }};

2.输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

class Solution {public:    bool IsPopOrder(vector<int> pushV,vector<int> popV) {        bool mark=false;        auto rush=pushV.begin();        auto pops=popV.begin();        int len=pushV.size();        stack<int> stacks;        if((pushV.size()!=popV.size())||(pushV.empty()))           return mark;        //stacks.push(*rush);        while((pops!=popV.end())){            while((stacks.empty()||(stacks.top()!=*pops))&&(rush!=pushV.end())){                stacks.push(*rush);                rush++;            }            if(stacks.top()!=*pops) break;            stacks.pop();            pops++;        }        if(stacks.empty()&&pops==popV.end()) mark=true;        return mark;    }};

3.输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。
这道题书本上的答案我感觉不太适合我自己,所以修改了一下然后通过了。

class Solution {public:    bool VerifySquenceOfBST(vector<int> sequence) {        if(sequence.empty()) return false;        return solve(sequence,0,sequence.size());    }    bool solve(vector<int>& nums,int begin,int end){        if(nums.empty()||(end-begin)<=0) return false;        int root=nums[end-1];        int i=begin;        for( ;i<end-1;i++){            if(nums[i]>root) break;        }        int j=i;        for(;j<end-1;j++){            if(nums[j]<root) return false;        }        bool left=true;        if(i>begin)left=solve(nums,begin,i);        bool right=true;        if(i+1<end-1)right=solve(nums,i+1,end);        return  left&&right;      }};

4.每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数….这样下去….直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)

注意这里要用list,如果用vector的erase的话,其在删除后会自动往后走一格。

class Solution {public:    int LastRemaining_Solution(int n, int m)    {        if(n<1||m<1) return -1;        list<int> nums;        for(int i=0;i<n;i++){            nums.push_back(i);        }        auto it=nums.begin();        while(nums.size()>1){            for(int i=1;i<m;i++){                it++;                if(it==nums.end()){                    it=nums.begin();                }                        }                       auto next=++it;            if(next==nums.end()){                next=nums.begin();            }            it--;            nums.erase(it);            it=next;                }        return nums.front();    }};

5.输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。
输入描述:
输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

注意set可以去重和排序

class Solution {public:    set<string> result;    vector<string> Permutation(string str) {        if(str.empty()) return vector<string>(result.begin(),result.end());        permute(str,0);        return vector<string>(result.begin(),result.end());    }    void permute(string str,int begin){        if(begin==str.size()){            result.insert(str);            return ;        }        for(int i=begin;i<str.size();i++){            //if(i!=begin&&str[i]==str[i-1])continue;            swap(str[begin],str[i]);            permute(str,begin+1);            swap(str[begin],str[i]);        }    }};

6.小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

class Solution {public:    vector<vector<int> > FindContinuousSequence(int sum) {        vector<vector<int>> result;        if(sum<3){            return result;        }        int small=1,big=2,middle=(1+sum)/2;        int cursum=small+big;        while(small<middle){            if(cursum==sum){                vector<int> res;                for(int i=small;i<=big;i++){                    res.push_back(i);                }                result.push_back(res);                        }            while(small<middle&&cursum>sum){                cursum-=small;                small++;                if(cursum==sum){                    vector<int> res;                    for(int i=small;i<=big;i++){                        res.push_back(i);                    }                    result.push_back(res);                            }            }            big++;            cursum+=big;        }        return result;    }};

7.将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0
输入描述:
输入一个字符串,包括数字字母符号,可以为空
输出描述:
如果是合法的数值表达则返回该数字,否则返回0

class Solution {public:    int StrToInt(string str) {        if(str.empty()) return 0;        int i=0;        for(;i<str.size();i++){            if(str[i]!=' ') break;                    }        str=str.substr(i);        int j;        for(j=str.size()-1;j>=0;j--){            if(str[j]!=' ') break;        }        str=str.substr(0,j+1);        long long num=0;        int mark=1;        i=0;        if(str[i]=='-') {mark=-1;i++;}        else if(str[i]=='+'){mark=1;i++;}        for(;i<str.size();i++){            if((str[i]<='9')&&(str[i]>='0')) num=(str[i]-'0')+num*10;              else return 0;        }        return num*mark;    }};

8.在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

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) {        if(length<=0||numbers==NULL) return false;        vector<int> nums;        for(int i=0;i<length;i++){            if(numbers[i]<0||numbers[i]>length-1){                return false;            }              nums.push_back(numbers[i]);                    }        for(int i=0;i<length;i++){            while(nums[i]!=i){                if(nums[i]==nums[nums[i]]){                    *duplication=nums[i];                    return true;                }                swap(nums[i],nums[nums[i]]);            }        }        return false;    }};

9.一个链表中包含环,请找出该链表的环的入口结点。

思路:首先算出环的节点个数,就是快慢指针(一个每次走一步,一个走两步)第一次碰撞后,开始计数直到第二次碰撞,这个数就是环节点个数k。然后让快慢指针(一个先走k步,为快指针)从头开始走,都是每次走一步,直到他们碰撞就是环入口节点。因为快指针就是比慢指针快环的长度。

/*struct ListNode {    int val;    struct ListNode *next;    ListNode(int x) :        val(x), next(NULL) {    }};*/class Solution {public:    ListNode* EntryNodeOfLoop(ListNode* pHead)    {        if(!pHead) return NULL;        ListNode* head=pHead;        ListNode* fast=head,*slow=head;        while(fast&&fast->next){                fast=fast->next->next;                slow=slow->next;                if(fast==slow) break;        }        if((fast==NULL)||(fast->next==NULL)) return NULL;        int num=0;        while(1){            fast=fast->next->next;            slow=slow->next;            num++;            if(fast==slow) break;        }        fast=head;        slow=head;        while(num--){            fast=fast->next;        }        while(fast!=slow){            fast=fast->next;            slow=slow->next;        }        return fast;    }};

10.给定一颗二叉搜索树,请找出其中的第k大的结点。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按结点数值大小顺序第三个结点的值为4。
这道题按理说不难,就是中序遍历然后是第k个数,但是还是花了一些时间。因为忘记中序遍历怎么写了。

/*struct TreeNode {    int val;    struct TreeNode *left;    struct TreeNode *right;    TreeNode(int x) :            val(x), left(NULL), right(NULL) {    }};*/class Solution {public:    TreeNode* result=NULL;    int begin=0;    TreeNode* KthNode(TreeNode* pRoot, int k)    {        if(!pRoot) return pRoot;        if(k==0) return NULL;        dfs(pRoot,k);        return result;    }    void dfs(TreeNode* root,int k){        if(!root) return ;                      if(root->left) dfs(root->left,k);          begin++;        if(begin==k) {result=root;return;}               if(root->right) dfs(root->right,k);            }};

11.给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

要分三种情况考虑
1.如果一个节点有右子树,那么他的下一个节点就是他的右子树中的最左子节点
2.如果其没有右子树,而且他是父节点的左子树,那么就是其父节点
3.如果没有右子节点,而且它还是其父节点的右子节点,那么就一直往上走,直到找到一个是它父节点的子节点的左子节点的节点。

/*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)    {        TreeLinkNode* root=pNode;        if(!root) return NULL;        TreeLinkNode* nextnode=NULL;        if(root->right){            TreeLinkNode* rightnode=root->right;            while(rightnode->left)                rightnode=rightnode->left;            nextnode=rightnode;        }        else if(root->next){            TreeLinkNode* current=root;            TreeLinkNode* parent=root->next;            while(parent&&current==parent->right){                current=parent;                parent=parent->next;            }            nextnode=parent;        }        return nextnode;     }};

12.如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
这道题是别人做出来的。

class Solution {    priority_queue<int, vector<int>, less<int> > p;    priority_queue<int, vector<int>, greater<int> > q;public:    void Insert(int num){        if(p.empty() || num <= p.top()) p.push(num);        else q.push(num);        if(p.size() == q.size() + 2) q.push(p.top()), p.pop();        if(p.size() + 1 == q.size()) p.push(q.top()), q.pop();    }    double GetMedian(){       return p.size() == q.size() ? (p.top() + q.top()) / 2.0 : p.top();    }};
原创粉丝点击