教你如何迅速秒杀掉:99%的海量数据处理面试题

我是慕小白, 一个专注前端/Java/Python/大数据/人工智能资源分享的技术人,我会在群里不定期免费分享一些资源,资源包括各种VIP教程(我会严格审核质量),以及书籍和优质文章。目前群是免费加入,后面会考虑会加收一点钱,当做群运营费用,用户买资料以及发红包给那些活跃的人。

程序员资源交流2群(加群需注明来意,最好可以注明自己的CSDN账号,否则不会允许加入):135948728

前言
一般而言,标题含有“秒杀”,“99%”,“史上最全/最强”等词汇的往往都脱不了
哗众取宠之嫌,但进一步来讲,如果读者读罢此文,却无任何收获,那么,我也
甘愿背负这样的罪名,:-),同时,此文可以看做是对这篇文章:十道海量数据处理
面试题与十个方法大总结的一般抽象性总结。
毕竟受文章和理论之限,本文将摒弃绝大部分的细节,只谈方法/模式论,且
注重用最通俗最直白的语言阐述相关问题。最后,有一点必须强调的是,全文行
文是基 于面试题的分析基础之上的,具体实践过程中,还是得具体情况具体分
析,且场景也远比本文所述的任何一种情况复杂得多。
OK,若有任何问题,欢迎随时不吝赐教。谢谢。
何谓海量数据处理?
所谓海量数据处理,无非就是基于海量数据上的存储、处理、操作。何谓海量,
就是数据量太大,所以导致要么是无法在较短时间内迅速解决,要么是数据太大,
导致无法一次性装入内存。
那解决办法呢?针对时间,我们可以采用巧妙的算法搭配合适的数据结构,如
Bloom filter/Hash/bit-map/堆/数据库或倒排索引/trie 树,针对空间,无非就一个
办法:大而化小:分而治之/hash 映射,你不是说规模太大嘛,那简单啊,就把
规模大化为规模小的,各个击破不就完了嘛。
至于所谓的单机及集群问题,通俗点来讲,单机就是处理装载数据的机器有
限(只要考虑 cpu,内存,硬盘的数据交互),而集群,机器有多辆,适合分布式
处理,并行计算(更多考虑节点和节点间的数据交互)。
再者,通过本 blog 内的有关海量数据处理的文章:Big Data Processing,我
们已经大致知道,处理海量数据问题,无非就是:
1. 分而治之/hash 映射 + hash 统计 + 堆/快速/归并排序;
2. 双层桶划分
3. Bloom filter/Bitmap;
4. Trie 树/数据库/倒排索引;
5. 外排序;
6. 分布式处理之 Hadoop/Mapreduce。
下面,本文第一部分、从 set/map 谈到 hashtable/hash_map/hash_set,简
要介绍下 set/map/multiset/multimap,及
hash_set/hash_map/hash_multiset/hash_multimap 之区别(万丈高楼平地起,基
础最重要),而本文第二部分,则针对上述那 6 种方法模式结合对应的海量数据
处理面试题分别具体阐述。
第一部分、从 set/map 谈到 hashtable/hash_map/hash_set
稍后本文第二部分中将多次提到 hash_map/hash_set,下面稍稍介绍下这些容器,以作
为基础准备。一般来说,STL 容器分两种,
 序列式容器(vector/list/deque/stack/queue/heap),
 关 联式容器。关联式容器又分为 set(集合)和 map(映射表)两大类,以及这两大类的
衍生体 multiset(多键集合)和 multimap(多键映射 表),这些容器均以 RB-tree 完成。
此外,还有第 3 类关联式容器,如 hashtable(散列表),以及以 hashtable 为底层机
制完成的 hash_set(散列集合)/hash_map(散列映射表)/hash_multiset(散列多键集
合)/hash_multimap(散列多键映 射表)。也就是说,set/map/multiset/multimap 都内
含一个 RB-tree,而 hash_set/hash_map/hash_multiset/hash_multimap 都内含一
个 hashtable。
所谓关联式容器,类似关联式数据库,每笔数据或每个元素都有一个键值(key)
和一个实值(value),即所谓的 Key-Value(键-值对)。当元 素被插入到关联式容
器中时,容器内部结构(RB-tree/hashtable)便依照其键值大小,以某种特定规则
将这个元素放置于适当位置。
包括在非关联式数据库中,比如,在 MongoDB 内,文档(document)是最基
本的数据组织形式,每个文档也是以 Key-Value(键-值对)的方式组织起来。
一个文档可以有多个Key-Value 组合,每个Value 可以是不同的类型,比如String、
Integer、List 等等。
{ “name” : “July”,
“sex” : “male”,
“age” : 23 }
set/map/multiset/multimap
set,同 map 一样,所有元素都会根据元素的键值自动被排序,因为 set/map
两者的所有各种操作,都只是转而调用 RB-tree 的操作行为,不过,值得注意的
是,两者都不允许两个元素有相同的键值。
不同的是:set 的元素不像 map 那样可以同时拥有实值(value)和键值(key),
set 元素的键值就是实值,实值就是键值,而 map 的所有元素都 是 pair,同时
拥有实值(value)和键值(key),pair 的第一个元素被视为键值,第二个元素被视
为实值。
至于 multiset/multimap,他们的特性及用法和 set/map 完全相同,唯一的差
别就在于它们允许键值重复,即所有的插入操作基于 RB-tree 的 insert_equal()
而非 insert_unique()。
hash_set/hash_map/hash_multiset/hash_multimap
hash_set/hash_map,两者的一切操作都是基于 hashtable 之上。不同的是,
hash_set 同 set 一样,同时拥有实值和键值,且 实质就是键值,键值就是实值,
而 hash_map 同 map 一样,每一个元素同时拥有一个实值(value)和一个键值
(key),所以其使用方式,和上面 的 map 基本相同。但由于 hash_set/hash_map
都是基于 hashtable 之上,所以不具备自动排序功能。为什么?因为 hashtable 没
有自动排序功能。
至于 hash_multiset/hash_multimap 的特性与上面的 multiset/multimap 完全
相同,唯一的差别就是它们 hash_multiset/hash_multimap 的底层实现机制是
hashtable(而 multiset/multimap,上面说了,底层实 现机制是 RB-tree),所以
它们的元素都不会被自动排序,不过也都允许键值重复。
所以,综上,说白了,什么样的结构决定其什么样的性质,因为
set/map/multiset/multimap 都是基于 RB-tree 之上,所以有自动排序功能,而
hash_set/hash_map/hash_multiset/hash_multimap 都是基于 hashtable 之上,
所以不含有自动排序功能,至于加个前缀 multi_无非就是允许键值重复而已。
此外,
 关于什么 hash,请看 blog 内此篇文章:
http://blog.csdn.net/v_JULY_v/article/details/6256463
 关于红黑树,请参看 blog 内系列文章:
http://blog.csdn.net/v_july_v/article/category/774945
 关于hash_map的具体应用:http://blog.csdn.net/sdhongjun/article/details/4517325
关于 hash_set:http://blog.csdn.net/morewindows/article/details/7330323
OK,接下来,请看本文第二部分、处理海量数据问题之六把密匙。
第二部分、处理海量数据问题之六把密匙
密匙一、分而治之/Hash 映射 + Hash 统计 + 堆/快速/归并排序
1、海量日志数据,提取出某日访问百度次数最多的那个 IP。
既然是海量数据处理,那么可想而知,给我们的数据那就一定是海量的。针对这个数据
的海量,我们如何着手呢?对的,无非就是分而治之/hash 映射 + hash 统计 + 堆/快速/归
并排序,说白了,就是先映射,而后统计,最后排序:
1. 分而治之/hash 映射:针对数据太大,内存受限,只能是:把大文件化成(取模映射)
小文件,即 16 字方针:大而化小,各个击破,缩小规模,逐个解决
2. hash统计:当大文件转化了小文件,那么我们便可以采用常规的hash_map(ip,value)
来进行频率统计。
3. 堆/快速排序:统计完了之后,便进行排序(可采取堆排序),得到次数最多的 IP。
具体而论,则是: “首先是这一天,并且是访问百度的日志中的 IP 取出来,逐个写入到一个大文件中。
注意到 IP 是 32 位的,最多有个 2^32 个 IP。同样可以采用映射的方 法,比如模 1000,把整个大文件映
射为 1000 个小文件,再找出每个小文中出现频率最大的 IP(可以采用 hash_map 对那 1000 个文件中的
所有 IP 进行频率统计,然后依次找出各个文件中频率最大的那个 IP)及相应的频率。然后再在这 1000
个最大的 IP 中,找出那个频率最大的 IP,即为所 求。”–十道海量数据处理面试题与十个方法大总
结。
关于本题,还有几个问题,如下:
1、Hash 取模是一种等价映射,不会存在同一个元素分散到不同小文件中
去的情况,即这里采用的是 mod1000 算法,那么相同的 IP 在 hash 后,只可能
落在同一个文件中,不可能被分散的。
2、那到底什么是 hash 映射呢?简单来说,就是为了便于计算机在有限的
内存中处理 big 数据,从而通过一种映射散列的方式让数据均匀分布在对应的内
存位 置(如大数据通过取余的方式映射成小树存放在内存中,或大文件映射成多
个小文件),而这个映射散列方式便是我们通常所说的 hash 函数,设计的好的
hash 函数能让数据均匀分布而减少冲突。尽管数据映射到了另外一些不同的位
置,但数据还是原来的数据,只是代替和表示这些原始数据的形式发生了变化而
已。
此外,有一朋友 quicktest 用 python 语言实践测试了下本题,地址如下:
http://blog.csdn.net/quicktest/article/details/7453189。谢谢。OK,有兴趣的,还可以再了解
下一致性 hash 算法,见 blog 内此文第五部分:
http://blog.csdn.net/v_july_v/article/details/6879101
2、寻找热门查询,300 万个查询字符串中统计最热门的 10 个查询
原题:搜索引擎会通过日志文件把用户每次检索使用的所有检索串都记录下
来,每个查询串的长度为 1-255 字节。假设目前有一千万个记录(这些查询串的重
复度比较高,虽然总数是 1 千万,但如果除去重复后,不超过 3 百万个。一个查询串的重复度越高,说明
查询它的用户越多,也就是越热门),请你统计最热门的 10 个查询串,要求使用的内存
不能超过 1G。
解答:由上面第 1 题,我们知道,数据大则划为小的,但如果数据规模比较
小,能一次性装入内存呢?比如这第 2 题,虽然有一千万个 Query,但是由于重
复度比较高,因此事实上只有 300 万的 Query,每个 Query255Byte,因此我们
可以考虑把他们都放进内存中去(300 万个字符串假设没有重复,都是最大长度,那么最多占
用内存 3M*1K/4=0.75G。所以可以将所有字符串都存放在内存中进行处理),而现在只是需要一
个合适的数据结构,在这里,HashTable 绝对是我们优先的选择。
所以我们放弃分而治之/hash 映射的步骤,直接上 hash 统计,然后排序。So,
针对此类典型的 TOP K 问题,采取的对策往往是:hashmap + 堆。如下所示:
1. hash 统计:先对这批海量数据预处理。具体方法是:维护一个 Key 为 Query 字串,
Value 为该 Query 出现次数的 HashTable,即 hash_map(Query,Value),每次读
取一个 Query,如果该字串不在 Table 中,那么加入该字串,并且将 Value 值设为 1;
如果该 字串在 Table 中,那么将该字串的计数加一即可。最终我们在 O(N)的时间
复杂度内用 Hash 表完成了统计;
2. 堆排序:第二步、借助堆 这个数据结构,找出 Top K,时间复杂度为 N„logK。即借
助堆结构,我们可以在 log 量级的时间内查找和调整/移动。因此,维护一个 K(该题
目中是 10)大小的小根堆,然后遍 历 300 万的 Query,分别和根元素进行对比。所
以,我们最终的时间复杂度是:O(N) + N’ * O(logK),(N 为 1000 万,N‟为 300
万)。
别忘了这篇文章中所述的堆排序思路:“维护 k 个元素的最小堆,即用容量为
k 的最小堆存储最先遍历到的 k 个数,并假设它们即是最大的 k 个数,建堆费时
O(k),并调整堆(费时 O(logk))后,有 k1>k2>…kmin(kmin 设为小顶堆中最小
元素)。继续遍历数列,每次遍历一个元素 x,与堆顶元素比较,若 x>kmin,
则更新堆(x 入堆,用时 logk),否则不更新堆。这样下来,总费时 O(k*logk+(n-k)*logk)=O(n*logk)。
此方法得益于在堆中,查找等各项操作时间复杂度均为 logk。”–第三章续、Top K 算法问题的实现。
当然,你也可以采用 trie 树,关键字域存该查询串出现的次数,没有出现为 0。
最后用 10 个元素的最小推来对出现频率进行排序。
3、有一个 1G 大小的一个文件,里面每一行是一个词,词的大小不超过 16 字
节,内存限制大小是 1M。返回频数最高的 100 个词。
由上面那两个例题,分而治之 + hash 统计 + 堆/快速排序这个套路,我
们已经开始有了屡试不爽的感觉。下面,再拿几道再多多验证下。请看此第 3
题:又是文件很大,又是内存受限,咋办?还能怎么办呢?无非还是:
1. 分 而治之/hash 映射:顺序读文件中,对于每个词 x,取 hash(x)%5000,然后按
照该值存到 5000 个小文件(记为 x0,x1,…x4999)中。这样每个文件大概是 200k
左右。如果其中的有的文件超过了 1M 大小,还可以按照类似的方法继续往下分,
直到分解得到 的小文件的大小都不超过 1M。
2. hash 统计:对每个小文件,采用 trie 树/hash_map 等统计每个文件中出现的词以及
相应的频率。
3. 堆/归并排序:取出出现频率最大的 100 个词(可以用含 100 个结点的最小堆)后,
再把 100 个词及相应的频率存入文件,这样又得到了 5000 个文件。最后就是把这
5000 个文件进行归并(类似于归并排序)的过程了。
4、海量数据分布在 100 台电脑中,想个办法高效统计出这批数据的 TOP10。
此题与上面第 3 题类似,
1. 堆排序:在每台电脑上求出 TOP10,可以采用包含 10 个元素的堆完成(TOP10 小,
用最大堆,TOP10 大,用最小堆)。比如求 TOP10 大,我们首先取前 10 个元素调整成最
小堆,如果发现,然后扫描后面的数据,并与堆顶元素比较,如果比堆顶元素大,那么用该元素
替换堆顶,然后再调整为最小堆。最后堆中的元素就是 TOP10 大。
2. 求出每台电脑上的 TOP10 后,然后把这 100 台电脑上的 TOP10 组合起来,共 1000
个数据,再利用上面类似的方法求出 TOP10 就可以了。
上述第 4 题的此解法,经读者反应有问题,如举个例子如求 2 个文件中的 top2,照上述
算法,如果第一个文件里有:
a 49 次
b 50 次
c 2 次
d 1 次
第二个文件里有:
a 9 次
b 1 次
c 11 次
d 10 次
虽然第 一个文件里出来 top2 是 b(50 次),a(49 次),第二个文件里出来 top2 是 c(11 次),d(10
次),然后 2 个 top2:b(50 次)a(49 次)与 c(11 次)d(10 次)归并,则算出所有的文件的 top2 是
b(50 次),a(49 次),但实际上是 a(58 次),b(51 次)。是否真是如此呢?若真如此,那作何解决呢?
正如老梦所述:
首先,先把所有的数据遍历一遍做一次 hash(保证相同的数据条目划分到同一台电脑上
进行运算),然后根据 hash 结果重新分布到 100 台电脑中,接下来的算法按照之前的即可。
最后由于 a 可能出现在不同的电脑,各有一定的次数,再对每个相同条目进行求和(由
于上一步骤中 hash 之后,也方便每台电脑只需要对自己分到的条目内进行求和,不涉及到
别的电脑,规模缩小)。
5、有 10 个文件,每个文件 1G,每个文件的每一行存放的都是用户的 query,每个文件的
query 都可能重复。要求你按照 query 的频度排序。
方案 1:直接上:
1. hash 映射:顺序读取 10 个文件,按照 hash(query)%10 的结果将 query 写入到另
外 10 个文件(记为 a0,a1,..a9)中。这样新生成的文件每个的大小大约也 1G(假
设 hash 函数是随机的)。
2. hash 统计:找一台内存在 2G 左右的机器,依次对用 hash_map(query, query_count)
来统计每个 query 出现的次数。注:hash_map(query,query_count)是用来统计每个 query
的出现次数,不是存储他们的值,出现一次,则 count+1。
3. 堆/快速/归并排序:利用快速/堆/归并排序按照出现次数进行排序,将排序好的 query
和对应的 query_cout 输出到文件中,这样得到了 10 个排好序的文件(记为
)。最后,对这 10 个文件进行归并排序(内排序与外排序相结合)。根
据此方案 1,这里有一份实现:
https://github.com/ooooola/sortquery/blob/master/querysort.py
除此之外,此题还有以下两个方法:
方案2:一般query的总量是有限的,只是重复的次数比较多而已,可能对于所有的query,
一次性就可以加入到内存了。这样,我们就可以采用 trie 树/hash_map 等直接来统计每个
query 出现的次数,然后按出现次数做快速/堆/归并排序就可以了。
方案 3:与方案 1 类似,但在做完 hash,分成多个文件后,可以交给多个文
件来处理,采用分布式的架构来处理(比如 MapReduce),最后再进行合并。
6、 给定 a、b 两个文件,各存放 50 亿个 url,每个 url 各占 64 字节,内存限
制是 4G,让你找出 a、b 文件共同的 url?
可以估计每个文件安的大小为 5G×64=320G,远远大于内存限制的 4G。所
以不可能将其完全加载到内存中处理。考虑采取分而治之的方法。
1. 分而治之/hash 映射:遍历文件 a,对每个 url 求取 ,然后根据所
取得的值将 url 分别存储到 1000 个小文件(记为 ,这里漏写个了 a1)
中。这样每个小文件的大约为 300M。遍历文件 b,采取和 a 相同的方式将 url 分别
存储到 1000 小文件中(记为 )。这样处理后,所有可能相同的 url 都
在对应的小文件( )中,不对应的小文件不可能有相
同的 url。然后我们只要求出 1000 对小文件中相同的 url 即可。
2. hash 统计:求每对小文件中相同的 url 时,可以把其中一个小文件的 url 存储到
hash_set 中。然后遍历另一个小文件的每个 url,看其是否在刚才构建的 hash_set
中,如果是,那么就是共同的 url,存到文件里面就可以了。
OK,此第一种方法:分而治之/hash 映射 + hash 统计 + 堆/快速/归并排序,
再看最后 4 道题,如下:
7、怎么在海量数据中找出重复次数最多的一个?
方案 1:先做 hash,然后求模映射为小文件,求出每个小文件中重复次数最
多的一个,并记录重复次数。然后找出上一步求出的数据中重复次数最多的一个
就是所求(具体参考前面的题)。
8、上千万或上亿数据(有重复),统计其中出现次数最多的钱 N 个数据。
方案 1:上千万或上亿的数据,现在的机器的内存应该能存下。所以考虑采
用 hash_map/搜索二叉树/红黑树等来进行统计次数。然后就是取出前 N 个出现
次数最多的数据了,可以用第 2 题提到的堆机制完成。
9、一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的
前 10 个词,请给出思想,给出时间复杂度分析。
方案 1:这题是考虑时间效率。用 trie 树统计每个词出现的次数,时间复杂
度是 O(n*le)(le 表示单词的平准长度)。然后是找出出现最频繁的前 10 个词,
可以用堆来实现,前面的题中已经讲到了,时间复杂度是 O(n*lg10)。所以总的
时间复杂度,是 O(n*le)与 O(n*lg10)中较大的 哪一个。
10. 1000 万字符串,其中有些是重复的,需要把重复的全部去掉,保留没有重复的字符串。
请怎么设计和实现?
 方案 1:这题用 trie 树比较合适,hash_map 也行。
 方案 2:from xjbzju:,1000w 的数据规模插入操作完全不现实,以前试过在 stl 下
100w 元素插入 set 中已经慢得不能忍受,觉得基于 hash 的实现不会比红黑树好太
多,使用 vector+sort+unique 都要可行许多,建议还是先 hash 成小文件分开处理
再综合。
上 述 方 案 2 中读者 xbzju 的 方 法 让 我 想 到 了 一 些 问 题 , 即 是 set/map , 与
hash_set/hash_map 的性能比较?共计 3 个问题,如下:
 1、hash_set 在千万级数据下,insert 操作优于 set? 这位 blog:http://t.cn/zOibP7t
给的实践数据可靠不?
 2、那 map 和 hash_map 的性能比较呢? 谁做过相关实验?
 3、那查询操作呢,如下段文字所述?
或者小数据量时用 map,构造快,大数据量时用 hash_map?
rbtree PK hashtable
据朋友№邦卡猫№的做的红黑树和 hash table 的性能测试中发现:当数据量
基本上 int 型 key 时,hash table 是 rbtree 的 3-4 倍,但 hash table 一般会浪费
大概一半内存。
因为 hash table 所做的运算就是个%,而 rbtree 要比较很多,比如 rbtree 要
看 value 的数据 ,每个节点要多出 3 个指针(或者偏移量)如果需要其他功能,
比如,统计某个范围内的 key 的数量,就需要加一个计数成员。
且 1s rbtree 能进行大概 50w+次插入,hash table 大概是差不多 200w 次。不过很多的
时候,其速度可以忍了,例如倒排索引差不多也是 这个速度,而且单线程,且倒排表的拉
链长度不会太大。正因为基于树的实现其实不比 hashtable 慢到哪里去,所以数据库的索引
一般都是用的 B/B+树,而且 B+树还对磁盘友好(B 树能有效降低它的高度,所以减少磁盘
交互次数)。比如现在非常流行的 NoSQL 数据库,像 MongoDB 也是采用的 B 树索引。关
于 B 树系列,请参考本 blog 内此篇文章:从 B 树、B+树、B*树谈到 R 树。
OK,更多请待后续实验论证。接下来,咱们来看第二种方法,双层捅划分。
密匙二、双层桶划分
双层桶划分—-其实本质上还是分而治之的思想,重在“分”的技巧上!
适用范围:第 k 大,中位数,不重复或重复的数字
基本原理及要点:因为元素范围很大,不能利用直接寻址表,所以通过多次
划分,逐步确定范围,然后最后在一个可以接受的范围内进行。可以通过多次缩
小,双层只是一个例子。
扩展:
问题实例:
11、2.5 亿个整数中找出不重复的整数的个数,内存空间不足以容纳这 2.5 亿个
整数。
有点像鸽巢原理,整数个数为 2^32,也就是,我们可以将这 2^32 个数,划
分为 2^8 个区域(比如用单个文件代表一个区域),然后将数据分离到不同的区域,
然后不同的区域在利用 bitmap 就可以直接解决了。也就是说只要有足够的磁盘
空间,就可以很方便的解决。
12、5 亿个 int 找它们的中位数。
1. 思 路一:这个例子比上面那个更明显。首先我们将 int 划分为 2^16 个区域,然后
读取数据统计落到各个区域里的数的个数,之后我们根据统计结果就可以判断中 位
数落到那个区域,同时知道这个区域中的第几大数刚好是中位数。然后第二次扫描
我们只统计落在这个区域中的那些数就可以了。
实 际上,如果不是 int 是 int64,我们可以经过 3 次这样的划分即可降低到可以接
受的程度。即可以先将 int64 分成 2^24 个区域,然后确定区域的第几 大数,在将
该区域分成 2^20 个子区域,然后确定是子区域的第几大数,然后子区域里的数的
个数只有 2^20,就可以直接利用 direct addr table 进行统计了。
2. 思路二@绿色夹克衫:同样需要做两遍统计,如果数据存在硬盘上,就需要读
取 2 次。
方 法同基数排序有些像,开一个大小为 65536 的 Int 数组,第一遍读取,统计 Int32
的高 16 位的情况,也就是 0-65535,都算作 0,65536 - 131071 都算作 1。就相当
于用该数除以 65536。Int32 除以 65536 的结果不会超过 65536 种情况,因此开一
个长度为 65536 的数组计数就可以。每读取一个数,数组中对应的计数+1,考虑有
负数的情况,需要 将结果加 32768 后,记录在相应的数组内。
第一遍统计之后,遍 历数组,逐个累加统计,看中位数处于哪个区间,比如处于
区间 k,那么 0- k-1 的区间里数字的数量 sum 应该

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值