剑指offer刷题笔记(摘录主要重点)

目录

剑指 Offer 07. 重建二叉树

剑指 Offer 11. 旋转数组的最小数字

剑指 Offer 12. 矩阵中的路径

剑指 Offer 13. 机器人的运动范围

剑指 Offer 14- I. 剪绳子

剑指 Offer 16. 数值的整数次方

剑指 Offer 24. 反转链表

剑指 Offer 17. 打印从1到最大的n位数

剑指 Offer 26. 树的子结构

剑指 Offer 42. 连续子数组的最大和

剑指 Offer 29. 顺时针打印矩阵

剑指 Offer 31. 栈的压入、弹出序列

剑指 Offer 32 - III. 从上到下打印二叉树 III

剑指 Offer 34. 二叉树中和为某一值的路径

剑指 Offer 33. 二叉搜索树的后序遍历序列

字符串的排列组合

剑指 Offer 55 - I. 二叉树的深度

剑指 Offer 55 - II. 平衡二叉树

剑指 Offer 26. 树的子结构

剑指 Offer 68 - I. 二叉树搜索树的最近公共祖先

剑指 Offer 68 - II. 二叉树的最近公共祖先


 

剑指 Offer 07. 重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。 例如,给出:

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]

 

思路:前序遍历的第一位是根节点,把中序遍历分割成左右两部分

代码:

class Solution {

public:

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {

        if(preorder.size()==0||inorder.size()==0||preorder.size()!=inorder.size())

            return nullptr;

        return build(preorder,0,preorder.size()-1,inorder,0,inorder.size()-1); 

    }

   

    TreeNode *build(vector<int>& preorder,int pbegin,int pend,vector<int>& inorder,int inbegin,int inend){

       

        //if(pbegin==pend)//终止条件搞清楚,是下面的。

        if(pbegin>pend||inbegin>inend)

            return nullptr;

        TreeNode *root=new TreeNode(preorder[pbegin]);//每次都应该新建一个节点,而且要在终止条件之后。不然就多创建了结点。

        for(int j=inbegin;j<=inend;++j){

            if(inorder[j]==preorder[pbegin]){

                root->left=build(preorder,pbegin+1,pbegin+j-inbegin,inorder,inbegin,j-1);//注意这个pbegin+(j-inbegin),很关键

                root->right=build(preorder,pbegin+j-inbegin+1,pend,inorder,j+1,inend);

                break;

            }

        }

        return root;

    }

};

剑指 Offer 11. 旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组 [3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

1.可以一个一个比较O(N);

2.二分法: 关键是和右边比较,因为是升序。不能和左边比较

代码:

class Solution {

public:

    int minArray(vector<int>& numbers) {

        //1暴力法,一个一个比较,

        //2有序->二分法

        /*存在三种情况://关键是要和右边比,因为是升序,和左边比没意义

        1.mid>right

        即[3,4,5,1,2] 那么带查找区间在右侧,即left=mid+1;

        2.mid==right

        即[3,4,1,1,1] 那么需要缩小待查找区间,即right--;

        3.mid<right

        即[1,2,3,4,5] 那么待查找区间在左侧,即right=mid;*/

 

        if(numbers.empty())

            return -1;

        int len=numbers.size();

        int low=0,high=len-1,mid=0;

        while(low<high){

            mid=low+((high-low)>>1);

            if(numbers[mid]<numbers[high])

                high=mid; //不能high=mid-1,如2 1 2 如果mid-1那么1就会被跳过

            else if(numbers[mid]>numbers[high])

                low=mid+1;

            else high--;

        }

        return numbers[low];

    }

};

剑指 Offer 12. 矩阵中的路径

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一格开始,每一步可以在矩阵中向左、右、上、下移动一格。如果一条路径经过了矩阵的某一格,那么该路径不能再次进入该格子。例如,在下面的3×4的矩阵中包含一条字符串“bfce”的路径(路径中的字母用加粗标出)。

 

[["a","b","c","e"],

["s","f","c","s"],

["a","d","e","e"]]

 

但矩阵中不包含字符串“abfb”的路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入这个格子。

思路:递归回溯

代码:

class Solution {

string word;

public:    

    bool exist(vector<vector<char>>& board, string word) {

this->word = word;

if(word.empty()||board.empty()) return false;

 

for(int i=0;i<board.size();i++)

for(int j=0;j<board[0].size();j++)

if(walk(board,0,0,0)) return true;

 

return false;

    }

 

    bool walk(vector<vector<char>>& board, int x, int y, int pos){

if(pos==word.size()-1) return true;

if(board[x][y]!=word[pos]) return false;

 

char temp=board[x][y];

board[x][y]='/';

 

int dx[4]={1,-1,0,0};int dy={0,0,1,-1};

for(int i=0;i<4;i++){

if(x+dx[i]>board.size()||x+dx[i]<0||y+dy[i]>board[0].size()||y+dy[i]<0)

continue;

if(walk(board,x+dx[i],y+dy[i],pos+1)) return true;

}

board[x][y]=temp;

return false;

}

};

剑指 Offer 13. 机器人的运动范围

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

思路:深度优先搜索DFS

class Solution { //这就是深度优先搜索了。

public:

    int movingCount(int m, int n, int k) {

        if(m<1||n<1) return 0;

        if(k==0) return 1;

        vector<vector<bool>> visited(m,vector<bool>(n,false));

        int sum=0;

        move(visited,0,0,k,m,n,sum);

        return sum;

           

    }

    void move(vector<vector<bool>> &visited,int i,int j,int k,int m,int n,int &sum){

        if(!leagal(i,j,k))

            return ;

        int a[2]={1,0};int b[2]={0,1};

        if(!visited[i][j]/*&&leagal(i,j,k)*/){

            visited[i][j]=true;

            sum++;

            for(int ii=0;ii<2;++ii){

                int x=i+a[ii];int y=j+b[ii];

                if(x>=0&&x<m&&y>=0&&y<n)

                    move(visited,x,y,k,m,n,sum);

            }

        }

    }

    bool leagal(int i,int j,int &k){

        int sum=0;

        while(i>0){

            sum+=(i%10);

            i=i/10;

        }

        while(j>0){

            sum+=(j%10);

            j=j/10;

        }

        if(sum<=k)

            return true;

        else return false;

    }

};

剑指 Offer 14- I. 剪绳子

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

1.找规律 3越多数越大。

          

        int sum=1;

        if(n<=1) return 0;

        else if(n==2)

            return 1;

        else if(n==3)

            return 2;

        while(n>0){

            if(n<3||n==4)

                sum*=n;

            else

                sum*=3;

            n-=3;

        }

        return sum;

2.动态规划

int cuttingRope(int n) {

if(n<=1) return 0;

if(n>=2&&n<=3) return n-1;

return dfs(n);

}

 

int  dfs(int n){

if(n<=4) return n;//关键,这个指的是分割或者不分割时的最大值

int ans=0;

for(int i=1;i<=n/2;i++){

ans=max(ans,dfs(i)*dfs(n-i));//有重复计算,超时

}

return ans;

}

2.动态规划改进;

int cuttingRope(int n) {

if(n<=1) return 0;

if(n>=2&&n<=3) return n-1;

vector<int> res(n,0);

return dfs(n,res);

}



int  dfs(int n,vector<int>&res){

if(n<=4) return n;//关键,这个指的是分割或者不分割时的最大值

int ans=0;

for(int i=1;i<=n/2;i++){//只需要到n/2即可

if(res[i]==0) res[i]=dfs(i,res);//不存在的时候才计算

if(res[n-i]==0) res[n-i]=dfs(n-i,res);

ans=max(ans,res(i)*res(n-i));}

return ans;

}

剑指 Offer 16. 数值的整数次方

实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。

思路:快速幂:

我们这里使用快速幂进行求解。我们看一下 n 的二进制形式一定是若干个 1 和 0 构成,比如 9 = 1001 = 1*2^3 + 0*2^2 + 0*2^1 + 1*2^0

 

x^9=x^{2^0}*x^{2^1*0}*x^{2^2*0}*x^{2^3}

代码:

 

class Solution {

public:

    double myPow(double x, int n) {

        double res=1.0;

        long t=abs(n);//int范围[−2147483648,2147483647] ,因此当n=−2147483648 时执行

        //n =-n=会因越界而赋值出错。解决方法是先将 n 存入 long 变量 t ,后面用 t 操作即可

        if(x==0&&t==0)

            return -1;

        else if(x==0)

            return 0;

        else if(t==0)

            return 1;

       

        else {

            while(t){

                if(t&1)

                    res*=x;

                x*=x;

                t=t>>1;

            }

        }

        return n>0?res:1/res;

    }

};

剑指 Offer 24. 反转链表

定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

1.经典反转:

ListNode* reverseList(ListNode* head) {

if(!head||!head->next) return head;

ListNode* pre=nullptr,*cur=head,*temp=nullptr;

while(cur){

temp=cur->next;

cur->next=pre;

pre=cur;

cur=temp;

}

return pre;

}

 

2.递归

ListNode* reverseList(ListNode* head) {

if(!head||!head->next) return head;//终止条件是head->next==nullptr,head=nullptr是防止非法输入。

ListNode* =reverseList(head->next);//终止时head->next->next==nullptr. t=head->next即尾结点。

head->next->next=head;

head->next=nullptr;//这两步反转

return t;

}

 

剑指 Offer 17. 打印从1到最大的n位数

输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

思路:主要是要考虑大数:模拟大数的加法

class Solution {

public:

    vector<int> res;

    vector<int> printNumbers(int n) {

        //1.不是很大的数的时候可以这样

        /*vector<int> res;

        if(n<=0) return res;

        int i=1;

        long t=pow(10,n);

        while(i<t){

            res.push_back(i);

            i++;

        }

        return res;*/

        //2.大数还是要用字符串才行

        if(n<=0) return res;

        string s(n,'0');

        while(!Increment(s))

            save(s);

        return res;

    }

    bool Increment(string &s){

        bool isOverFlow=false;//检查是否越界

        int nTakeOver=0;//存储进位

        int len=s.length();

        for(int i=len-1;i>=0;--i){//模拟十进制加法

            int nSum=s[i]+nTakeOver-'0';

            if(i==len-1)//如果是个位就直接加1

                nSum++;

            if(nSum>=10){//加1后产生了进位

                if(i==0)//如果最高位产生了进位,那么就超过了n位数

                    isOverFlow=true;

                else{

                    nTakeOver=1;

                    s[i]=nSum-10+'0';

                }

            }

            else{//没有进位

                s[i]=nSum+'0';

                break;

            }

        }

        return isOverFlow;

    }

    void save(string s){//保存的时候 会出现00001243,前面是0的情况,要把前面的0去除。

        string tempstr="";

        bool flag=false;

        for(int i=0;i<=s.size()-1;i++){

            if(!flag&&s[i]!='0'){

                flag=true;

            }

            if(flag)

                tempstr+=s[i];

        }

        int num=0;

        for(int i=0;i<tempstr.size();++i){

            num*=10;

            num+=(tempstr[i]-'0');

        }

        //int num=stoi(tempstr);

        res.push_back(num);

    }

 

//我自己的想法:

bool Increment(string &s){

        bool flag=false;

        bool wei=false;

        for(int i=s.size()-1;i>=0;i--){

            if(i==s.size()-1){      //个位

                if(s[i]-'0'+1==10){//产生进位

                    wei=true;

                    s[i]='0';

                }

                else {            //不产生进位加一后直接break;

                    s[i]+=1;

                    break;

                }

            }

            else{                //不是个位,那必然是进位了

                if(s[i]-'0'+1==10){

                    wei=true;

                    s[i]='0';

                }

                else {           //不进位,加一之后直接break;

                    s[i]+=1;

                    wei=false;

                    break;

                }

            }

            if(i==0&&wei) {flag=true;break;}//判断是否越界

        }

        return flag;

    }

    void save(string s){

        int begin=0;

        for(int i=0;i<s.size();i++){

            if(s[i]=='0')

                continue;

            else break;

        }

        int sum=0;

        for(int j=begin;j<s.size();j++){

            sum*=10;

            sum+=s[j]-'0';

        }

        res.push_back(sum);

    }

 

};

剑指 Offer 26. 树的子结构

输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)

B是A的子结构, 即 A中有出现和B相同的结构和节点值。

class Solution {//有个大坑,题目说的是子结构,而不是子树。

public:

bool isSubStructure(TreeNode* A, TreeNode* B) {

if(A==nullptr&&B==nullptr) return true;

else if(A==nullptr||B=nullptr) return fasle;

else{

if(A->val==B->val)

return DoesSubTree(A,B);

else return isSubStructure(A->left,B)||isSubStructure(A->right,B);

}

}

bool DoesSubTree(TreeNode* root1, TreeNode* root2){

if(root2==nullptr) return true;

if(root1==nullptr) return false;

if(root1->val!=root2->val) return false;

return DoesSubTree(root1->left,root2->left)&&DoesSubTree(root1->right,root2->right);

}

};

剑指 Offer 42. 连续子数组的最大和

输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。

要求时间复杂度为O(n)。

//1.动态规划

class Solution {

public:

int maxSubArray(vector<int>& nums) {

int n=nums.size();

if(n==0) return 0;

int ans=INT_MIN;

vector<int> dp(n+1,0);//表示前i项中连续子数组的最大和

dp[0]=nums[0];

for(int i=1;i<=n;i++){

dp[i]=max(dp[i-1]+nums[i],nums[i]);

ans=max(ans,dp[i]);;

}

return ans;

}

}

2.贪心算法

int sum=0,Max=nums[0];

for(int i=0;i<nums.size();i++){

sum=max(sum+nums[i],nums[i]);

Max=max(Max,sum);

}

return Max;

剑指 Offer 29. 顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。

//1暴力,

//2.定义两个方向d[x]d[y] 和是否走过vis[][] 遇到边界或者走过就顺时针转向

class Solution {

public:

    vector<int> spiralOrder(vector<vector<int>>& matrix) {

        vector<int> res;

        if(matrix.empty()) return res;

        int m=matrix.size(),n=matrix[0].size();

        int dx[]={0,1,0,-1};int dy[]={1,0,-1,0};int d=0;

        int x=0,y=0;

        vector<vector<bool>> vis(m,vector<bool>(n,false));

        for(int k=0;k<m*n;k++){

            res.push_back(matrix[x][y]);

            vis[x][y]=true;

            x+=dx[d],y+=dy[d];

            if(x<0||x>=m||y<0||y>=n||vis[x][y]){

                x-=dx[d],y-=dy[d];//越界了就回退

                d=(d+1)%4;

                x+=dx[d],y+=dy[d];//然后换向

            }

        }

        return res;

    }

};

剑指 Offer 31. 栈的压入、弹出序列

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

思路:模拟整个压入弹出的过程 看最终是否符合

代码:

class Solution {

public:

    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {

         //模拟pushed数组push过程和poped数组pop过程

if(pushed.size()!=poped.size()) return false;

           stack<int> stk;

int k=0;

int n=pushed.size();

for(int i=0;i<n;i++){

stk.push(pushed[i]);

while(!stk.empty()&&k<n&&stk.top()==poped[k]){//用while,需要连续弹出

stk.pop();

k++;

}

}

if(k==n||stk.empty()) return true;

else return false;

    }

};

剑指 Offer 32 - III. 从上到下打印二叉树 III

请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。

 

剑指 Offer 34. 二叉树中和为某一值的路径

输入一棵二叉树和一个整数,打印出二叉树中节点值的和为输入整数的所有路径。从树的根节点开始往下一直到叶节点所经过的节点形成一条路径。

class Solution {

private:

vector<int<int>> res;

vector<int> temp;

public:

vector<vector<int>> pathSum(TreeNode* root, int sum) {       

if(root==nullptr) return res;

 

dfs(root,sum);

        

 return res;

}

void dfs(TreeNode* root,int sum){

temp.push_back(root->val);

if(!root->left&&!root->right){//到叶子了

if(sum==root->val)

res.push_back(temp);

}

      

 if(root->left) dfs(root->left,sum-root->val);

      

 if(root->right) dfs(root->right,sum-root->val);

      

 temp.pop_back();//回溯

}

};

 

剑指 Offer 33. 二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回 true,否则返回 false。假设输入的数组的任意两个数字都互不相同。

字符串的排列组合

有重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合。

1.让每个字符都有在第一的机会,然后递归,把第一位固定,让剩余的子母都有在第二的机会……

vector<string> res;

vector<string> permutation(string S) {

        if(S.empty()) return res;

        dfs(S,0);

        return res;

    }

    void dfs(string &str,int begin){

        if(begin==str.size()) {

            res.push_back(str);

            return;

        }

        for(int i=begin;i<str.size();i++){

            if(ilegal(str,begin,i)) continue;//考虑重复的

            swap(str[i],str[begin]);

            dfs(str,begin+1);

            swap(str[i],str[begin]);//回溯

        }

    }

    bool ilegal(string &s,int a,int b){

        for(int i=a;i<b;i++){

            if(s[i]==s[b]) return true;

        }

        return false;

    }

 

剑指 Offer 55 - I. 二叉树的深度

输入一棵二叉树的根节点,求该树的深度。从根节点到叶节点依次经过的节点(含根、叶节点)形成树的一条路径,最长路径的长度为树的深度。

//1.递归求  简洁,复杂度o(N) N为节点数。

int maxDepth(TreeNode* root) {

if(!root) return 0;

return max(maxDepth(root->left),maxDepth(root->right))+1;

}

2.按层打印,看一共多少层//o(2N)

if(root==nullptr) return 0;

        int cnt=0;

        queue<TreeNode*> q;

        q.push(root);

        while(!q.empty()){

            cnt++;

            int len=q.size();

            while(len--){

                TreeNode* temp=q.front();

                if(temp->left) q.push(temp->left) ;

                if(temp->right) q.push(temp->right) ;

                q.pop();

            }

        }

        return cnt;

3.用路径的方法//dfs||回溯

int sum=0,m=0;

int maxDepth(TreeNode* root) {

if(!root) return 0;

dfs(root);

return m;

}

void dfs(TreeNode* root){

        sum++;

        if(!root->left&&!root->right) m=max(m,sum);

        if(root->left) {

            dfs(root->left);

            sum--;//回溯

        }

        if(root->right) {

            dfs(root->right);

            sum--;//回溯

        }

    }

 

剑指 Offer 55 - II. 平衡二叉树

输入一棵二叉树的根节点,判断该树是不是平衡二叉树。如果某二叉树中任意节点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。

思路:根据左右子树的深度 但是求深度的时候只能用递归的方法求,不能用回溯,因为主程序里面有isBalanced(root->left) && isBalanced(root->right),而

这个递归里面没法对sum进行回溯。

bool isBalanced(TreeNode* root) {

if (root == nullptr) return true;

 return abs(getDepth(root->left) - getDepth(root->right)) <= 1 &&isBalanced(root->left) && isBalanced(root->right);

}

int getDepth(TreeNode* node)

    {

        if (node == nullptr) return 0;

        return 1+max(getDepth(node->left), getDepth(node->right));

    }

剑指 Offer 26. 树的子结构

输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)

B是A的子结构, 即 A中有出现和B相同的结构和节点值。

思路:递归判断A的左右子树是否等于B

class Solution {//有个大坑,题目说的是子结构,而不是子树。

public:

    bool isSubStructure(TreeNode* A, TreeNode* B) {

        if(A==nullptr&&B==nullptr) return true;

        if(A==nullptr||B==nullptr) return false;//B肯定是不能为空的

        if(A->val==B->val){

            if(DoesSubTree(A,B))

                return true;

        }

        return isSubStructure(A->left,B)||isSubStructure(A->right,B);

    }

    bool DoesSubTree(TreeNode* root1, TreeNode* root2){

        if(root2==nullptr) return true;//1为空,2为空//root2先跑完了,就是true,子结构不是子树

        if(root1==nullptr) return false;//1或2只一个为空

        if(root1->val!=root2->val) return false;

        return DoesSubTree(root1->left,root2->left)&&DoesSubTree(root1->right,root2->right);

    }

};

剑指 Offer 68 - I. 二叉树搜索树的最近公共祖先

可以利用搜索树的性质:左边永远小于根,右边永远大于根

代码:

LastAncester(TreeNode* root,TreeNode *p,TreeNode *q){

if(!root||p==root||q==root) return root;

while(root){

if(q->val<root->val&&q->val<root->val)

root=root->left;

else if(q->val>root->val&&q->val>root->val)

root=root->right;

else  return root;

}

return root;

}

剑指 Offer 68 - II. 二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {

        if(!root||root==p||root==q) return root;

        TreeNode* left=lowestCommonAncestor(root->left,p,q);

        TreeNode* right=lowestCommonAncestor(root->right,p,q);

        if(!left) return right;//左边找不到,那么就在右边

        else if(!right) return left;//同理

        else return root;//左右都有,那么当前就是祖先

    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值