[Algorithm]九章四:BSF

69. Binary Tree Level Order Traversal: 点击打开链接

Time: O(n)

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
 
public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: Level order a list of lists of integer
     */
    public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) {
        ArrayList<ArrayList<Integer>> result=new ArrayList<>();
        if(root==null){
            return result;
        }
        
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);                              //先把root的值放入
        
        while(!queue.isEmpty()){                        //每次while循环的时候都是前一层节点加入后进行的
            ArrayList<Integer> level=new ArrayList<>();
            int size=queue.size();
            for(int i=0;i<size;i++){                    //加入每层的结点,同时拿到下一层的结点加入queue里,使得while循环不为空
                TreeNode cur=queue.poll();
                level.add(cur.val);
                
                if(cur.left!=null){                     //拿下一层的节点
                    queue.offer(cur.left);
                }
                if(cur.right!=null){
                    queue.offer(cur.right);
                }
            }
            result.add(level);
        }
        return result;
    }   
}

71.Binary Tree Zigzag Level Order Traversal: 点击打开链接    

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
public class Solution {                    
    /**
     * @param root: The root of binary tree.
     * @return: A list of lists of integer include 
     *          the zigzag level order traversal of its nodes' values 
     */
    public ArrayList<ArrayList<Integer>> zigzagLevelOrder(TreeNode root) {
        ArrayList<ArrayList<Integer>> result=new ArrayList<>();
        if(root==null){
            return result;
        }
        
        Queue<TreeNode> queue=new LinkedList<>();
        queue.offer(root);
        boolean rightOrder=true;                    //只需要这边多个flag来指示每层的顺序是从左向右,还是从右向左
        
        while(!queue.isEmpty()){
            ArrayList<Integer> level=new ArrayList<>();
            int size=queue.size();
            
            for(int i=0;i<size;i++){
                TreeNode cur=queue.poll();
                if(rightOrder){
                    level.add(cur.val);
                }else{
                    level.add(0,cur.val);           //ArrayList这个方法是给添加的元素指定位置,这里指定位置为最前面
                }
                if(cur.left!=null){
                    queue.add(cur.left);
                }
                if(cur.right!=null){
                    queue.add(cur.right);
                }
            }
            result.add(level);                      //还有一种方法是每次添加到result前,
            rightOrder=!rightOrder;                 //根据flag判断 Collections.reverse(level);
        }
        return result;
    }
}

281. Zigzag Iterator - LeetCode

note:感觉是我找到的参考中最好的解答方法,简洁易懂,queue的很好练习

public class ZigzagIterator {
    
    Queue<Integer> queue = new LinkedList<>();    
    public ZigzagIterator(List<Integer> v1, List<Integer> v2) {
        int len = Math.min(v1.size(), v2.size());
        for(int i=0; i<len; i++)
        {
            queue.offer(v1.get(i));
            queue.offer(v2.get(i));
        }
        
        if(v1.size()>v2.size())
        {
            for(int i=len; i<v1.size(); i++)
            {
                queue.offer(v1.get(i));
            }
        }
        else{
            for(int i=len; i<v2.size(); i++)
            {
                queue.offer(v2.get(i));
            }
        }
    }

    public int next() {
        return queue.poll();
    }

    public boolean hasNext() {
        return !queue.isEmpty();
    }
}

/**
 * Your ZigzagIterator object will be instantiated and called as such:
 * ZigzagIterator i = new ZigzagIterator(v1, v2);
 * while (i.hasNext()) v[f()] = i.next();
 */

7. Binary Tree Serialization and Derialization: 点击打开链接

    1                
   / \                  
  2   3               

思路:序列化为:1,2,#,#,3,#,#

/**
 * Definition of TreeNode:
 * public class TreeNode {
 *     public int val;
 *     public TreeNode left, right;
 *     public TreeNode(int val) {
 *         this.val = val;
 *         this.left = this.right = null;
 *     }
 * }
 */
class Solution {
    public String serialize(TreeNode root) {                                 //序列化
        return serial(new StringBuilder(), root).toString();
    }

    private StringBuilder serial(StringBuilder sb, TreeNode root) {   
        if (root == null) {
            return sb.append("#").append(",");
        }else{
            sb.append(root.val).append(",");
        }
       
        serial(sb, root.left);
        serial(sb, root.right);
        return sb;
    }

    
  
    public TreeNode deserialize(String data) {                               //反序列化
        return deserial(new LinkedList<>(Arrays.asList(data.split(","))));
    }
    
    private TreeNode deserial(Queue<String> queue) {                         //建树的过程                       
        String val = queue.poll();
        if ("#".equals(val)) return null;
        TreeNode root = new TreeNode(Integer.valueOf(val));
        root.left = deserial(queue);
        root.right = deserial(queue);
        return root;
    }
}

178.Graph Valid Tree: 点击打开链接

思路:以n=5, edges={{0,1}, {0,2}, {0,3}, {1,4}}为例:

1. 初始化图: {0=[1, 2, 3],1=[0, 4],2=[0],3=[0],4=[1]}

2. 对graph里的每一个value进行判断,如果这些value去重后最后的集合是key的集合{0,1,2,3,4},就是树。

注意:图是一棵树需要满足两个条件:n-1=边的条数,n个点连通

所以要判断两步:

  • 判断边的条数是不是等于n-1
  • 判断从一点出发(任意一点),是不是能连通另外所有的点
public class Solution {
    /**
     * @param n an integer
     * @param edges a list of undirected edges
     * @return true if it's a valid tree, or false
     */
    public boolean validTree(int n, int[][] edges) {
        if(n==0){       
            return false;
        }                                                //图是一棵树要满足两个条件:
        if(edges.length!=n-1){                           //条件1:n-1=边的条数
            return false;
        }
        Map<Integer, Set<Integer>> graph=initializeGraph(n,edges);
        
        Queue<Integer> queue=new LinkedList<>();
        Set<Integer> set=new HashSet<>();
        
        queue.offer(0);
        set.add(0);
        while(!queue.isEmpty()){
            int node=queue.poll();
            for(Integer neighbor: graph.get(node)){      //就是把所有连通的点放在set里的过程,最后用条件2判断
                if(set.contains(neighbor)){              //每次往set里放之前都要先判断是不是已经存在于set里
                    continue;                            //如果已经在了,continue掉当前neighbor,查看下一个               }
                set.add(neighbor);
                queue.offer(neighbor);
            }
        }
        
        // 就是要看从一点出发,是不是能找到其余所有的点
        return set.size()==n;                            //条件2:n个点连通(也就是没有零星节点在连着的集体外面)
    }
    

    //EX. [[0,1],[0,2],[0,3],[1,4]], 对于点1,map的key是1,set是{0,4}
    private Map<Integer, Set<Integer>> initializeGraph(int n, int[][] edges){
        Map<Integer, Set<Integer>> graph=new HashMap<>();   //map装的是<每个点,和每个点相邻的边的另外连着的点的集合set>
        for(int i=0;i<n;i++){
            graph.put(i, new HashSet<Integer>());           //先把map里装上<每个点,<>>, 空set是将要装满足条件的点的
        }
        for(int i=0;i<edges.length;i++){                    //graph用二维数组表示
            int a=edges[i][0];                              //整个操作就是装map
            int b=edges[i][1];
            graph.get(a).add(b);
            graph.get(b).add(a);
        }
        return graph;
    }
}

323. Number of Connected Components in an Undirected Graph

Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), write a function to find the number of connected components in an undirected graph.

Example 1:

     0          3
     |          |
     1 --- 2    4

Given n = 5 and edges = [[0, 1], [1, 2], [3, 4]], return 2.

Example 2:

     0           4
     |           |
     1 --- 2 --- 3

Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [3, 4]], return 1.

You can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges.

思路:遍历n里的每一个点,如果点不在visited HashSet里,就有一个component,然后bfs这个component找到这一块的所有连通点

注意:很多情况下都是Queue和HashSet连在一起用的,HashSet可以在整体上帮助判断当前点有没有被遍历过

 

class Solution {
    public int countComponents(int n, int[][] edges) {
        Map<Integer,Set<Integer>> map=getGraph(n,edges);

        HashSet<Integer> visited = new HashSet<>();
        int count = 0;
        for(int i=0;i<n;i++){
            if(!visited.contains(i)){     //一开始visited的size是0, 所以只有一个连通块的情况就是从这里入口,进行宽搜,后面遍历到的所有元素,都是set里
                count++;
                bfs(map,i,visited);       //哪个元素不在set里,就用那个元素做为入口,把这个元素所在的连通块里的所有元素都加入set里
            }
        }
        return count;
    }

    // 所以这个题从始至终,只有一个set,无论几个连通块进行各自的bfs, 都加入这个set里
    private void bfs(Map<Integer,Set<Integer>> map, int i, Set<Integer> visited){
        Queue<Integer> q = new LinkedList<>();
        q.offer(i);
        visited.add(i);
        while(!q.isEmpty()){
            int curr = q.poll();
            for(int neighbor : map.get(curr)){
                if(!visited.contains(neighbor)){
                    q.offer(neighbor);
                    visited.add(neighbor);
                }
            }
        }
    }
    
    private Map<Integer,Set<Integer>> getGraph(int n,int[][] edges){
        Map<Integer,Set<Integer>> map=new HashMap<>();
        for(int i=0;i<n;i++){
            map.put(i,new HashSet<Integer>());
        }
        for(int i=0;i<edges.length;i++){
            int a=edges[i][0];
            int b=edges[i][1];
            map.get(a).add(b);
            map.get(b).add(a);
            
        }
        return map;   
    }     
}

 

137. Clone Graph: 点击打开链接

/**
 * Definition for undirected graph.
 * class UndirectedGraphNode {
 *     int label;
 *     ArrayList<UndirectedGraphNode> neighbors;
 *     UndirectedGraphNode(int x) { 
 *        label = x; 
 *        neighbors = new ArrayList<UndirectedGraphNode>();
 *     }
 * };
 */
public class Solution {
    /**
     * @param node: A undirected graph node
     * @return: A undirected graph node
     */
    public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
        if(node==null){
            return node;
        }
          
        ArrayList<UndirectedGraphNode> nodes=getNodes(node);                    //拿到所有和node连接点                                
        Map<UndirectedGraphNode, UndirectedGraphNode> mapping=new HashMap<>();  //map是新老节点的映射<老节点,新克隆的节点>
        for(UndirectedGraphNode n : nodes){                                     //克隆每一个点
            //因为题目给定的UndirectedGraphNode类的neighbors属性是constructor一加载,自动new ArrayList<>() 
            //所以这边要注意new实例时的小细节 
            mapping.put(n, new UndirectedGraphNode(n.label));
        }
        for(UndirectedGraphNode n : nodes){                                     //克隆每一条边
            UndirectedGraphNode newNode=mapping.get(n);
            for(UndirectedGraphNode neighbor : n.neighbors){
                UndirectedGraphNode newNeighbor=mapping.get(neighbor);
                newNode.neighbors.add(newNeighbor);
            }
        }
        return mapping.get(node);                                               //return的就是和老节点对应的新节点node
    }
    
    private ArrayList<UndirectedGraphNode> getNodes(UndirectedGraphNode node){  //通过一个点找到这个点的所有连通点
        Queue<UndirectedGraphNode> queue=new LinkedList<>();
        Set<UndirectedGraphNode> set=new HashSet<>();
        
        queue.offer(node);
        set.add(node);
        while(!queue.isEmpty()){
            UndirectedGraphNode head=queue.poll();
            for(UndirectedGraphNode neighbor:head.neighbors){
                if(!set.contains(neighbor)){
                    set.add(neighbor);
                    queue.offer(neighbor);
                }
            }
        }
        return new ArrayList<UndirectedGraphNode>(set);
    }
}

618. Search Graph Nodes: 点击打开链接

/**
 * Definition for graph node.
 * class UndirectedGraphNode {
 *     int label;
 *     ArrayList<UndirectedGraphNode> neighbors;
 *     UndirectedGraphNode(int x) { 
 *         label = x; neighbors = new ArrayList<UndirectedGraphNode>(); 
 *     }
 * };
 */
public class Solution {
    /**
     * @param graph a list of Undirected graph node
     * @param values a hash mapping, <UndirectedGraphNode, (int)value>
     * @param node an Undirected graph node
     * @param target an integer
     * @return the a node
     */
    public UndirectedGraphNode searchNode(ArrayList<UndirectedGraphNode> graph,  //gragh参数是多余的
                                          Map<UndirectedGraphNode, Integer> values,
                                          UndirectedGraphNode node,              //因为通过这一点可以访问到其他的点
                                          int target) {
       Queue<UndirectedGraphNode> queue=new LinkedList<>();
       Set<UndirectedGraphNode> set=new HashSet<>();
       
       queue.offer(node);
       set.add(node);
       
       while(!queue.isEmpty()){
           UndirectedGraphNode curNode=queue.poll();
           if(values.get(curNode)==target){                          //用queue遍历,先拿到的点一定是离当前点最近的
               return curNode;
           }
           for(UndirectedGraphNode neighbor:curNode.neighbors){
               if(!set.contains(neighbor)){
                   set.add(neighbor);
                   queue.offer(neighbor);
               }
           }
       }
       return null;
    }
}

127.Topological Sort: 点击打开链接

/**
 * Definition for Directed graph.
 * class DirectedGraphNode {
 *     int label;
 *     ArrayList<DirectedGraphNode> neighbors;
 *     DirectedGraphNode(int x) { label = x; neighbors = new ArrayList<DirectedGraphNode>(); }
 * };
 */
public class Solution {
    /**
     * @param graph: A list of Directed graph node
     * @return: Any topological order for the given graph.
     */    
    public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
        ArrayList<DirectedGraphNode> result=new ArrayList<>();
        if(graph==null){
            return result;
        }
        
        Map<DirectedGraphNode,Integer> indegree=getIndegree(graph);   //拿到整个图上所有点和每点对应的入度映射
        
        Queue<DirectedGraphNode> queue=new LinkedList<>();
        
        for(DirectedGraphNode node:graph){                            //这边要有个判断,indegree为0的首先进queue
            if(indegree.get(node)==0){
                queue.offer(node);
                result.add(node);
            }
        }
        
        while(!queue.isEmpty()){
            DirectedGraphNode curNode=queue.poll();                   //只要有点从queue里poll出
            for(DirectedGraphNode neighbor:curNode.neighbors){        //就要把此点的所有邻居点的indegree-1
                indegree.put(neighbor,indegree.get(neighbor)-1);      //因为此点被删,所有的邻居点的入度都要减少1
                if(indegree.get(neighbor)==0){
                    queue.offer(neighbor);
                    result.add(neighbor);
                }
            }
        }
        return result;
    }
    
    private Map<DirectedGraphNode,Integer> getIndegree(ArrayList<DirectedGraphNode> graph){
        Map<DirectedGraphNode,Integer> map=new HashMap<>();      //得到graph里每一个node的入度indegree
        
        for(DirectedGraphNode node:graph){                       //先初始化graph里每一个node,使得入度是0
            map.put(node,0);
        }
        for(DirectedGraphNode node:graph){
            for(DirectedGraphNode neighbor:node.neighbors){      //然后再对每个node的邻居点算入度
                map.put(neighbor,map.get(neighbor)+1);
            }
        }  
        return map;      
    }
}

615. Course Schedule:   点击打开链接

以numCourses=5, prerequisites={{1,0}, {2,0}, {4,2}, {4,1}}为例:

public class Solution {
    /**
     * @param numCourses a total of n courses
     * @param prerequisites a list of prerequisite pairs
     * @return true if can finish all courses or false
     */
    public boolean canFinish(int numCourses, int[][] prerequisites) {
        List<Integer>[] neighbors=new ArrayList[numCourses]; //List数组[null,null,null,null,null]
        int[] degree=new int[numCourses];                    //每个课程的入度数组[0,0,0,0,0]
        
        for(int i=0;i<neighbors.length;i++){                 //初始化List数组[[],[],[],[],[]]
            neighbors[i]=new ArrayList<>();
        }
        
        for(int i=0;i<prerequisites.length;i++){  //prerequisites[i][0]或是prerequisites[i][1]表示每一个课程
            degree[prerequisites[i][0]]++;                              //[0,1,1,0,2]
            neighbors[prerequisites[i][1]].add(prerequisites[i][0]);    //[[1,2],[4],[4],[],[]]
        }
        
        Queue<Integer> queue=new LinkedList<>();
        for(int i=0;i<degree.length;i++){
            if(degree[i]==0){
                queue.offer(i);
            }
        }
        
        int resultNum=0;
        while(!queue.isEmpty()){
            int course=queue.poll();                        //每一个检测完的的课程都要删掉
            resultNum++;                                    //然后检测的结果数+1
            
            int size=neighbors[course].size();              //针对刚才删掉的课程对它的邻居课程List进行判断
            for(int i=0;i<size;i++){
                int neighbor=neighbors[course].get(i);      //拿到邻居课程的每一个课程,List里的每一个小List里的内容
                degree[neighbor]--;                         //在邻居课程里的每一个课程的入度都要-1
                
                if(degree[neighbor]==0){                    //再判断入度-1后是否有课程满足条件:入度为0
                    queue.offer(neighbor);                  //如果满足条件,再循环检测
                }
            }
        }
        return resultNum==numCourses;                       //最后的判断很关键,检测的结果数==课程总数
    }
}

598.Zombie in Matrix :   点击打开链接

矩阵中的BFS的代表题型,而且此题是一个完整的BFS,具有三层。

class Coordinate{
    int x,y;
    public Coordinate(int x,int y){
        this.x=x;
        this.y=y;
    }
}

public class Solution {
    
    public int[] deltaX = {1, 0, 0, -1};                    //四个方向的坐标变换数组形式
    public int[] deltaY = {0, 1, -1, 0};
     
    /**
     * @param grid a 2D integer grid
     * @return an integer
     */
    public int zombie(int[][] grid) {
        if (grid == null || grid.length == 0) {
            return 0;
        }
        
        int people = 0;                                     //遍历整个matrix
        Queue<Coordinate> queue = new LinkedList<>();
        for (int i = 0; i < grid.length; i++) {
            for (int j = 0; j < grid[0].length; j++) { 
                if (grid[i][j] == 0) {                      //拿到people的个数,后面根据people==0来具体判断
                    people++;
                } else if (grid[i][j] == 1) {
                    queue.offer(new Coordinate(i, j));      //遍历过程中所有zombie的坐标放到queue里
                }
            }
        }
        
        if (people == 0) {                                  //corner case
            return 0;
        }
        
        int days = 0;                                       //每一圈(每一层),也就是一天
        while (!queue.isEmpty()){
            days++;
            int size = queue.size();
            for (int i = 0; i < size; i++){
                Coordinate zombie = queue.poll();           //对于queue里的每一个删除的zombie,都要对它的外一层判断
                for (int direction = 0; direction < 4; direction++) {
                    Coordinate neighbor = new Coordinate(   //外一层有四个点
                        zombie.x + deltaX[direction],
                        zombie.y + deltaY[direction]
                    );
                    
                    if(isPeople(neighbor, grid)){           //如果四个点中有是people的
                        grid[neighbor.x][neighbor.y] = 1;   //就会被咬成zombie
                        people--;                           //同时people的个数-1
                        if (people == 0) {                  //如果没有people了,过程就结束了,返回所需天数
                            return days;
                        }
                        queue.offer(neighbor);
                   }
                }
            }
        }       
        return -1;
    }
    
    private boolean isPeople(Coordinate coor, int[][] grid) {    
        if (coor.x < 0 || coor.x >= grid.length) {         //在遍历是不是isPeopleP过程中,要对出界的情况进行处理
            return false;
        }
        if (coor.y < 0 || coor.y >= grid[0].length) {
            return false;
        }
        return (grid[coor.x][coor.y] ==0);
    }
}

611.Knight Shortest Path :  点击打开链接

/**
 * Definition for a point.
 * public class Point {
 *     publoc int x, y;
 *     public Point() { x = 0; y = 0; }
 *     public Point(int a, int b) { x = a; y = b; }
 * }
 */
public class Solution {
    /**
     * @param grid a chessboard included 0 (false) and 1 (true)
     * @param source, destination a point
     * @return the shortest path 
     */
    public int[] deltaX={1,1,-1,-1,2,2,-2,-2};                //坐标变换数组:马走日
    public int[] deltaY={2,-2,2,-2,1,-1,1,-1};
    public int shortestPath(boolean[][] grid, Point source, Point destination) {
        if(grid==null || grid.length==0){
            return -1;
        }
        
        Queue<Point> queue=new LinkedList<>();
        queue.offer(source);
        
        int steps=0;
        while(!queue.isEmpty()){
            int size=queue.size();
            
            for(int i=0;i<size;i++){
                Point point=queue.poll();
                if(point.x==destination.x && point.y==destination.y){
                    return steps;
                }
                for(int direction=0;direction<8;direction++){
                    Point movePoint=new Point(point.x+deltaX[direction],
                                              point.y+deltaY[direction]);
                    if(isValid(grid, movePoint)){           //如果是有效点,就添加到queue
                        queue.offer(movePoint);             //因为下一轮马要从queue里poll出的点出发走下一步
                        grid[movePoint.x][movePoint.y]=true;//同时添加到queue里的点要做标记
                    }
                }
            }
            steps++;
        }
        return -1;
    }
    
    private boolean isValid(boolean[][] grid, Point point){ //拿到有效点,并赋值为false返回供部分需要点标记为true
        if (point.x < 0 || point.x >= grid.length) {        //出边界的点
            return false;
        }
        if (point.y < 0 || point.y >= grid[0].length) {   
            return false;
        }
        return grid[point.x][point.y] == false;             //其实这个函数起名有歧义
    }
}

690. Employee Importance (LeetCode)

/*
// Employee info
class Employee {
    // It's the unique id of each node;
    // unique id of this employee
    public int id;
    // the importance value of this employee
    public int importance;
    // the id of direct subordinates
    public List<Integer> subordinates;
};
*/
class Solution {
    public int getImportance(List<Employee> employees, int id) {
        
         int nImportance = 0;

         for(Employee e : employees)
         {
             if (e.id == id)
             {
                 if (e.subordinates.size()==0)
                 {
                     return e.importance;
                 }
                 
                 nImportance += e.importance;                
                 for(Integer n : e.subordinates)
                 {
                      nImportance += getImportance(employees, n);
                 }
             }
         }
        
        return nImportance;

    }
}
/*
// Employee info
class Employee {
    // It's the unique id of each node;
    // unique id of this employee
    public int id;
    // the importance value of this employee
    public int importance;
    // the id of direct subordinates
    public List<Integer> subordinates;
};
*/
class Solution {
    public int getImportance(List<Employee> employees, int id) {
        
        int nImportance = 0;
        
        // <Id, Employee>
        Map<Integer, Employee> map = new HashMap<>();  //map的设计很到位          
        for(Employee e : employees)      
        {
            map.put(e.id, e);
        }
          
        Queue<Integer> queue = new LinkedList<>();
        queue.offer(id);
        
        while(!queue.isEmpty())
        {
            Employee e = map.get(queue.poll());        //queue与map的精妙结合
            nImportance += e.importance;
            
            List<Integer> subordinates = e.subordinates;
            for(Integer sub : subordinates)
            {
                queue.offer(sub);
            }            
        }
        
        return nImportance;
    }
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值