C++ : 剑指offer(4-20)

C++ : 剑指offer(4-20)


4、二维数组的查找

题目描述
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        
        int rows = array.size();   
        int columns = array[0].size();
        
        int row = 0;
        int column = columns - 1;
        bool found = false;
            
        if(rows>0&&columns>0){
            while(row<rows&&column>=0){
                if(target<array[row][column]){
                    --column;
                }
                else if(target==array[row][column]){
                    found = true;
                    break;
                }
                else{
                    ++row;
                }
            }
        }
        return found;
    }
};

思路:从数组的右上角或者左下角进行逐行或逐列删除,直至搜索完毕。

  • 另外需要掌握利用vector创建二维数组的各项操作;

5、替换空格

题目描述
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

class Solution {
public:  // 该题需要注意数组是否原本就有足够长度
	void replaceSpace(char *str,int length) {  
                        // length为字符数组的总长度(包含\0)
        
        if(str&&length>0){  // 字符数组不为空,需要处理
            int oldlength = 0;
            int num = 0;
            int i = 0;
            while(str[i]!='\0'){
                if(str[i]==' ') ++num;   // 统计空格数目
                ++oldlength;  // 数组本身长度
                ++i; 
            }
            if(num>0){    // 存在空格需要替换
                int newlength = oldlength+num*2;
                if(newlength<=length){ // 留有足够空间
                    int indexOfNew = newlength;
                    int indexOfOld = oldlength;
                    while(indexOfOld>=0&&indexOfNew>indexOfOld){
                        if(str[indexOfOld]==' '){
                            str[indexOfNew--]='0';
                            str[indexOfNew--]='2';
                            str[indexOfNew--]='%';
                        }
                        else{
                            str[indexOfNew--]=str[indexOfOld];
                        }
                        --indexOfOld;
                    }
                }
            }
        }
	}
};

思路:首先明确str是一个类似char str[20]=“hello world”;的静态字符数组,传参到函数为char* str类型,但可以使用下标操作;其次,明确str要发生长度变化,故必须实现留有足够的长度空间;然后,为了节省计算量,从后往前逐步移动字符数组,将空格进行代替;


6、倒序打印链表

题目描述
输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> vec;
        stack<int> stk;
        if(head==nullptr||!(head->val)){return vec;}
        
        ListNode * pNode = head;
        
        stk.push(pNode->val);
        while(pNode->next!=nullptr){
            stk.push(pNode->next->val);
            pNode = pNode->next;
        }
        while(!stk.empty()){
            vec.push_back(stk.top());
            stk.pop();
        }
        return vec;
    }
};

思路:利用栈stack解决问题;


7、重建二叉树

题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        
        int size1 = pre.size(), size2 = vin.size();
        if(size1==0&&size2==0) return nullptr;
        if(size1!=size2||size1<0||size2<0) return nullptr;
        
        int RootValue = pre[0];
        TreeNode* root = new TreeNode(RootValue);
        
        if(pre.size()==vin.size()&&pre.size()==1){
            if(pre[0]==vin[0]){
                return root;
            }
            else{
                return nullptr;
            }
        }
        
        int index = 0;
        while(vin.size()>1&&vin[index]!=RootValue){
            ++index;
        }
        if(vin[index]!=RootValue){
            return nullptr;
        }
        
        if(index>0){
            vector<int> pre_left(pre.begin()+1,pre.begin()+index+1);
            vector<int> vin_left(vin.begin(),vin.begin()+index);
            root->left = reConstructBinaryTree(pre_left,vin_left);
        }
        if((size2-index-1)>0){
            vector<int> pre_right(pre.begin()+index+1,pre.end());
            vector<int> vin_right(vin.begin()+index+1,vin.end());
            root->right = reConstructBinaryTree(pre_right,vin_right);
        }
        return root;
    }
};

思路:较为复杂,首先需要十分熟悉二叉树的三种遍历方式:前序遍历、中序遍历和后续遍历以及其各自的性质特点,从根节点入手,进而可以区分出左右子树的节点序列(前序和中序),演变到左右两个子树的重构问题,形成递归形式;


8、二叉树的下一个节点

题目描述
给定一个二叉树和其中一个节点,找出其在中序遍历序列中的下一个节点并返回其指针;其中二叉树中的节点有三个指针,分别指向左右子节点和自己的父节点;

BinaryTreeNode* findnext_inorder(BinaryTreeNode* root,BinaryTreeNode* node){
    if(root==nullptr) return nullptr;
    BinaryTreeNode* Temp;
    if(node->rightchild!=nullptr){   // 有右子节点
        Temp = node->rightchild;
        while(Temp->leftchild!=nullptr){
            Temp = Temp->leftchild;
        }return Temp;
    }
    else{         // 无右子节点
        if(node==root) return nullptr;
        if(node->father->leftchild==node){  // 父节点的左子节点
            return node->father;
        }
        else{    // 是父节点的右子节点
            Temp = node->father;
            while(true){
                if(Temp->father==nullptr) return nullptr; // 序列最后一个节点
                if(Temp->father->leftchild==Temp) return Temp->father;  // 父节点的右节点
                Temp = Temp->father;
            }
        }
    }
}

思路:问题比较复杂,需要先分析中序遍历序列的特性,建议首先在纸上列出所有情况并分别分析:
1、当二叉树为空,返回nullptr;
2、当该节点有右子节点时: 问题转化为求该右子节点树的最左子节点;
3、当该节点没有右子节点时:
(1)、该节点本身为根节点时,直接返回nullptr;
(2)、该节点是父节点的左子节点,返回其父节点;
(3)、该节点是父节点的右子节点,返回一个是其本身父节点的左子节点的父节点;


9、用两个栈实现队列

题目描述
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

class Solution
{
public:
    void push(int node) {
        if(!stack2.empty()){
            while(!stack2.empty()){
                stack1.push(stack2.top());
                stack2.pop();
            }
        }
        stack1.push(node);
    }
    int pop(){
        int temp;
        if(!stack1.empty()){
            while(!stack1.empty()){
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
        temp = stack2.top();
        stack2.pop();
        return temp;
    }

private:
    stack<int> stack1;
    stack<int> stack2;
};

思路:两个栈互相倒可以调换顺序,用来push或者pop;其中stack1用来push,stack2用来pop;


10、斐波那契数列(跳台阶)

题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

class Solution {
public:
    int jumpFloor(int number) {
        if(number==0) return 0;
        if(number==1) return 1;
        if(number==2) return 2;
        int f = 0;
        int n1 = 1, n2 = 2;
        for(int i=2;i<number;++i){
            f = n1 + n2;
            if(n1<=n2){
                n1 = f;
            }
            else{
                n2 = f;
            }
        }
        return f;
    }
};

思路:跳台阶问题本质上是一个斐波那契数列,一定要转化为这种问题才好解决;
该问题实质上是一个动态规划问题,将大问题分解为多个小问题的组合;
(尽量不要用递归,速度慢)

思路延伸: 变态跳台阶(可以一次跳1到n阶台阶,共多少种跳法)

f(n)=f(n-1)+f(n-2)+…+f(1)+f(0);
f(n-1)=f(n-2)+f(n-3)+…+f(1)+f(0);
相减得到: f(n)=2f(n-1);

可以利用递归、循环求解和规律公式:return pow(2,n-1);


11、旋转数组的最小数字

题目描述
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

class Solution {
public:
    static int minNumberInRotateArray(vector<int> rotateArray) {
        int len = rotateArray.size();
        if(len==0) return 0;
        int l = 0;
        int r = len - 1;
        int result = l;
        while(rotateArray[l]>=rotateArray[r]){    // 如果是个旋转序列
            if((r-l)==1) return rotateArray[r];   // 循环截止
            int mid = (l + r) / 2;
            if(rotateArray[mid]==rotateArray[r]&&rotateArray[l]==rotateArray[r]){
                return findmin(rotateArray,l,r);
            }
            if(rotateArray[mid]>=rotateArray[l]){
                l = mid;             // 最小值在右侧序列中
            }
            else if(rotateArray[mid]<=rotateArray[r]){
                r = mid;             // 最小值在mid或mid左侧
            }
            result = rotateArray[r];
        }
        return result;
    }
private:
    static int findmin(vector<int>& rotateArray,int l,int r){
        int min = rotateArray[0];
        for(int i=l;i<=r;++i){
            if(min>rotateArray[i]) min = rotateArray[i];
        }
        return min;
    }
};

思路:一个可以应用二分查找的题,需熟练掌握二分写法;


12、矩阵中的路径

题目描述
请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则该路径不能再进入该格子。例如矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

class Solution {
public:
    bool hasPath(char* matrix, int rows, int cols, char* str)
    {
        if(matrix==nullptr||rows<=0||cols<=0||str==nullptr) return false;
        int pathLength = 0;
        int ifsearched[rows*cols]; 
        memset(ifsearched,0,rows*cols*4);
        for(int row=0;row<rows;++row){
            for(int col=0;col<cols;++col){
                if(matrix[row*cols+col]==str[0]){
                    if(hasNext(matrix,rows,cols,str,row,col,ifsearched,pathLength))
                        return true;
                }
            }
        }
        return false;
    }
    bool hasNext(char* matrix,int rows,int cols,char* str,int row,int col,int* ifsearched,int& pathLength){
        if(str[pathLength]=='\0') return true;
        bool hasnext = false;
        if(row>=0 && col>=0 && row<rows && col<cols && matrix[row*cols+col]==str[pathLength] && ifsearched[row*cols+col]==0){
            ++pathLength;
            ifsearched[row*cols+col] = 1;
            hasnext = hasNext(matrix,rows,cols,str,row+1,col,ifsearched,pathLength)
                ||hasNext(matrix,rows,cols,str,row-1,col,ifsearched,pathLength)
                ||hasNext(matrix,rows,cols,str,row,col+1,ifsearched,pathLength)
                ||hasNext(matrix,rows,cols,str,row,col-1,ifsearched,pathLength);
            if(!hasnext){
                --pathLength;
                ifsearched[row*cols+col] = 0;
            }
        }
        return hasnext;
    }
};

思路:回溯法,逐个查找,难点在于程序思路和设计,以及撰写,细节很多要注意。


13、机器人的运动范围

题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

class Solution {
public:
    int movingCount(int threshold, int rows, int cols)
    {
        if(rows<1&&cols<1&&threshold<0){ return 0; }
        int searched[rows*cols]; memset(searched,0,rows*cols*4);
        int row = 0, col = 0;
        return hasnext(threshold,rows,cols,row,col,searched);
    }
    int hasnext(const int& threshold,const int& rows,const int& cols,int row,int col,int* searched){
        int count = 0;
        if(row<rows&&row>=0&&col<cols&&col>=0&&searched[row*cols+col]!=1){
            if(check(threshold,row,col)){
                searched[row*cols+col] = 1;
                count = 1 + hasnext(threshold,rows,cols,row+1,col,searched)
                    + hasnext(threshold,rows,cols,row-1,col,searched)
                    + hasnext(threshold,rows,cols,row,col+1,searched)
                    + hasnext(threshold,rows,cols,row,col-1,searched);
            }
        }
        return count;
    }
    bool check(const int& threshold,int row,int col){
        int sum = 0;
        bool b = false;
        while(row>0){
            sum = sum + row % 10;
            row = row / 10;
        }
        while(col>0){
            sum = sum + col % 10;
            col = col / 10;
        }
        if(sum<=threshold) b = true;
        return b;
    }
};

思路:也是一道回溯法求路径问题,主要注意细节和步骤;


14、剪绳子

题目描述
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。(2 <= n <= 60)

class Solution {
public:
    int cutRope(int number) {
        if(number==2) return 1;
        if(number==3) return 2;
        int list[number];
        list[1] = 1;
        list[2] = 2;
        list[3] = 3;
        list[4] = 4;
        for(int i=5;i<=number;++i){
            int max = 0;
            for(int j=1;j<i;++j){
                if(list[j]*list[i-j]>max) max = list[j]*list[i-j];
            }
            list[i] = max;
        }
        return list[number];
    }
};

思路:典型的动态规划问题(求最优解,可分解为子问题,子问题之间有计算重合部分),自上而下分析问题,自下而上解决问题(求绳子长度等于每一个数的最优解)。


15、二进制中1的个数

题目描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

class Solution {
public:
     int  NumberOf1(int n) {
         int num = 0;
         for(int i=0;i<sizeof(n)*8;++i){
             if(n&1){
                 ++num;
             }
             n = n >> 1;
         }
         return num;
     }
};

思路:灵活运用位运算如n&1。


16、数值的整数次方

题目描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。保证base和exponent不同时为0

bool Power_InvalidInput = false;  // 全局变量
bool double_equal(double& base,double number){
    const double epsilon = 1e-6;
    if(base-number<number*epsilon){
        return true;
    }
    else{
        return false;
    }
}
class Solution {
public:
    double Power(double base, int exponent) {
        // 当底数为0而指数为负时,输入不合法
        // double类型的相等判断不能通过==号
        if(double_equal(base,0.0)&&exponent<0){ 
            Power_InvalidInput = true;
            return 0.0;
        }
        double result = 1.0;
        // 必须考虑到指数有正有负的情况
        int abs_exponent;
        if(exponent<0){
            abs_exponent = - exponent;
        }else{
            abs_exponent = exponent;
        }
        for(int i=0;i<abs_exponent;++i){
            result = result * base;
        }
        if(exponent<0){
            result = 1.0 / result;
        }
        return result;
    }
};

思路:考察思维全面性,需要考虑到底数为0,指数为负的情况,同时注意非法输入的处理方式、double类型的比较方法等;

附:(求指数幂的O(logn)复杂度递归方法,e>0)

double getPow(double base,int e){
    if(e==0) return 1.0;
    if(e==1) return base;
    double result = 1.0;
    result = getPow(base,e>>1);
    result = result * result;
    if(e&1==1) result = result * base;
    return result;
}

17、打印从1到最大的n位数

题目描述
输入数字n,按顺序打印从1到最大的n位十进制整数。

void Print1ToMaxOfDigitsRecursively(char* number,int length,int index){
    if(index==length-1){      // 递归终止条件
        print_str(number);
        return;
    }

    for(int i=0;i<10;++i){           // 每一位不断循环增加
        number[index+1] = i + '0';
        Print1ToMaxOfDigitsRecursively(number,length,index+1);  // 再下一位
    }
}
void Print1ToMaxOfDigits(int n){
    if(n<=0) return;   // 非法输入处理
    char number[n+1];
    number[n] = '\0';
    for(int i=0;i<10;++i){       // 最高位的循环(即321中的3),循环频率最慢
        number[0] = i + '0';     // 最高位的不断增加
        Print1ToMaxOfDigitsRecursively(number,n,0);  // 进入次高位不断增加的循环(同时负责递归结束时打印工作)
    }
}

思路:首先必须考虑全面,该数字并没有限制在int的范围内,可能会非常大,故需要利用字符串来代替数字进行打印,涉及到全排列或者顺序排列问题,用递归是不错的方法;


18、删除链表中的节点(1)(2)

题目描述
(1)、在O(1)时间内删除指定的链表节点;

// 链表结构
struct ListNode{   
    int val;
    ListNode* p_Next;
    ListNode(int value,ListNode* next=nullptr):val(value),p_Next(next){}
};
// 删除链表节点操作
void DeleteNode(ListNode** pHead,ListNode* pDelete) {
    if (pHead == nullptr || *pHead == nullptr || pDelete == nullptr) return;  // 为空
    if (pDelete == *pHead && pDelete->p_Next == nullptr) {    // 为头且无下节点
        delete *pHead;
        *pHead = nullptr;
        pDelete = nullptr;
        return;
    }
    if(pDelete != *pHead && pDelete->p_Next == nullptr) {      // 不为头且为尾,循环法
        ListNode* pNode = *pHead;
        while(pNode->p_Next!=pDelete){
            pNode = pNode->p_Next;
        }
        pNode->p_Next = nullptr;
        delete pDelete;
        pDelete = nullptr;
        return;
    }
    // 其他情况(复制下一节点到当前节点、删除下一节点)
    ListNode* pDeleteNext = pDelete->p_Next;
    pDelete->val = pDeleteNext->val;
    pDelete->p_Next = pDeleteNext->p_Next;
    delete pDeleteNext;
    pDeleteNext = nullptr;
}

思路:思路特殊,需要转变思路,将要删除节点的下一节点复制给当前节点,删除下一节点即可;但需要注意各种特殊情况,比如删除头节点、只有头节点、链表长度不为1且删除尾节点时等等,都需考虑;另外注意尽量将链表头节点参数设定为指针的指针,防止在链表为空时添加、链表长度为1时删除后,头节点指针发生改变的情况;


题目描述
(2)、在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

// 链表结构
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};

class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead)
    {       // 因为传入了指针pHead,参数也是指针,故函数内的pHead是一个独立的个体,
            // 单独改变函数内的pHead,将其置为链表头,并返回pHead;
        if(pHead==nullptr||pHead->next==nullptr) return pHead;
        
        ListNode* left = pHead;
        ListNode* right = pHead->next;
        ListNode* toBeDel = nullptr;
        
        if(left->val==right->val){    // 若头节点也是重复节点
            delete left; left = nullptr;
            while(right->next!=nullptr&&right->next->val==right->val){
                toBeDel = right;
                right = right->next;
                delete toBeDel; toBeDel = nullptr;
            }
            pHead = right->next;
            delete right; right = nullptr;
            return deleteDuplication(pHead);
        }
        // 总循环
        while(right!=nullptr&&left->val!=right->val){
            if(right->next==nullptr) break;  // 循环结束
            else if(right->next->val==right->val){  // 从right开始是重复节点
                while(right->next!=nullptr&&right->next->val==right->val){
                    toBeDel = right;
                    right = right->next;
                    delete toBeDel; toBeDel = nullptr;
                }
                toBeDel = right;
                right = right->next;
                delete toBeDel; toBeDel = nullptr;
                left->next = right;   // 连接链表
            }
            else{  // 当前无重复节点,往后推进
                left = right;
                right = right->next;
            }
        }
        // 所有处理结束,返回头节点
        return pHead;
    }
};

思路:链表节点删除看似简单,实则非常复杂,需要考虑各种情况,还有传参指针的问题,注意在删除链表程序中最好都建立一个节点指针toBeDel专门删除节点;


19、正则表达式匹配

题目描述
请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配

class Solution {
public:
    bool match(char* str, char* pattern)
    {
        if(str==nullptr||pattern==nullptr) 
            return false;    // 当str或patten为空时;
        return matchCore(str,pattern);  // 否则直接转入子函数判断
    }
    bool matchCore(char* str,char* pattern){
        if(*str=='\0'&&*pattern=='\0')
            return true;  // 当两者都走到头时,匹配结束,返回true
        if(*str!='\0'&&*pattern=='\0')
            return false;  // 当字符串未走完,但模板已走完时,递归路线的这种匹配方式出错
                     // 当字符串走完,但模板没走完时,有可能后面有c*模式,放在下一个if中讨论
        if(*(pattern+1)=='*'){  // 当模板出现c*形式时
            if(*str==*pattern||(*pattern=='.'&&*str!='\0')){
                // 当(字符相等)或者(模板是.*形式且数组没有结束)时
                // 在该情况下,以下路线只要有一条行得通,就会返回true
                return matchCore(str+1,pattern) // 匹配数组一个当前字符的匹配路线(还有其他匹配字符在后面)
                    || matchCore(str+1,pattern+2)  // 匹配上最后一个字符,c*模式结束
                    || matchCore(str,pattern+2); // 没有匹配,直接跳过c*模式
            }
            else{
                return matchCore(str,pattern+2);  // 有c*模式但字符不相等,直接跳过
            }
        }
        if(*str==*pattern||(*pattern=='.'&&*str!='\0')){
            // 如当前(两者头字符相等)或(遇到.模式)时
            return matchCore(str+1,pattern+1);
        }
        return false;   // 最后不能忘了return false;
    }
};

思路:字符串匹配问题,该题目涉及到可以是若干个字符匹配一个字符的问题,就要想办法把问题转化为递归求解路径问题;匹配了当前部分,剩下部分的匹配交给递归。把每一种匹配方式通过递归和或运算的方式结合,思想类似于求解矩阵路径;另外灵活使用字符串指针的解引用方式,该题目不需要用到下标运算;


20、表示数值的字符串

题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。

class Solution {
public:
    bool isNumeric(char* string)
    {
        if(string==nullptr) return false;
        bool isnum = scanInterger(&string); // 先判断+-整数部分
        if(*string=='.'){  // 如果整数部分有小数点
            ++string;
            // 小数点前有整数或小数点后有整数都可,所以用或,这里注意||的前后顺序
            isnum = scanUnsignedInterger(&string) || isnum;
        }
        if(*string=='e'||*string=='E'){ // 如果有e或E指数部分
            ++string;
            // 指数部分的判断,要求eE后面必须有个带符号的整数部分
            isnum = isnum && scanInterger(&string); 
        }
        return isnum && *string=='\0'; // 判断完后string需要到达末尾对齐,才算完成匹配
    }
    bool scanUnsignedInterger(char** string){  // 对无符号整数进行遍历
        // 这里传入的参数是字符串指针的指针,为了使string在函数外发生改变
        const char* before = *string;
        while(**string!='\0'&&**string>='0'&&**string<='9'){
            ++(*string);
        }
        return *string>before;  // 如果存在无符号整数,则为true
    } 
    bool scanInterger(char** string){  // 对有符号整数的+-号进行判断
        if(**string=='+'||**string=='-'){
            ++(*string);
        }
        return scanUnsignedInterger(string);  // 调用无符号整数遍历
    }
};

思路:一道非常复杂的题,如果用常规循环按条件求解的方式会非常复杂,上述的思路较为简便,即移动string指针,让前面的匹配与后面的匹配紧密结合,分解出了符号±和eE以及小数点,按组合顺序依次判断,化繁为简;两个问题:string指针传参中要求发生改变的问题,以及与或运算符的结合顺序问题;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值