CC150小结数据结构

数组与字符串

二叉堆可以用数组来表示

如大顶堆,构建的过程为从下到上。每次出现子节点大于父节点,旋转,然后对当前节点的子树进行递归处理,打印出排序的堆的时间复杂度为,nlog(n).

1.1确定一个字符串的所有字符是否全都不同。

思路:采用boolean数组进行缓存,ASCII与Unicode,考虑进去长度的因素256个,大于肯定会出现重复,时间复杂度O(n)。

1.2用c或者c++实现void reverse(char* str),反转一个null结尾的字符串。

思路:不使用额外的空间就可以实现,这个是双指针。
这里给出程序

void reverse(char *str){
    char *end = str;
    char temp;
    if (str){
        while(*end){
            ++end;
        }
        --end;
        while (str < end){
            temp = *str;
            *str++ = *end;
            *end-- = temp;
        }
    }
}
1.3给定两个字符串,请编写程序,确定其中一个字符串重新排列后能否变成另外的一个字符串。

思路:先去定细节,变位词Dog与God疏忽是同一个字符串,空格出现算不算,String.trim()去除首尾的空格。
解法1:可以先对字符串进行排序处理,String.toCharArray(),java.util.Arrays.sort()方法
解法2:假设为ASCII码,那么用int数组记录第一个字串出现的次数,当第二字符串字符出现次数大于第一个出现次数时,返回false。第一个字符串使用toCharArray的方法,第二个使用charAt()。

1.4编写方法,将字符串中的空格全部替换为“%20”。

思路:字符串的操作,这个要进行两次遍历,先进行一次得到数组中空字符串的个数,然后再进行处理。从尾部开始,避免数据丢失。
这里给出代码:

public void replaceSpace(char[] str, int length){
    int spacenum = 0, newlength, i;
    for(i = 0; i < length; i++){
        if (str[i] == ' '){
            spacenum++;
        }
    }
    newlength = length + spacenum * 2;
    str[newlength] = '\n';//结束标志位
    int index = newlength - 1;
    for (i = length - 1; i > 0; i--){
        if (str[i] != ' '){
            str[index--] = str[i];
        } else {
            str[index--] = '0';
            str[index--] = '2';
            str[index--] = '%';
        }
    }
}
1.5利用字符重复出现的次数,编写一个方法,实现基本的字符串的压缩功能。比如,字符串“aabcccccaaa”会变为a2b1c5a3。若压缩后没有变短,就返回原字符串。

思路:采用StringBuffer,按照规则进行统计,最后进行长度统计。

1.6给定一幅N*N矩阵表示的图像,其中每个像素的大小为4个字节,编写一个方法,将图像旋转90度。不占用额外的空间。

思路:进行一层层的旋转,对每一层进行环状旋转。用first来定义每一个环的最小下标,last表示最小标志,offset做缓存。

     public static void rotate(int[][] num) {
         int len = num.length;
         for (int layer = 0; layer < len / 2; layer++){
             int first = layer;
             int last = len - 1 - first;
             for (int i = first; i < last; i++){
                 int offset = i - first;
                 int top = num[first][i];
                 //左转上
                 num[first][i] = num[last - offset][first];
                 //下转左
                 num[last - offset][first] = num[last][last - offset];
                 //右转下
                 num[last][last - offset] = num[i][last];
                 //上转右
                 num[i][last] = top; 
             }
         }
    }
1.7编写一个方法,若M*N矩阵中某个元素为0,则将其所在的行与列清零。

思路:这是一个陷阱题,首先用两个booelan类型的数组进行归零行以及列的标记,下一步再进行清零操作。

1.8假定有一个方法isSubString,给定两个字符串s1与s2,编写代码检查s2是否由s1旋转组成,只能调用一次isSubString的方法。

思路:out of box方法,假定s1 = xy = waterbottle,x = wat, y = terbottle,s2 = yx =erbottlemat,yx 肯定是xyxy的子串。先进行长度的判定,长度不同,肯定返回false,然后利用子串进行判定。

public boolean isRotation(String s1, String s2) {
    if (s1 == null && s2 == null) return false;
    if (s1 == null || s2 == null) return true;
    int len = s1.length();
    if (len == s2.length() && len > 0) {
        String s1s1 = s1 + s1;
        return isSubstring(s1s1, s1);
    }
    return false;
}

链表

链表这块需要注意dummy的使用

2.1 编写代码,移除未排序链表中的重复节点。进阶:如果不使用缓冲区,该怎么解决?

思路:利用散列表记录,有一个函数需要掌握,containsKey(),同时注意链表的删除操作,要有previous的缓存。

public void deleteDups(LinkedListNode n){
    Hashtable table = new Hashtable();
    LinkedListNode previous = null;
    while (n != null){
        if (table.containsKey(n.data)){
            previous.next = n.next;
        } else {
            table.put(n.data, true);
            previous = n;
        }
        n = n.next;
    }
}

不使用缓存区,就得采用两个指针进行迭代处理

2.2实现一个算法,找出单向链表中倒数第k个结点。

思路:用先行指针的方法

2.3实现一个算法,删除单向链表中间的某个结点,假定你只能访问该结点。

思路:将当前结点的下一个结点的值复制到当前结点,然后删除下一个结点。

2.4编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前。

思路:这个是采用新建两个链表,然后进行合并处理的方式。
java中的super()方法是针对父类来说的。

2.5给定两个用链表表示的整数,每个节点包含一个数位。这些数位是反向存放的也就是个位排在链表的首部。编写函数对这两个整数求和,并利用链表形式返回结果。

示例 : 输入 (7-> 1 -> 6) + ( 5 -> 9 -> 2) ,即617 + 295 与普通的加法保持一致 输出 2-> 1-> 9 ,即912.
这个采用的是普通的加法进行处理。
进阶 :假设这些数位是正向存放的,请再做一遍。
这个是要用到递归进行处理,需要注意两个数的位数不相等。

2.6给定一个有环链表,实现一个算法返回环路的开头结点。

有环链表的定义,在链表中的某个结点的next元素指向在它前面出现过的结点,则表明链表存在环路。
示例
输入: A->B ->C->D->E->C (C结点出现了两次)
那么返回:C 结点
思路:设置两个指针,fast与slow,假设从第s个结点,进入到环路,那么当slow在s结点的时候,fast处于2s结点,让大S为 S = s mod loop_size,此时,fast与slow相差S步,在loop_size - S 步以后,fast 与 slow相遇,碰撞结点距离环路开始的位置为S,(对于slow来说,走了loop_size - S步,那么loop_size- (loop_size- S))此时碰撞结点距离环路起始处的距离为s个结点,链表开始位置也是距离起始处s个结点,那么两个指针方向同时出发,会相交于环路起始结点。

public static LinkedListNode getBegainHead(LinkedListNode head){
        LinkedListNode fast = head;
        LinkedListNode slow = head;
        while (fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
            if (fast == slow){
                break;
            }
        }
        if (fast == null || fast.next == null){
            return null;
        }
        slow = head;
        while (slow != fast){
            slow = slow.next;
            fast = fast.next;
        }
        return fast;
    }

这是一个很经典的方法。

2.7 编写一个函数,检查链表是否为回文。

思路:先行指针,取到中间位置的数,用stack来存储数据,注意长度为奇数,根据fast指向的内容即可判断。

栈与队列

3.2请设计一个栈,除push与pop方法,还支持min方法,可返回栈元素中的最小值。push、pop、min方法的时间复杂度为O(1)。

思路:1.新封装 一个对象,对象中包含 value 以及 min,在stack中进行存储。注意super.调用父类方法,peek()查看栈顶元素
2.与以上类似,设计子类,继承Stack,子类中增加新的Stack用于存储出现变化的最小值,入栈操作时进行比较,出栈操作时进行更新。

3.4经典汉诺塔问题

思路:利用stack的数据类型做数据存储
递归方法求解:

public void moveDisks(int n, Tower origin, Tower destination, Tower buffer){
    if (n <= 0) return;
    moveDisks(n -1, origin, buffer, destination);
    moveTop(origin, destination);
    moveDisks(n - 1, buffer, destination, origin);
}
3.5实现一个MyQuene类,该类用两个栈来实现一个队列

思路:两个栈,一个为new,另外一个为old。队列add数据为new push数据,队列出数据,从old pop数据,如果old 为空,则将new出栈,old入栈。
两个队列实现栈的话,

class MyStack {
    private Queue<Integer> inquene = new LinkedList<Integer>();
    private Queue<Integer> outquene = new LinkedList<Integer>();
    int temp =0;
    // Push element x onto stack.
    public void push(int x) {
        inquene.add(x);
    }
    // Removes the element on top of the stack.
    public void pop() {
      if ( inquene.isEmpty()){
          while (!outquene.isEmpty()){
              temp = outquene.peek();
              outquene.poll();
              if( !outquene.isEmpty() ){
                  inquene.add(temp);
              }
          }  
      } else {
            while (!inquene.isEmpty()){
                 temp = inquene.peek();
                  inquene.poll();
                  if( !inquene.isEmpty() ){
                      outquene.add(temp);
                  }
            }
        }
    }
    // Get the top element.
    public int top() {
        if( inquene.isEmpty() ){
            while( !outquene.isEmpty() ){
                  temp = outquene.peek();
                  outquene.poll();
              }
            return temp;
        }else{
             while(  !inquene.isEmpty() ){
                temp = inquene.peek();
                inquene.poll();
                outquene.add(temp);
            }
             return temp;
        }       
    }
    // Return whether the stack is empty.
    public boolean empty() {
        return inquene.isEmpty()&&outquene.isEmpty();
    }
}
3.6经典的stack排序问题,按照升序对栈进行排序。最多只能使用一个额外的栈存放临时数据。

思路:新建一个栈,

//注意给定两个while指针的使用
public Stack<Integer> stackSort(Stack<Integer> s1){
    Stack<Integer> s2 = new Stack<Integer>();
    while (!s1.isEmpty()){
        Integer temp = s1.pop();
        while(!s2.isEmpty() && s2.peek() > temp){// 本次while循环保证temp是当前s2里面最小的那个
            s1.push(s2.pop());
        }
        s2.push(temp);// 
    }
    return s2;
}

树与图

树的三种遍历方式,前序遍历,中序遍历,后序遍历等,递归形式的实现以及使用栈与队列迭代形式的实现。用V表示父节点,L表示左子节点,R表示右子节点,则VLR表示先序遍历,LVR表示中序遍历,LRV表示后序遍历。在处理时,按照递归的思想,对每一个结点都进行顺序上的检查处理。前序,中序,后序是根据中间结点被访问的相对顺序来说的。
判断图是否有环:

针对无向图可以采用并查集来判断是否有环:
class GraphCycle{
     int V, E;    // V-> no. of vertices & E->no.of edges
     Edge edge[]; // /collection of all edges

     class Edge {//edges
         int src, dest;
     };

     // Creates a graph with V vertices and E edges
     GraphCycle(int v,int e){
         V = v;
         E = e;
         edge = new Edge[E];
         for (int i=0; i<e; ++i)
             edge[i] = new Edge();
     }

     // A utility function to find the subset of an element i
     int find(int parent[], int i){
         if (parent[i] == -1)
             return i;
         return find(parent, parent[i]);
     }

     // A utility function to do union of two subsets
     void Union(int parent[], int x, int y){
         int xset = find(parent, x);
         int yset = find(parent, y);
         parent[xset] = yset;
     }


     // The main function to check whether a given graph
     // contains cycle or not
     int isCycle( GraphCycle graph) {
         // Allocate memory for creating V subsets
         int parent[] = new int[graph.V];

         // Initialize all subsets as single element sets
         for (int i=0; i<graph.V; ++i)
             parent[i]=-1;

         // Iterate through all edges of graph, find subset of both
         // vertices of every edge, if both subsets are same, then
         // there is cycle in graph.
         for (int i = 0; i < graph.E; ++i) {
             int x = graph.find(parent, graph.edge[i].src);
             int y = graph.find(parent, graph.edge[i].dest);

             if (x == y && x != -1)
                 return 1;
             graph.Union(parent, x, y);
         }
         return 0;
     }  
针对有向图,采用的是dfs加上标记位来做
      public boolean canFinish(int numCourses, int[][] prerequisites) {
            HashSet<Integer>[] edges = new HashSet[numCourses];
            for (int i = 0 ; i < numCourses; i++) {
                edges[i] = new HashSet<Integer>();
            }
            for (int[] temp : prerequisites) {
                HashSet a = edges[temp[0]];
                a.add(temp[1]);
            }
            for (int i = 0; i < numCourses; i++) {
                boolean[] visit = new boolean[numCourses];
                boolean[] resTack = new boolean[numCourses];
                Arrays.fill(visit, false);
                Arrays.fill(resTack, false);
                if (isRecyle(i, edges, visit, resTack)) {
                    return false;
                }
            }
            return true;
      }
      public boolean isRecyle(int i,HashSet<Integer>[] edges, boolean[] visit, boolean[] resTack) {
          if (visit[i] == false) {
              visit[i] = true;
              resTack[i] = true;
              HashSet<Integer> pre = edges[i];
              for (int id : pre) {
                  if (! visit[id] && isRecyle(id,edges, visit, resTack) ) {
                      return true;
                  } else if (resTack[id]) {
                      return true;
                  }
              }
          }
          resTack[i] = false;
          return false;
      }

图的遍历
深度优先搜索

// 递归版本
void DFSsearch(Node root){
    if (root == null){
        return;
    }
    visit(root);
    root.isvisited = true;
    foreach (Node n in root.adjacent){
        search(n);
    }
}
//迭代版本,与树的前序遍历类似,先访问本节点的内容,右边入栈,左边入栈
void DFSearch(Node root){
    if (root == null){
        return; 
    }
    Stack<Node> stack = new Stack(root);
    stack.push(root);
    Node temp = null;
    while(stack.size() > 0){
        temp = stack.pop();
        if (root.right != null){
            stack.push(root.right)
        }
        if (root.left != null){
            stack.push(root.left);
        }
    }
}
//广度优先的话,就采用队列的形式
void search(Node root){
    if (null == root){
        return;
    }
    Quene<Node> que = new LinkedList<Node>();
    root.visited = true;
    visit(root);
    que.add(root);
    Node temp = null;
    while (que.size() > 0){
        temp = que.remove();
        for (Node n in temp.adjacent){
            visit(n);
            n.visited = true;
            que.add(n);
        }
    }
}

注意substring(a, b);从0开始,包含a,但是不包含b。
递归版树的遍历
前序vlr

public void trvelPre(TreeNode root){
    if (null == root){
        retrun;
    }
    visit(root.data);
    trvelPre(root.left);
    trvelPre(root.right);
}
中序lvr以及后续lrv只是修改递归的后三条语句就可以

迭代版的遍历

前序遍历
public void trvelPre(TreeNode root){
    if (null == root){
        return;
    }
    Stack<TreeNode> stack = new Stack<TreeNode>();
    stack.push(root);
    while(!stack.isEmpty()){
        TreeNode temp = stack.pop();
        visit(temp);
        if (null != temp.right){
            stack.push(temp.right);
        }
        if (null != temp.left){
            stack.push(temp.left);
        }
    }
}
中序遍历,对于完备的树,可以得到parent,空间复杂度为O(1),非完备的就先不这样处理
public void trvelIn(TreeNode root){
        if (null == root){return;}
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode temp = root;
        //中序遍历方式有所不同,碰到左节点就入栈,左节点访问完成后,转向右子节点
        while (true){
            if (temp != null){
                stack.push(temp);
                temp = temp.left;
            } else if (!stack.isEmpty()){
                temp = stack.pop();
                System.out.print(temp.val);
                temp = temp.right;
            } else {
                break;
            }
        }
}
后序遍历
public void vistiafter(TreeNode root) {  
        if (null == root ){return;}
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode temp = root;
        stack.push(temp);
        while (!stack.isEmpty()){
            if ((stack.peek().left != temp) && (stack.peek().right != temp)){
                //当前temp结点既不表示栈顶元素的左节点也不表示右节点,
                //temp栈顶元素的左兄弟结点或者是root结点
                // 表示切换子树
                getHLVFL(stack.peek(), stack);
            }
            temp = stack.pop();
            System.out.print(temp.val);
        }
    }
    public void getHLVFL(TreeNode temp, Stack<TreeNode> stack){
        while(null != temp){
            if (null != temp.left){
                if (null != temp.right){
                    stack.push(temp.right);
                }
                stack.push(temp.left);
            } else {
                stack.push(temp.right);
            }
            temp = stack.peek();
        }
        stack.pop();
    }
    后序遍历结束

根据vlr以及lvr,得到lrv,构造出树

    public TreeNode getaf(String pre, String in ,int len){
        TreeNode node = new TreeNode();
        if(len == 0){
            return null;
        }
        char root = pre.charAt(0);
        int index = 0;
        for(int i = 0; i < len; i++){
            if(root == in.charAt(i)){
                index = i;
                break;
            }
        }
        node.val = root;
        node.left = getaf(pre.substring(1,index + 1), in.substring(0, index), index );
        node.right = getaf(pre.substring(index + 1, len), in.substring(index + 1, len), len - index - 1);
        System.out.println(root);//这条语句放的位置,可以输出不同的遍历顺序,现在是后序,最上面是前序,放到中间就是中序
        return node;
    }
//root.right = bulidHelp(pre, in, preroot + index - left + 1, index + 1, right);对两边的进行处理

图的DFS深度优先遍历,BFS广度优先遍历,要使用到队列

4.1检查二叉树是否平衡,任意一个结点,其两棵子树的高度差不超过1

思路:递归得到树的高度,递归判断每一个结点是否平衡

public int checkHeight(TreeNode root){
    if (null == root){
        return 0;
    }
    int leftHeight = checkHeight(root.left);
    if (leftHeight == -1){
        return -1;
    }
    int rightHeight = cheakHeight(root.right);
    if (rightHeight == -1){
        return -1;
    }
    if (Math.abs(leftHeight - rightHeight) > 1){
        return -1;
    } else {
        return Math.max(leftHeight, rightHeight) + 1;
    }
}
public boolean isBlance(TreeNode tree){
    if (checkHeight(tree) == -1){
        return fasle;
    } else {
        return true;
    }
}
4.2给定一个有向图,找出两个节点之间是否存在一条路径

广度优先搜索适合查找最短路径

public enum State{
    Unvisited, Visited, Visiting;
}
public static boolean search(Graph g, Node start, Node end){
    if (null == g || null == start){
        return false;
    }
    LinkedList<Node> list = new LinkedList<Node>();
    for (Node u : g.getNodes()){
        u.state = State.Unvisited;
    }
    list.add(start);
    start.state = State.Visiting;
    Node u = null;
    while(!list.isEmpty()){
        u = q.removeFirst();
        if (u != null){
            for (Node v : u.getAdjacent()){
                if (v.state == State.Unvisited){
                    if (v == end){
                        return true;
                    } else {
                        v.state = State.Visiting;
                        q.add(v);
                    }
                }
            }
            u.state = State.Visited;
        }
    }
    return false;
}
4.3给定一个有序整数数组,元素个不相同,并且按照升序排列,编写算法创建高度最小的二叉查找树。

使处于中间位置上的元素更靠近根节点。

public TreeNode createMin(int nums, int start, int end){
    if (start > end){
        return null;
    }
    int mid = start + ((end - start) >> 1);
    TreeNode temp = new TreeNode(nums[mid]);
    temp.left = createMin(nums, start, mid - 1);
    temp.right = createMin(nums, mid + 1, end);
    return temp;
}
public TreeNode createMinBFS(int[] nums){
    return createMin(nums, 0, nums.length - 1);
}
4.4给定一个二叉树,创建含有某一深度上的所有结点的链表,比如一棵树的深度为D,创建D个链表。

思路:对广度优先的算法进行稍微修改,一层一层增加即可。

4.5检查一课二叉树是否为二叉查找树

思路:1.如果不存在相等的树,所有左结点小于等于当前结点,当前结点小于右结点,current.left.val<= current.val < current.right.val(程序也可以这么写)。改进,递归

public static int last_printed = integer.MIN_VALUE;
public boolean checkBFS(TreeNode root){
    if (null == root){return true;}
    if (!checkBFS(root.left)){
        return false;
    }
    if (root.val <= last_printed){// 右侧的必须大于
        return false;
    }
    last_printed = temp.val;
    if (!checkBFS(root.right)){
        return false;
    }
    return true;
}

思路2,利用最大最小算法,递归,限定当前结点的数的范围,与数学上的夹逼准则类似

public boolean checkMaxMinBFS(TreeNode root, int min, int max){
    if (null == root){return true;}
    if (root.val <= min || root.val > max){
        return false;
    }
    if (!checkMaxMinBFS(root.left, min, root.val) || !checkMaxMinBFS(root.right, root.val, max)){
        return false;
    }
    return true;
}
public boolean checkBFS(TreeNode root){
    return checkMaxMinBFS(root, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
#
4.6找出二叉查找树的下一个结点(可以得到父节点)

思路:也就是中序遍历的下一个结点,此时要分开讨论

public TreeNode leftMostChild(TreeNode root){
    if (null == root){return null;}
    while(root.left != null){
        root = root.left;
    }
    return root;
}
public TreeNode inorderSucc(TreeNode n){
    if (null == n){return null;}
    if(n.right != null){
        return leftMostChild(n.right);
    } else {
        TreeNode cu = n;
        TreeNode pa = cu.parent;
        while (pa != null && pa.left != cu){
            cu = pa;
            pa = cu.parent;
        }
        return pa;
    }
}
4.7 找出二叉树中两个结点的第一个共同祖先。不得将额外的结点存储在数据结构中

思路:1.从根结点调用cover方法,先检查是否都在根结点中,不在的话返回null,然后依次调用,left与right,
2.递归,优化常数时间 返回值依次为 返回p,root子树包含p不包含q;返回q,root子树中包含q不包含p;返回null,都不包含;否则返回 p与q的共同祖先。

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q)  return root;
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        if(left != null && right != null)   return root;
        return left != null ? left : right;
    }
     // 非递归版本的,时间复杂度挺高的。
       public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        Map<TreeNode, TreeNode> parents = new HashMap<TreeNode, TreeNode>();
        Queue<TreeNode > queue  = new LinkedList<>();
        parents.put(root, null);
        queue.offer(root);
        TreeNode temp = null;
        while (!parents.containsKey(p) || !parents.containsKey(q)) {
            temp = queue.poll();
            if (temp.left != null) {
                parents.put(temp.left, temp);
                queue.offer(temp.left);
            }
            if (temp.right != null) {
                parents.put(temp.right, temp);
                queue.offer(temp.right);               
            }
        }
        Set<TreeNode> anc = new HashSet<>();
        while (p != null) {
            anc.add(p);
            p = parents.get(p);
        }
        while (!anc.contains(q)) {
            q = parents.get(q);
        }
        return q;
    }
4.8你有一颗非常大的二叉树:T1,有几百万个结点;T2有几百个结点。设计一个算法,判断T2是不是T1的子树

思路1:对两个树前序以及中序遍历,判断T2是不是T1的子串,注意null补全特殊的字符
2:递归调用

public boolean treeMatch(TreeNode a, TreeNode b){
    if (a == null && b == null){
        return true;
    }
    if (a == null || b == null){
        return false;
    }
    if (a.val != b.val){
        return false;
    }
    return (treeMatch(a.left, b.left) && treeMatch(a.right, b.right));
}
public boolean isSubTree(TreeNode t1, TreeNode t2){
    if (null == t1 && null == t2){
        return true;
    }
    if (t1 == null){
        return false;
    }
    if (t1.val == t2.val){
        if (treeMatch(t1, t2)){return true;}
    }
    return (isSubTree(t1.left, t2) || isSubTree(t1.right, t2));
}
4.9给定一个二叉树,其中每一个结点都含有一个数值。设计一个算法,打印某个结点数值总和等于某个给定值的所有路径。

思路:从根节点出发进行计算

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值