• 剑指offer习题集2


    1.把数组排成最小的数

    class Solution {
    public:
         
        static bool compare(const string& s1, const string& s2) {  
            string t1 = s1 + s2;   
            string t2 = s2 + s1;
            return t1 <= t2? true : false;
        }
         
        string PrintMinNumber(vector<int> numbers) {
         
            string str;
            int i, len = numbers.size();   
            if (len<1) return str;
         
            string res;
            vector<string> vt;
            for (i = 0;i<len;++i) { 
                stringstream stream;       
                stream << numbers[i];    
                stream >> str;       
                vt.push_back(str);
            }
         
            sort(vt.begin(), vt.end(), compare);   
            for (i = 0;i<len;++i)       
                res += vt[i];  
            return res;
        }
    };
    View Code

    这里使用string会比使用char*更加快捷方便。

    另外使用sort而不是qsort,主要是sort是qsort的升级,且参数更少,不需要制定每个参数占据的内存空间大小。

    2.字符流中第一个不重复的字符

    少有的一遍通过的程序,眼泪都快流下来了

    class Solution
    {
    public:
        
        Solution():index(0){ //初始化位置
            for(int i=0;i<256;++i)
                pos[i]=-1;
        }
        
        
      //Insert one char from stringstream
        void Insert(char ch)
        {
             if(pos[ch]==-1)
                 pos[ch]=index;
             else if(pos[ch]>=0)
                 pos[ch]=-2;
                 
             ++index;
        }
        
        
      //return the first appearence once char in current stringstream
        char FirstAppearingOnce()
        {  
            char res='#';
            int minv=1e8,i; //设置字符串max值
            for(i=0;i<256;++i){
                if(pos[i]>=0&&pos[i]<minv){ //若是当前位置小于min,则对min进行更新
                    res=(char)i;
                    minv=pos[i];
                }  
            }
            
            return res;
        }
        
    private:
        int index;
        int pos[256];
    };
    View Code

    3.求滑动窗口最大值

    还是不能一遍通过,而且思维定式,真的很难找到错误的

    class Solution {
    public:
        vector<int> maxInWindows(const vector<int>& num, unsigned int size)
        {
            int i,j,k,len=num.size();
            vector<int> result;
            if(len<size||size==0) 
                return result;
            
            int max=num[0];
            for(i=1;i<size;++i){ //先寻找第一个窗口的最大值
                if(max<num[i])
                    max=num[i];
            }
            result.push_back(max);
            
            for(i=1;i<=(len-size);++i){
                j=i+size-1;
                if(num[j]<max){
                    //判断最大值是否移出滑动窗口
                    if(num[i-1]!=max)
                        result.push_back(max);
                    else{ //确定最大值被移出滑动窗口,重新确定最大值
                        max=num[i];
                        for(k=i;k<=j;++k){
                            if(num[k]>max)
                                max=num[k];
                        }
                        result.push_back(max);
                    }
                }else{
                    result.push_back(num[j]);
                    max=num[j];
                }               
            }
            return result;
        }
    };
    View Code

    4.表示数值的字符串(最耗人心力的程序,没有之一)

    有空多做几遍,绝对练耐心

    class Solution {
    public:
        
        bool isdigit(const char& ch){
            if(ch<='9'&&ch>='0')
                return true;
            else return false;
        }
        
        void scandigits(char** str){
            while(**str!=''&&isdigit(**str))
                ++(*str);
        }
        
        bool isexpand(char** str){
            if(**str!='E'&&**str!='e')
                return false;
            
            ++(*str);
            if(**str=='+'||**str=='-')
                ++(*str);
            
            if(**str=='')
                return false;
            
            scandigits(str);
            return (**str=='')?true:false;
        }
        
        bool isNumeric(char* strt)
        {
            if(NULL==strt)
                return false;
            
            bool digit=true;
            char *str=strt;
            
            //排除符号干扰,找到第一个数字
            while(str){
                if(*str=='+'||*str=='-'){
                    ++str;break;
                }else if(isdigit(*str)){
                    break; //找到第一个数字
                }
            }
            if(*str=='') return false;
            
            scandigits(&str);
            if(*str!=''){
                //针对小数进行处理
                if(*str=='.'){
                    ++str;
                    scandigits(&str);
                    
                    if(*str=='e'||*str=='E')
                        digit=isexpand(&str);
                }else if(*str=='E'||*str=='e'){
                    digit=isexpand(&str);  
                }else{
                    digit=false;
                }
            }
             
            return digit&&(*str=='');
        }
    
    };
    View Code

    5.字符串的排列

    《剑指offer》上针对的是无重复字符串的全排列递归做法。

    下面贴的是对重复字符进行处理了的全排列递归做法,为了通过测试集,对字符串进行了排序。

    class Solution {
    public:
         
        vector<string> Permutation(string str) {
             
            vector<string> res;
            int len=str.length();
            if(0==len) return res;
            else if(1==len){
                res.push_back(str); return res;
            }
             
            int left=0,right=len-1;
            Permutation(str,left,right,res);
            sort(res.begin(),res.end());
            return res;
        }
         
        //递归实现字符交换
        void Permutation(string& str,int left,int right,vector<string>& res){
             
            if(left==right){
                res.push_back(str);
            }else{
                for(int i=left;i<=right;++i){
                    if(isswap(str,left,i)){
                        swap(str[i],str[left]);
                        Permutation(str,left+1,right,res);
                        swap(str[i],str[left]);
                    }
                }
            }
        }
         
    private:
        void swap(char& a,char& b){
            char t=a;a=b;b=t;
        }
         
        bool isswap(const string& str,const int& left,const int& right){
            for(int i=left;i<right;++i)
                if(str[i]==str[right])
                    return false;
            return true;
        } 
    };
    View Code

    后续会添加相应的非递归做法。

    另外,此题可以扩展为多个子问题,待后续一一解决。

    6.求旋转数组的最小数

    没有通过测试集,不过自行调试,觉得程序应该是正确的啊

    class Solution {
    public:
        int minNumberInRotateArray(vector<int> rotateArray) {
    
            int len = rotateArray.size();
            if (0 == len) return 0;
            else if (1 == len) return rotateArray[0];
    
            int left = 0, right = len - 1, mid;
            while (rotateArray[left] >= rotateArray[right]) {
    
                if (right - left == 1) {
                    mid = right;break;
                }
    
                mid = left + (right - left) / 2;
    
                //如果下标为left/right/mid指向的三个数字相等
                if (rotateArray[left] == rotateArray[right] &&
                    rotateArray[left] == rotateArray[mid]) {
                    //顺序查找最小元素
                    return mininorder(rotateArray, left, right);
                }
    
                if (rotateArray[mid] >= rotateArray[left]) {
                    left = mid;
                }
                else if (rotateArray[mid] <= rotateArray[right]) {
                    right = mid;
                }
            }
    
            return rotateArray[mid];
        }
    
    private:
        int mininorder(const vector<int>& rotateArray, const int& left, const int& right) {
            int min = rotateArray[left];
            for (int i = left + 1;i <= right;++i) {
                if (rotateArray[i]<min)
                    min = rotateArray[i];
            }
            return min;
        }
    };
    View Code

    7.扑克牌顺子

    class Solution {
    public:
        bool IsContinuous( vector<int> numbers ) {
            
            int len=numbers.size();
            if(len<=1) return false;
            
            //进行排序
            sort(numbers.begin(),numbers.end());
            
            int i=0,zeronum=0,gap,numgap=0;
            for(i=0;i<len;i++){
                if(numbers[i]==0)
                    ++zeronum;
                else break;
            }
            
            //从非零的下一个位置开始进行计算
            for(i=i+1;i<len;++i){
                gap=numbers[i]-numbers[i-1];
                if(0==gap)
                    return false;
                else if(1==gap)
                    continue;
                else{
                    numgap+=gap-1;
                }
            }
            
            if(numgap<=zeronum)
                return true;
            else return false;
        }
    };
    View Code

    8.丑数

    此题真的不太好理解,需要重复练习几遍方能理解贯通。

    class Solution {
    public:
        int GetUglyNumber_Solution(int index) {
             
            if(0==index) return 0;
            else if(1==index) return 1;
                 
            long long *uglynum=new long long[index];
            uglynum[0]=1;
            int nextuglyindex=1;
             
            long long min,*p1=uglynum,*p2=uglynum,*p3=uglynum;
            while(nextuglyindex<index){
                min=minnum(*p1*2,*p2*3,*p3*5);
                uglynum[nextuglyindex]=min;
                 
                while(*p1*2<=uglynum[nextuglyindex])
                    ++p1;
                while(*p2*3<=uglynum[nextuglyindex])
                    ++p2;
                while(*p3*5<=uglynum[nextuglyindex])
                    ++p3;
                 
                ++nextuglyindex;
            }
             
            int res= (int)uglynum[nextuglyindex-1];
            delete[] uglynum;
            return res;
        }
         
    private:
        long long minnum(const long long& num1,const long long& num2,const long long& num3){
            long long min=(num1<num2)?num1:num2;
            return (num3<min)?num3:min;
        }
    };
    View Code

    9.正则表达式匹配

    class Solution {
    public:
        bool match(char* str, char* pattern)
        {
            if(NULL==str||pattern==NULL)
                return false;
            else return matchstr(str,pattern);
        }
         
    private:
        bool matchstr(char* str,char* pattern){
             
            if(*str==''&&*pattern=='')
                return true;
             
            if(*str!=''&&*pattern=='')
                return false;
             
            if(*(pattern+1)=='*'){
                if(*pattern==*str||(*pattern=='.'&&*str!=''))
                    return    matchstr(str+1,pattern+2)
                           || matchstr(str+1,pattern)
                           || matchstr(str,pattern+2);
                else return matchstr(str,pattern+2);   
            }
             
            if(*str==*pattern||(*pattern=='.'&&*str!=''))
                return matchstr(str+1,pattern+1);
             
            return false;
        }
    };
    View Code

    return使用||返回几个可能结果,状态之间的变化,简直不能再赞了

    10.树的子结构

    /*
    struct TreeNode {
        int val;
        struct TreeNode *left;
        struct TreeNode *right;
        TreeNode(int x) :
                val(x), left(NULL), right(NULL) {
        }
    };*/
    class Solution {
    public:
        bool HasSubtree(TreeNode* root1, TreeNode* root2)
        {
            bool res=false;
            
            if(root1!=NULL&&root2!=NULL){
                if(root1->val==root2->val){
                    res=judgetree(root1,root2);
                }
                if(!res)
                    res=HasSubtree(root1->left,root2);
                if(!res)  
                    res=HasSubtree(root1->right,root2);
            }
            
            return res;
        }
        
    private:
        bool judgetree(TreeNode* root1, TreeNode* root2){
            if(root2==NULL)
                return true;
            
            if(root1==NULL)
                return false;
            
            if(root1->val!=root2->val)
                return false;
            
            return judgetree(root1->left,root2->left)&&
                judgetree(root1->right,root2->right);
        }
    };

    以后看看能不能改进,避免递归调用。

    11.栈的压入弹出

    class Solution {
    public:
        bool IsPopOrder(vector<int> push, vector<int> pop) {
    
            bool res = false;
            int len = push.size();
            if (len != pop.size() || len <= 0) return res;
    
            stack<int> sdata;
            vector<int>::iterator nextpush = push.begin(), nextpop = pop.begin();
    
            while (nextpop - pop.begin() < len)
            {
                while (sdata.empty() || sdata.top() != *nextpop)
                {
                    if (nextpush - push.begin() == len)
                        break;
    
                    sdata.push(*nextpush);
    
                    ++nextpush;
                }
    
                if (sdata.top() != *nextpop)
                    break;
    
                sdata.pop();
                nextpop++;
            }
    
            if (sdata.empty() && nextpop - pop.begin() == len)
                res = true;
    
            return res;
        }
    };

    12.二叉搜索树的后序遍历序列

    class Solution {
    public:
        bool VerifySquenceOfBST(vector<int> sdata) {
    
            int len = sdata.size();
            if (len <= 0) return false;
    
            return judgeBST(sdata, 0, len - 1);
        }
    
    private:
        bool judgeBST(vector<int>& sdata, int left, int right) {
    
            if (right - left < 0) return false;
    
            int i, j, root = sdata[right];
    
            for (i = left;i < right;++i) {
                if (sdata[i] > root)
                    break;
            }
    
            for (j = i;j < right;++j) {
                if (sdata[j] < root)
                    return false;
            }
    
            bool leftsign = true, rightsign = true;
            if (i > left)  //表示有左子树
                leftsign = judgeBST(sdata, left, i - 1);
    
            if (i < right) //表示有右子树
                rightsign = judgeBST(sdata, i, right - 1);
    
            return (leftsign&&rightsign);
        }
    };

    13.按之字形顺序打印二叉树

    class Solution {
    public:
        vector<vector<int>> Print(TreeNode* root) 
        {
            vector<vector<int>> res;
            if (NULL == root)
                return res;
    
            int i, left, right, nextlevel = 0, tobepush = 1;
            vector<int> vtmp;
            std::queue<TreeNode*> nodes;
            nodes.push(root);
    
            while (!nodes.empty())
            {
                TreeNode *nodetmp = nodes.front();
                vtmp.push_back(nodetmp->val);
    
                if (nodetmp->left) 
                {
                    ++nextlevel;
                    nodes.push(nodetmp->left);
                }
                    
                if (nodetmp->right)
                {
                    ++nextlevel;
                    nodes.push(nodetmp->right);
                }
                    
                nodes.pop();
                --tobepush;
                if (0 == tobepush)
                {
                    res.push_back(vtmp);
                    vtmp.clear();
                    tobepush = nextlevel;
                    nextlevel = 0;
                }
            }
    
            for (i = 1; i < res.size(); i += 2)
            {
                left = 0;right = res[i].size() - 1;
                while (left < right)
                {
                    swap(res[i][left], res[i][right]);
                    ++left;--right;
                }
            }
            return res;
        }
    
    private:
        void swap(int& a, int& b)
        {
            int tmp = a;a = b;b = tmp;
        }
    };

    14.判断二叉树是否对称

    class Solution {
    public:
        bool isSymmetrical(TreeNode* pRoot)
        {
            if (NULL == pRoot)
                return true;
            else return judgeSymmetrical(pRoot->left, pRoot->right);
        }
    
    private:
        bool judgeSymmetrical(TreeNode* left, TreeNode* right)
        {
            if (NULL == left&&NULL == right)
                return true;
    
            if (NULL == left || NULL == right)
                return false;
    
            if (left->val != right->val)
                return false; //注意此处不能判断相等返回true,因为下面还要进行判断
    
            return judgeSymmetrical(left->left, right->right)
                && judgeSymmetrical(left->right, right->left);
        }
    };

    很完美的思路,通过前序序列进行判断。

    15.二叉树的序列化和反序列化

    class Solution {
    public:
        char* Serialize(TreeNode *root) 
        {
            string str;
            Serialize(root, str);
    
            int i,len = str.length();
            char *res = new char[len + 1];
            for (i = 0; i < len; i++)
                res[i] = str[i];
            res[i] = '';
            return res;
        }
    
        TreeNode* Deserialize(char *str) 
        {
            if (NULL == str || *str == '')
                return NULL;
    
            int left = 0;
            
            string numstr(str);
            
            TreeNode* head = Deserialize(numstr, left);
            return head;
        }
    
    private:
    
        void Serialize(TreeNode *root, string& str)
        {
            if (NULL == root)
            {
                str += "#,"; return;
            }
            else
            {
                ostringstream ost;
                ost << root->val;
                str += ost.str() + ',';
            }
    
            Serialize(root->left, str);
            Serialize(root->right, str);
        }
    
        bool readstr(string& str,int& left, int& num)
        {
            if (str[left] == '#')
            {
                left += 2; //退后至下一个数字
                return false;
            }
            else
            {
                string tmp;
                while (str[left] != ',' && str[left] != '')
                {
                    tmp += str[left++];
                }
                ++left;
                num = atoi(tmp.c_str());
                return true;
            }
        }
    
        TreeNode* Deserialize(string& numstr,int& left)
        {
            int num;
            if (readstr(numstr, left, num))
            {
                TreeNode* root = new TreeNode(num);
                
                root->left = Deserialize(numstr, left);
                root->right = Deserialize(numstr, left);
                return root;
            }
            return NULL;
        }
    };

    16.二叉搜索树的第K个节点

    class Solution {
    public:
        TreeNode* KthNode(TreeNode* pRoot, unsigned int k)
        {
            if (NULL == pRoot || k == 0)
                return NULL;
    
            return KthTreeNode(pRoot, k);
        }
    
    private:
        TreeNode* KthTreeNode(TreeNode* root, unsigned int& k)
        {
            TreeNode* target = NULL;
    
            if (root->left != NULL)
                target = KthTreeNode(root->left, k);
    
            if (NULL == target)
            {
                if (k == 1)
                    target = root;
                --k;
            }
    
            if (NULL == target&&root->right != NULL)
                target = KthTreeNode(root->right, k);
    
            return target;
        }
    };

    根据中序遍历的方式实现寻找。

  • 相关阅读:
    前端模板Nunjucks简介
    git提交时支持文件名大小写的修改
    多行文本加省略号的处理方法
    前端性能优化实践方案总结
    使用gulp工具生成svgsprites
    koa简介
    JSX语法简介
    踩坑所引发出的appendChild方法的介绍
    React业务实践
    javascript--数组
  • 原文地址:https://www.cnblogs.com/jason1990/p/4739232.html
Copyright © 2020-2023  润新知