百度2012-笔试面试题目汇总

从互联网来,返回之!

//csdn博客目前暂时不再更新了,有兴趣请访问我的技术博客-晓的博客:zhangxiaolong.org 

研发

1.第一大题要求用二分查找在一个序列里查找一个key。这题实际包含两个小题。第一个小题它给出的函数原型是:
int f1(int* array,int size,int key);
具体要求大概是:array是个有序序列,要求用二分查找找出指定的key,如果key在序列中,返回序列的位置,如果key不在序列中,则返回key应当被插入的位置。
第二小题给出的原型也是一样:
int f2(int* array,int size,int key);
不过要求却不同。array是个先增后减的序列,临界值mid的位置是不确定的。同样的要求查找指定的key,如果key在序列中,则返回key的位置,如果不在,则直接返回-1(不必指出key应当插入的位置)。

2. 第二大题考的是“左孩子右兄弟”的树结构,具体要求记不清了,大概是这棵树共右N个结点,在v和m之间….之类的。
第三道大题考的是系统设计题。大概是有一批老数据要导入到新的机器上,这批数据是大小相当的总数为10万个的二进制文件,导入时间与文件大小成线性关系, 一个500K的文件需要3秒的导入时间,文件的平均大小是1000K。用以转换函数也已经有,不过这些函数存在不少问题,譬如会产生数组越界等等,然后时 间又不允许你重写一套函数…,然后就要你设计一个方案来实现…大概就是问的这个方向,要你用文字表述清楚你的方案。

1 简要说明树的深度优先、广度优先遍历算法挤特点
2 一个复数相加的编码挑错题
3 告诉内存大小和cpu速度,计算可能的程序运行最长时间
4 复杂项目的组件编译依赖,设计一个快速算法并计算复杂度

5 写个c程序,返回字符串中最长数字字符串的长度和地址,不能用标准库函数
6 设计个系统,存储100亿个url和属性信息,并可以更改属性信息和查找url,快速搜索站点的所有url及信息


算法

第一题:某个公司举行一场羽毛球赛,有1001个人参加,现在为了评比出“最厉害的那个人”,进行淘汰赛,请问至少需要进行多少次比赛。
第二题:一百个灯泡排成一排,第一轮将所有灯泡打开;第二轮每隔一个灯泡关掉一个。即排在偶数的灯泡被关掉,第三轮每隔两个灯泡,将开着的灯泡关掉,关掉的灯泡打开。依次类推,第n轮结束的时候,还有几盏灯泡亮着。
第三题:有20个数组,每个数组里面有500个数组,降序排列,每个数字是32位的unit,求出这10000个数字中最大的500个


其他:

1、实现一个函数,对一个正整数n,算得到1需要的最少操作次数。操作规则为:如果n为偶数,将其除以2;如果n为奇数,可以加1或减1;一直处理下去。
例子:
func(7) = 4,可以证明最少需要4次运算
n = 7
n-1 6
n/2 3
n-1 2
n/2 1
要求:实现函数(实现尽可能高效)> · return 0;
·> · return 1 + func(n/2);
·> · int y = func(n – 1);
· if(x > y)
· return y+1;
· else
· return x+1;
· }

假设n表示成二进制有x bit,可以看出计算复杂度为O(2^x),也就是O(n)。
将n转换到二进制空间来看(比如7为111,6为110):
- 如果最后一位是0,则对应于偶数,直接进行除2操作。
- 如果最后一位是1,情况则有些复杂。
**如果最后几位是???01,则有可能为???001,???1111101。在第一种情况下,显然应该-1;在第二种情况下-1和+1最终需要的步数相同。所以在???01的情况下,应该选择-1操作。
**如果最后几位是???011,则有可能为???0011,???11111011。在第一种情况下,+1和-1最终需要的步数相同;在第二种情况下+1步数更少些。所以在???011的情况下,应该选择+1操作。
**如果最后有更多的连续1,也应该选择+1操作。
如果最后剩下的各位都是1,则有11时应该选择-1;111时+1和-1相同;1111时应选择+1;大于四个1时也应该选择+1;
·> · return 0;
·> · return 1 + func(n/2);
·> · return 2;
· if(n&2)
· return 1 + func(n+1);
· else
· return 1 + func(n-1);
· }

2、找到满足条件的数组
给定函数d(n)=n+n的各位之和,n为正整数,如d(78)=78+7+8=93。这样这个函数可以看成一个生成器,如93可以看成由78生成。
定义数A:数A找不到一个数B可以由d(B)=A,即A不能由其他数生成。现在要写程序,找出1至10000里的所有符合数A定义的数。
回答:
申请一个长度为10000的bool数组,每个元素代表对应的值是否可以有其它数生成。开始时将数组中的值都初始化为false。
由于大于10000的数的生成数必定大于10000,所以我们只需遍历1到10000中的数,计算生成数,并将bool数组中对应的值设置为true,表示这个数可以有其它数生成。
最后bool数组中值为false的位置对应的整数就是不能由其它数生成的。
3、一个大的含有50M个URL的记录,一个小的含有500个URL的记录,找出两个记录里相同的URL。
回答:
首先使用包含500个url的文件创建一个hash_set。
然后遍历50M的url记录,如果url在hash_set中,则输出此url并从hash_set中删除这个url。
所有输出的url就是两个记录里相同的url。
4、海量日志数据,提取出某日访问百度次数最多的那个IP。
回答:
IP地址最多有2^32=4G种取值可能,所以不能完全加载到内存中。
可以考虑分而治之的策略,按照IP地址的hash(IP)%1024值,将海量日志存储到1024个小文件中。每个小文件最多包含4M个IP地址。
对于每个小文件,可以构建一个IP作为key,出现次数作为value的hash_map,并记录当前出现次数最多的1个IP地址。
有了1024个小文件中的出现次数最多的IP,我们就可以轻松得到总体上出现次数最多的IP。
5、有10个文件,每个文件1G,每个文件的每一行都存放的是用户的query,每个文件的query都可能重复。如何按照query的频度排序?
回答:
1)读取10个文件,按照hash(query)%10的结果将query写到对应的文件中。这样我们就有了10个大小约为1G的文件。任意一个query只会出现在某个文件中。
2)对于1)中获得的10个文件,分别进行如下操作
-利用hash_map(query,query_count)来统计每个query出现的次数。
-利用堆排序算法对query按照出现次数进行排序。
-将排序好的query输出的文件中。
这样我们就获得了10个文件,每个文件中都是按频率排序好的query。
3)对2)中获得的10个文件进行归并排序,并将最终结果输出到文件中。
6、蚂蚁爬杆问题
有一根27厘米长的细木杆,在第3厘米,7厘米,11厘米,17厘米,23厘米这五个位置上各有一只蚂蚁,木杆很细,不能同时通过两只蚂蚁,开始时,蚂蚁的头朝向左还是右是任意的,他们只会朝前走或掉头,但不会后退,当两只蚂蚁相遇后,蚂蚁会同时掉头朝反方向走,假设蚂蚁们每秒钟可以走1厘米的距离。求所有蚂蚁都离开木杆的最小时间和最大时间。
答案:
两只蚂蚁相遇后,各自掉头朝相反方向走。如果我们不考虑每个蚂蚁的具体身份,这和两只蚂蚁相遇后,打个招呼继续向前走没有什么区别。
所有蚂蚁都离开木杆的最小时间为
max(min(3,27-3),min(7,27-7),> 所有蚂蚁都离开木杆的最大时间为
max(max(3,27-3),max(7,27-7),> 7、当在浏览器中输入一个url后回车,后台发生了什么?比如输入url后,你看到了百度的首页,那么这一切是如何发生的呢?
回答:
简单来说有以下步骤:
1、查找域名对应的IP地址。这一步会依次查找浏览器缓存,系统缓存,路由器缓存,ISPDNS缓存,根域名服务器。
2、向IP对应的服务器发送请求。
3、服务器响应请求,发回网页内容。
4、浏览器解析网页内容。
当然,由于网页可能有重定向,或者嵌入了图片,AJAX,其它子网页等等,这4个步骤可能反复进行多次才能将最终页面展示给用户。
8、判断两棵树是否相等,请实现两棵树是否相等的比较,相等返回1,否则返回其他值,并说明算法复杂度。
数据结构为:
[cpp]
·> 递归方法:
[cpp]
·> · return true;
·> · return false;
·> · return false;
· if( (CompTree(tree1->leftchild, tree2->leftchild) && CompTree(tree1->rightchild, tree2->rightchild)) || CompTree(tree1->leftchild, tree2->rightchild) && CompTree(tree1->rightchild, tree2->leftchild))
· return true;
· }

时间复杂度:
在树的第0层,有1个节点,我们会进行1次函数调用;
在树的第1层,有2个节点,我们可能会进行4次函数调用;
在树的第2层,有4个节点,我们可能会进行16次函数调用;
….
在树的第x层,有2^x个节点,我们可能会进行(2^x)^2次函数调用;
所以假设总节点数为n,则算法的复杂度为O(n^2)。
腾讯面试题:求一个论坛的在线人数,假设有一个论坛,其注册ID有两亿个,每个ID从登陆到退出会向一个日志文件中记下登陆时间和退出时间,要求写一个算法统计一天中论坛的用户在线分布,取样粒度为秒。
回答:
一天总共有3600*24=86400秒。
定义一个长度为86400的整数数组intdelta[86400],每个整数对应这一秒的人数变化值,可能为正也可能为负。开始时将数组元素都初始化为0。
然后依次读入每个用户的登录时间和退出时间,将与登录时间对应的整数值加1,将与退出时间对应的整数值减1。
这样处理一遍后数组中存储了每秒中的人数变化情况。
定义另外一个长度为86400的整数数组intonline_num[86400],每个整数对应这一秒的论坛在线人数。
假设一天开始时论坛在线人数为0,则第1秒的人数online_num[0]=delta[0]。第n+1秒的人数online_num[n]=online_num[n-1]+delta[n]。
这样我们就获得了一天中任意时间的在线人数。
9、三个警察和三个囚徒的过河问题
三个警察和三个囚徒共同旅行。一条河挡住了去路,河边有一条船,但是每次只能载2人。存在如下的危险:无论在河的哪边,当囚徒人数多于警察的人数时,将有警察被囚徒杀死。问题:请问如何确定渡河方案,才能保证6人安全无损的过河。
回答:警察囚徒过去,警察回来
囚徒囚徒过去,囚徒回来
警察警察过去,警察囚徒回来
警察警察过去,囚徒回来
囚徒囚徒过去,囚徒回来
囚徒囚徒过去
10、从300万字符串中找到最热门的10条
搜索的输入信息是一个字符串,统计300万输入信息中的最热门的前10条,我们每次输入的一个字符串为不超过255byte,内存使用只有1G。请描述思想,写出算法(c语言),空间和时间复杂度。
答案:
300万个字符串最多(假设没有重复,都是最大长度)占用内存3M*1K/4=0.75G。所以可以将所有字符串都存放在内存中进行处理。
可以使用key为字符串(事实上是字符串的hash值),值为字符串出现次数的hash来统计每个每个字符串出现的次数。并用一个长度为10的数组/链表来存储目前出现次数最多的10个字符串。
这样空间和时间的复杂度都是O(n)。
11、如何找出字典中的兄弟单词。给定一个单词a,如果通过交换单词中字母的顺序可以得到另外的单词b,那么定义b是a的兄弟单词。现在给定一个字典,用户输入一个单词,如何根据字典找出这个单词有多少个兄弟单词?
答案:
使用hash_map和链表。
首先定义一个key,使得兄弟单词有相同的key,不是兄弟的单词有不同的key。例如,将单词按字母从小到大重新排序后作为其key,比如bad的key为abd,good的key为dgoo。
使用链表将所有兄弟单词串在一起,hash_map的key为单词的key,value为链表的起始地址。
开始时,先遍历字典,将每个单词都按照key加入到对应的链表当中。当需要找兄弟单词时,只需求取这个单词的key,然后到hash_map中找到对应的链表即可。
这样创建hash_map时时间复杂度为O(n),查找兄弟单词时时间复杂度是O(1)。
12、找出数组中出现次数超过一半的数,现在有一个数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数。
答案1:
创建一个hash_map,key为数组中的数,value为此数出现的次数。遍历一遍数组,用hash_map统计每个数出现的次数,并用两个值存储目前出现次数最多的数和对应出现的次数。
这样可以做到O(n)的时间复杂度和O(n)的空间复杂度,满足题目的要求。
但是没有利用“一个数出现的次数超过了一半”这个特点。也许算法还有提高的空间。
答案2:
使用两个变量A和B,其中A存储某个数组中的数,B用来计数。开始时将B初始化为0。
遍历数组,如果B=0,则令A等于当前数,令B等于1;如果当前数与A相同,则B=B+1;如果当前数与A不同,则令B=B-1。遍历结束时,A中的数就是要找的数。
这个算法的时间复杂度是O(n),空间复杂度为O(1)。
13、找出被修改过的数字
n个空间(其中n<1M),存放a到a+n-1的数,位置随机且数字不重复,a为正且未知。现在第一个空间的数被误设置为-1。已经知道被修改的数不是最小的。请找出被修改的数字是多少。
例如:n=6,a=2,原始的串为5,3,7,6,2,4。现在被别人修改为-1,3,7,6,2,4。现在希望找到5。
回答:
由于修改的数不是最小的,所以遍历第二个空间到最后一个空间可以得到a的值。
a到a+n-1这n个数的和是total=na+(n-1)n/2。
将第二个至最后一个空间的数累加获得sub_total。
那么被修改的数就是total-sub_total。
14、设计DNS服务器中cache的数据结构。
要求设计一个DNS的Cache结构,要求能够满足每秒5000以上的查询,满足IP数据的快速插入,查询的速度要快。(题目还给出了一系列的数据,比如:站点数总共为5000万,IP地址有1000万,等等)
回答:
DNS服务器实现域名到IP地址的转换。
每个域名的平均长度为25个字节(估计值),每个IP为4个字节,所以Cache的每个条目需要大概30个字节。
总共50M个条目,所以需要1.5G个字节的空间。可以放置在内存中。(考虑到每秒5000次操作的限制,也只能放在内存中。)
可以考虑的数据结构包括hash_map,字典树,红黑树等等。
15、找出给定字符串对应的序号。
序列Seq=[a,b,…z,aa,ab…az,ba,bb,…bz,…,za,zb,…zz,aaa,…]类似与excel的排列,任意给出一个字符串s=[a-z]+(由a-z字符组成的任意长度字符串),请问s是序列Seq的第几个。
回答:
注意到每满26个就会向前进一位,类似一个26进制的问题。
比如ab,则位置为26*1+2;
比如za,则位置为26*26+1;
比如abc,则位置为26*26*1+26*2+3;
16、找出第k大的数字所在的位置。写一段程序,找出数组中第k大小的数,输出数所在的位置。例如{2,4,3,4,7}中,第一大的数是7,位置在4。第二大、第三大的数都是4,位置在1、3随便输出哪一个均可。
答案:
先找到第k大的数字,然后再遍历一遍数组找到它的位置。所以题目的难点在于如何最高效的找到第k大的数。
我们可以通过快速排序,堆排序等高效的排序算法对数组进行排序,然后找到第k大的数字。这样总体复杂度为O(NlogN)。
我们还可以通过二分的思想,找到第k大的数字,而不必对整个数组排序。从数组中随机选一个数t,通过让这个数和其它数比较,我们可以将整个数组分成了两部分并且满足,{x,xx,…,t}<{y,yy,…}。
在将数组分成两个数组的过程中,我们还可以记录每个子数组的大小。这样我们就可以确定第k大的数字在哪个子数组中。
然后我们继续对包含第k大数字的子数组进行同样的划分,直到找到第k大的数字为止。
平均来说,由于每次划分都会使子数组缩小到原来1/2,所以整个过程的复杂度为O(N)。
17、给40亿个不重复的unsigned> 18、在一个文件中有10G个整数,乱序排列,要求找出中位数。内存限制为2G。
回答:
不妨假设10G个整数是64bit的。
2G内存可以存放256M个64bit整数。
我们可以将64bit的整数空间平均分成256M个取值范围,用2G的内存对每个取值范围内出现整数个数进行统计。这样遍历一边10G整数后,我们便知道中数在那个范围内出现,以及这个范围内总共出现了多少个整数。
如果中数所在范围出现的整数比较少,我们就可以对这个范围内的整数进行排序,找到中数。如果这个范围内出现的整数比较多,我们还可以采用同样的方法将此范围再次分成多个更小的范围(256M=2^28,所以最多需要3次就可以将此范围缩小到1,也就找到了中数)。
19、时分秒针在一天之内重合多少次?(24小时)
2次
而时针和分针重合了22次。
20、将多个集合合并成没有交集的集合。
给定一个字符串的集合,格式如:{aaabbbccc},{bbbddd},{eeefff},{ggg},{dddhhh}要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集,例如上例应输出{aaabbbcccdddhhh},{eeefff},{ggg}。
(1)请描述你解决这个问题的思路;
(2)请给出主要的处理流程,算法,以及算法的复杂度
(3)请描述可能的改进。
回答:
集合使用hash_set来表示,这样合并时间复杂度比较低。
1、给每个集合编号为0,1,2,3…
2、创建一个hash_map,key为字符串,value为一个链表,链表节点为字符串所在集合的编号。遍历所有的集合,将字符串和对应的集合编号插入到hash_map中去。
3、创建一个长度等于集合个数的int数组,表示集合间的合并关系。例如,下标为5的元素值为3,表示将下标为5的集合合并到下标为3的集合中去。开始时将所有值都初始化为-1,表示集合间没有互相合并。在集合合并的过程中,我们将所有的字符串都合并到编号较小的集合中去。
遍历第二步中生成的hash_map,对于每个value中的链表,首先找到最小的集合编号(有些集合已经被合并过,需要顺着合并关系数组找到合并后的集合编号),然后将链表中所有编号的集合都合并到编号最小的集合中(通过更改合并关系数组)。
4、现在合并关系数组中值为-1的集合即为最终的集合,它的元素来源于所有直接或间接指向它的集合。
算法的复杂度为O(n),其中n为所有集合中的元素个数。
题目中的例子:
0:{aaabbbccc}
1:{bbbddd}
2:{eeefff}
3:{ggg}
4:{dddhhh}
生成的hash_map,和处理完每个值后的合并关系数组分别为
aaa:0。[-1,-1,-1,-1,-1]
bbb:0,1。[-1,0,-1,-1,-1]
ccc:0。[-1,0,-1,-1,-1]
ddd:1,4。[-1,0,-1,-1,0]
eee:2。[-1,0,-1,-1,0]
fff:2。[-1,0,-1,-1,0]
ggg:3。[-1,0,-1,-1,0]
hhh:4。[-1,0,-1,-1,0]
所以合并完后有三个集合,第0,1,4个集合合并到了一起。


软件工程师

一 简答:
1 说明数据库和线程死锁的原理和必要条件,如何防止死锁。
2 面向对象开发的三要素和五个基本原则。
3 Windows下内存管理叙述,并说明其优缺点。

二 算法和程序设计
1 某公司举行羽毛球大赛,共1001人,采用淘汰制,至少需要多少场比赛?用程序模拟实现。
2 100盏灯,第一轮操作:全部亮灯;第二轮,隔一个灭一个灯,即第偶数盏等灭掉;第三轮:隔两盏灯,如果是亮着的,灭掉,如果没亮,则打开;以此类推,进行到第100轮操作的时候,有多少盏灯是亮着的?
3 20个数组,每个数组有500个数,都按照降序排列,而且每个数组中保存的是uint 类型的数,32位。问如何选择其中的最大的500个数。

4 系统设计:太长了记不太清楚了,大意就是手机输入法,数字2和字母abc在一个键上,3和def…9和wxyz。针对输入法做了一下改进,联系人保存在UserList中,现在输入数字字符串NumStr“926”,则一下两种情况可以返回:
1 手机号码为13792611111等连续包含“926”的联系人会返回;
2 万年历,王小二。。。等会返回;因为“926”对应的一种拼音组合是“WAN”,这样wannianli,wangxiaoer等中包含wan,符合结果。
依据以上,写出程序。
输入:UserList,NumStr,和汉字拼音映射表Dir;
输出:ResultList

我感觉自己是尽力答了。可能结果不尽如人意。
死锁问题基本上差不多
面向对象三要素:封装继承多态;五个原则不会。
内存管理答非所问,我写的是堆啊栈啊常量区啊什么的,问的实际不是这个!!!!应该是虚拟内存啊什么的。要不为啥强调Windows下呢?

算法问题

羽毛球大赛赛程安排,采用递归。首先我先把每个人的模拟成一个结构体,其羽毛球水平是其一个int类型的属性,越大越好,随机分配。
然后分情况,每次淘汰一半人,如果剩余人数是偶数,则比较第一个和最后一个,把能力值(int)大的人放到前面的位置,把要淘汰的人放到后面的位置,整个数组的前一半所表示的员工有意义,后一半不考虑;如果剩余人数是奇数,既要先把最后一个人轮空,前偶数个人按照上一情况比赛,知识最后保留所有人数的一半+1,当然不能然最后一个人一直轮空,所以将其移到第一个位置,其他整体后移一位然后继续。。。现在想起来,前面选择一个位置随机和最后一个位置替换就成了。。。而且这道题我写的很乱。。。

100盏灯,刚开始毫无思路,后来忽然想到把每一盏灯变化的次数求出来不久行了吗?这样一看,题目 很明了,实际上就是告诉你有一百次操作,第 i 次操作就是把第 i*1,i*2…i*n(要小于等于100)个灯的状态改变,这样再看,那么第1盏灯值变一次,第2,3,5…只变了2次,第4盏灯只变了3 次…瞬间明白,分解因数。。。但是乐极生悲,我当时想当然的认为只要分解成1,本身,和其他素因子的个数就行了,在出考场的那一瞬间,我想到,其实不是素因子也可以。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。天哪!!!!!!!!!!!!!!!!!!!

20个数组问题:我感觉这道题应该不太难,可能是想让我进行一些优化什么的吧,提出一些高级的算法,不过我只想到最简单的情况,就是比较20个数组的第一个数,找最大的‘。假设第i组第一个最大,则这个数在10000个数中最大,保留,然后用剩余19个数字和第i组第二个数比较,找最大,找到剩余9999中最大的数字。。。依次,但是我一直不明白为啥要告诉32位。。。。。。应该是我有什么没想到的地方。。。

系统涉及题目,开始感觉不是特别难吧,但是把算法全部实现,我觉得我是难以完成,什么字符串匹配了,都忘了,之好用JAVA中的String来投机取巧,但是这样一来,还是有问题,怎样把你输入的StrNum转化成所有拼音组合并且排除其中一些不可能的组合。我估计在短时间内写不出来,而且实在恶心的不想继续再大体,所以瞎写几行,草草交了,抬头一看,偌大的中心考场,本来一人爱着一人,全部坐满,现在考场只剩下十几个了。。。

2.

满分100 时间2小时
一.问答题
1.写出几个经典的哈希算法,哈希算法的作用是什么
2.OSI网络通信协议有哪7层,HTTP协议在哪层运行
3.C语言代码运行起来的代码要求和执行过程
二.算法或程序设计题
1. 有一车苹果,先对其包装,一个袋子放3个最后剩2个,一个袋子放5个最后剩3个,一个袋子放7个最后剩2个。请找出N个符合这种条件的苹果个数,写出该算法(可用伪代码)
2.用递归函数实现求一个字符串相同字符连续的最大个数,如字符串aaabbcc 相同字符连续最多数为3.
3.有一个超过100亿个数据元素的数组,按从小到大排序。现将它分为若干个数组,每个数组的元素少于20个。现把这些数组重新排序,试写出时间效率最高的算法,并写出时间复杂度分析。
三.一道很长的数据库题,数据关系类的。完全不会,所以也记不住了。就记得是一个社交网站,记录某人配偶,子女,父母,兄弟,朋友这些社会关系,并且假如你是某人的儿子,则你父母的数据将自动生成他们的儿子是…而你的朋友是D,则D的朋友自动生成你的名字…..
定义数据库……

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值