剑指offer刷题记录2

第二篇是后面的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();
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值