OJ中级:开放的书名检索

6 篇文章 0 订阅
3 篇文章 0 订阅
描述: 

实现一个开放的书名检索库。库中存储了若干个书名。用户可以:指定搜索条件,搜索库中符合条件的书名

重要格式说明

单词

由小写英文字母组成,不含其它字符。

书名

由一个或多个单词组成。

当包含多个单词时,单词间用一个空格分隔;第一个单词前和最后一个单词后没有空格。

若只包含一个单词,则该单词前后均无空格。

搜索条件

1、由一个或多个不重复的关键字组成,每个关键字是一个单词。

2、当包含多个关键字时,关键字间用一个空格分隔;第一个关键字前和最后一个关键字后没有空格。

3、若只包含一个关键字,则该关键字前后均无空格。

4、关键字搜索的时候需要单词完全匹配如  关键字为soft  书名为software 则不匹配 

 

知识点: 
题目来源: 内部整理 
练习阶段: 高级 
运行时间限制:无限制
内存限制:无限制
输入: 

整数N。

N行字符串,每行一个书名。

一行字符串,搜索条件,包含一个或者多个搜索的关键词。

 

 

输出: 

整数M,满足条件的书名个数(未找到则为0)

符合条件的书名,每行一个,如果多个,按到书名的字典序输出。

字典顺序

1.两个书名均从第一个单词开始逐个单词比较,若遇到不相同的单词,则单词“较小”的书名排在前面。

2.单词中字母全部为小写。两个单词先以第一个字母作为排序的基准,如果第一个字母相同,就用第二个字母为基准,如果第二个字母相同就以第三个字母为基准。依此类推,如果到某个字母不相同,字母顺序在前的那个单词“较小”。

3.当一个短单词和一个长单词的开头部分都相同(即短单词是长单词从首字母开始的一部分),短单词“较小”。

 

 

样例输入:
7
high performance mysqlsecond edition
writing gnu emacs extensions
web client programming with perlautomating tasks
net test automation recipes a problem solution approach
photoreading
pro wfwindows workflow in net
aspect oriented analysis and design the theme approach
extensions gnu
                   
样例输出:
1
writing gnu emacs extensions
                    
答案提示:

书名个数N范围 [1,200]  

书名所含单词个数  [1,10]  

单词所含字母数  [1,50]  

搜索条件中关键字个数 [1,3]  

 

package huawei;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;


public class Demo
{
	
	public static ArrayList<HashSet<String>> synonymies = new ArrayList<HashSet<String>>();
	public static ArrayList<String> allBookNames = new ArrayList<String>();
	public static ArrayList<String> searchedBookNames = new ArrayList<String>();
	int flag = 0;
	
	//构造方法
	public Demo()
	{
		clear();
	}
	
    /**
     * 增加一条书名将两个单词设置为近义词关系
     *
     * @param BookName 书名字符串
     * @return true  成功(如果书名在库中已存在,也返回成功,但书名不重复加入);
     *         false 失败
     *
     */
    public boolean addBook(String bookName)
    {
        /* 在这里实现功能 */  	
    	if(bookName == null || "".equals(bookName) ||  " ".equals(bookName) || bookName.charAt(0) == ' ' || 
    			bookName.charAt(bookName.length()-1) == ' ')
    	{
    		return false;
    	}
    	String[] bookNameWords = bookName.split(" ");
    	for (int i = 0; i < bookNameWords.length; i++) {
    		String tempStr = bookNameWords[i];
    		if("".equals(tempStr))
    		{
    			return false;
    		}
		}
    	if(bookNameWords.length > 10)
    	{
    		return false;
    	}
    	
    	for (int i = 0; i < bookNameWords.length; i++) {
        	if(bookNameWords[i].length() > 50)
        	{
        		return false;
        	}
		}
	
    	if(allBookNames.contains(bookName))
    	{
    		return true;
    	}
    	else
    	{
    		if(allBookNames.size() < 200)
    		{
        		allBookNames.add(bookName);
    		}
    		if(allBookNames.contains(bookName))
    		{
    			return true;
    		}
    	}
        return false;
    }

    /**
     * 将两个单词设置为近义词关系
     *
     * @param word1 要设置为近义词的单词
     * @param word2 要设置为近义词的单词
     * @return true,成功(如果两个单词在之前已设置为近义词,也认为成功)
     *         false,失败(如果两个单词相同,也认为失败)
     *
     */
    public boolean setSynonymy(String word1, String word2)
    {
        /* 在这里实现功能 */
    	
		if(null == word1 || null == word2 || "".equals(word1) || "".equals(word2) || word1.equals(word2) ||
				word1.length() > 50 || word2.length() > 50 || " ".equals(word1) || " ".equals(word2)){
			
			return false;
		}
		
		for (int i = 0; i < word1.length(); i++) {
			if(word1.charAt(i) < 'a' || word1.charAt(i) > 'z')
			{
				return false;
			}
		}
		
		for (int i = 0; i < word2.length(); i++) {
			if(word2.charAt(i) < 'a' || word2.charAt(i) > 'z')
			{
				return false;
			}
		}
		
		if(synonymies.isEmpty()){
			HashSet<String> st = new HashSet<String>();
			st.add(word1);
			st.add(word2);
			synonymies.add(st);
		}
		else
		{
			for (int i = 0; i < synonymies.size(); i++) 
			{
				if(synonymies.get(i).contains(word1) || synonymies.get(i).contains(word2)){
					synonymies.get(i).add(word1);
					synonymies.get(i).add(word2);
					break;
				}
				
				if(i == synonymies.size()-1)
				{
					HashSet<String> hashSet = new HashSet<String>();
					hashSet.add(word1);
					hashSet.add(word2);
					synonymies.add(hashSet);
				}
			}			
		}
		return true;
            
    }

    /**
     * 根据输入的搜索条件,返回满足搜索条件的书名(可能为多条)
     *
     * @param condition condition 搜索条件字符串
     * @return 非空list  成功;
     *         null 失败
     *
     */
    public String[] searchBook(String input)
    {
        /* 在这里实现功能 */
    	if(input == null)
    	{
    		return null;
    	}	
    	if(allBookNames.isEmpty())
    	{
    		return null;
    	}
    	String[] keyWords = input.split(" ");
    	for (int i = 0; i < allBookNames.size(); i++) {
			String tempBookName = allBookNames.get(i);
			String[] tempWords = tempBookName.split(" ");
			List<String> list = Arrays.asList(tempWords);
			
			for (int j = 0; j < keyWords.length; j++) {
				List<String> keyWordsList = findSynonymy(keyWords[j]);
				for(String str : keyWordsList)
				{
					if(list.contains(str) && (!searchedBookNames.contains(tempBookName)))
					{
						searchedBookNames.add(tempBookName);
						break;
					}
				}
			}
		}
    	
    	if(!searchedBookNames.isEmpty())
    	{
    		Collections.sort(searchedBookNames);
    		String[] result = searchedBookNames.toArray(new String[searchedBookNames.size()]);
    		return result;
    	}
        return null;
    }

    /**
     * 清空库中所有书名及已设置的近义词
     *
     * @return 
     *
     */
    public boolean clear()
    {
        /* 在这里实现功能 */
    	allBookNames.clear();
    	synonymies.clear();
    	searchedBookNames.clear();
    	if(allBookNames.isEmpty() && synonymies.isEmpty() && searchedBookNames.isEmpty())
    	{
    		return true;
    	}
    	else
    	{
            return false;
    	}
    }
    
    /**
     * 找出一个单词的近义词
     *
     * @param word 要找近义词的单词
     * @return 非空list  成功;
     *
     */
    public List<String> findSynonymy(String word)
    {
    	List<String> result = new ArrayList<String>();
    	result.add(word);
    	for (HashSet<String> hashSet : synonymies) 
    	{
    		if(hashSet.contains(word))
    		{
    			for(String str : hashSet)
    			{
    				result.add(str);
    			}
    		}
		}
    	return result;
    }
    
}
/**
 *
 */
package testcase;

import java.util.Arrays;

import huawei.Demo;
import junit.framework.TestCase;

/**
 *
 *
 */

public class DemoTest extends TestCase
{


    private static final int MAX_BOOK_NUMBER = 7;

    private static String TEST_BOOK_NAME[] = {
            "mock objects in unit tests",
            "embedded system design a unified hardware software approach",
            "agile software development methods review and analysis",
            "object oriented analysis and design",
            "object oriented software composition",
            "software engineering with reusable components",
            "composite software construction",
            "embedded system design a unified hardware software approach software engineering with reusable components",
            "unitapproachsoftwareengineeringwithreusablecomponent",
            "embedded system design a unified hardware software",
            " "};

    String TEST_SYNONYMS_WORDS[] = {"analysis", "design", "approach", "method", "methods", "unit",
            "composition", "components", "composite"};

    String TEST_KEYWORDS[] = {"mock", "object", "system framework", "mock analysis",
            "object oriented", "framework", "framework build compile", "analysis",
            "unit",
            "software analysis mock",///10
            "software analysis mock", "method framework compile", "unit",
            "software analysis method unit system", "software analysis method unit system",//15
            "software analysis design", "soft", "ware", "analysis unit",//这个不用了
            "analysis method system",//20
            "software analysis method unit system", "analysis"};

    private String[] testExpectedNum(Demo demo, String keyword, int expectedNum)
    {
        String[] ret = demo.searchBook(keyword);
        if (expectedNum == 0)
        {
        	System.out.println("**************************************53 ret = %d"+ret);
            assertNull(ret);
        }
        else
        {
            assertEquals(ret.length, expectedNum);
        }
        return ret;
    }

    private void testExpectedValue(Demo demo, String keyword, String expected[], int expectedNum)
    {
        String[] ret = testExpectedNum(demo, keyword, expectedNum);

        sort(ret);
        sort(expected);

        compareResult(ret, expected);
    }

    //result的排序
    private void sort(String[] list)
    {
        if (list != null)
        {
            Arrays.sort(list);
        }
    }

    private void compareResult(String[] actual, String[] expected)
    {
        assertEquals(expected.length, actual.length);
        for (int i = 0; i < expected.length; i++)
        {
            assertEquals(expected[i], actual[i]);
        }
    }

    private void testAddAllBooks(Demo demo)
    {
        for (int i = 0; i < MAX_BOOK_NUMBER; i++)
        {
            boolean ret = demo.addBook(TEST_BOOK_NAME[i]);
            assertTrue(ret);
        }
    }

    public void testCase01()
    {
        Demo demo = new Demo();
        boolean ret = demo.addBook(TEST_BOOK_NAME[0]);
        assertTrue(ret);

        String ExpectBookName[] = {"mock objects in unit tests"};
        String keyword = TEST_KEYWORDS[0];
        int Expectnumber = 1;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase02()
    {
        Demo demo = new Demo();
        boolean ret = demo.addBook(TEST_BOOK_NAME[3]);
        assertTrue(ret);
        ret = demo.addBook(TEST_BOOK_NAME[4]);
        assertTrue(ret);

        String ExpectBookName[] = {"object oriented analysis and design",
                "object oriented software composition"};
        String keyword = TEST_KEYWORDS[1];
        int Expectnumber = 2;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase03()
    {
        Demo demo = new Demo();
        boolean ret = demo.addBook(TEST_BOOK_NAME[1]);
        assertTrue(ret);

        String ExpectBookName[] = {"embedded system design a unified hardware software approach"};
        String keyword = TEST_KEYWORDS[2];
        int Expectnumber = 1;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase04()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        String ExpectBookName[] = {"agile software development methods review and analysis",
                "mock objects in unit tests", "object oriented analysis and design"};
        String keyword = TEST_KEYWORDS[3];
        int Expectnumber = 3;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase05()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        String ExpectBookName[] = {"object oriented analysis and design",
                "object oriented software composition"};
        String keyword = TEST_KEYWORDS[4];
        int Expectnumber = 2;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase06()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        String keyword = TEST_KEYWORDS[5];
        testExpectedNum(demo, keyword, 0);
    }

    public void testCase07()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        String keyword = TEST_KEYWORDS[6];
        testExpectedNum(demo, keyword, 0);
    }

    public void testCase08()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        boolean ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[0], TEST_SYNONYMS_WORDS[1]);
        assertTrue(ret);

        String ExpectBookName[] = {"agile software development methods review and analysis",
                "embedded system design a unified hardware software approach",
                "object oriented analysis and design"};
        String keyword = TEST_KEYWORDS[7];
        int Expectnumber = 3;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase09()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        boolean ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[5], TEST_SYNONYMS_WORDS[6]);
        assertTrue(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[6], TEST_SYNONYMS_WORDS[7]);
        assertTrue(ret);

        String ExpectBookName[] = {"mock objects in unit tests",
                "object oriented software composition",
                "software engineering with reusable components"};
        String keyword = TEST_KEYWORDS[8];
        int Expectnumber = 3;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase10()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        boolean ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[0], TEST_SYNONYMS_WORDS[1]);
        assertTrue(ret);

        String ExpectBookName[] = {"agile software development methods review and analysis",
                "composite software construction",
                "embedded system design a unified hardware software approach",
                "mock objects in unit tests", "object oriented analysis and design",
                "object oriented software composition",
                "software engineering with reusable components"};
        String keyword = TEST_KEYWORDS[9];
        int Expectnumber = 7;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase11()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        String ExpectBookName[] = {"agile software development methods review and analysis",
                "composite software construction",
                "embedded system design a unified hardware software approach",
                "mock objects in unit tests", "object oriented analysis and design",
                "object oriented software composition",
                "software engineering with reusable components"};
        String keyword = TEST_KEYWORDS[10];
        int Expectnumber = 7;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
        demo.clear();

        testExpectedNum(demo, keyword, 0);
    }

    public void testCase12()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        boolean ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[2], TEST_SYNONYMS_WORDS[3]);
        assertTrue(ret);
        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[3], TEST_SYNONYMS_WORDS[4]);
        assertTrue(ret);

        String ExpectBookName[] = {"agile software development methods review and analysis",
                "embedded system design a unified hardware software approach"};
        String keyword = TEST_KEYWORDS[11];
        int Expectnumber = 2;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);

        ret = demo.clear();
        assertTrue(ret);

        testAddAllBooks(demo);

        testExpectedNum(demo, keyword, 0);
    }

    public void testCase13()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        boolean ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[5], TEST_SYNONYMS_WORDS[6]);
        assertTrue(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[6], TEST_SYNONYMS_WORDS[7]);
        assertTrue(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[7], TEST_SYNONYMS_WORDS[8]);
        assertTrue(ret);

        String ExpectBookName[] = {"composite software construction", "mock objects in unit tests",
                "object oriented software composition",
                "software engineering with reusable components"};

        String keyword = TEST_KEYWORDS[12];
        int Expectnumber = 4;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase14()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        String ExpectBookName[] = {"agile software development methods review and analysis",
                "composite software construction",
                "embedded system design a unified hardware software approach",
                "mock objects in unit tests", "object oriented analysis and design",
                "object oriented software composition",
                "software engineering with reusable components"};
        String keyword = TEST_KEYWORDS[13];
        int Expectnumber = 7;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase15()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        boolean ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[0], TEST_SYNONYMS_WORDS[1]);
        assertTrue(ret);

        String ExpectBookName[] = {"agile software development methods review and analysis",
                "composite software construction",
                "embedded system design a unified hardware software approach",
                "mock objects in unit tests", "object oriented analysis and design",
                "object oriented software composition",
                "software engineering with reusable components"};
        String keyword = TEST_KEYWORDS[14];
        int Expectnumber = 7;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase16()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);
        boolean ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[0], TEST_SYNONYMS_WORDS[1]);
        assertTrue(ret);

        String ExpectBookName[] = {"agile software development methods review and analysis",
                "composite software construction",
                "embedded system design a unified hardware software approach",
                "object oriented analysis and design", "object oriented software composition",
                "software engineering with reusable components"};
        String keyword = TEST_KEYWORDS[15];
        int Expectnumber = 6;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase17()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        String keyword = TEST_KEYWORDS[16];
        testExpectedNum(demo, keyword, 0);
    }

    public void testCase18()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        String keyword = TEST_KEYWORDS[17];
        testExpectedNum(demo, keyword, 0);
    }

    public void testCase19()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        boolean ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[0], TEST_SYNONYMS_WORDS[1]);
        assertTrue(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[2], TEST_SYNONYMS_WORDS[3]);
        assertTrue(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[3], TEST_SYNONYMS_WORDS[4]);
        assertTrue(ret);

        String ExpectBookName[] = {"agile software development methods review and analysis",
                "embedded system design a unified hardware software approach",
                "object oriented analysis and design",};
        String keyword = TEST_KEYWORDS[19];
        int Expectnumber = 3;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase20()
    {
        Demo demo = new Demo();
        testAddAllBooks(demo);

        boolean ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[2], TEST_SYNONYMS_WORDS[3]);
        assertTrue(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[3], TEST_SYNONYMS_WORDS[4]);
        assertTrue(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[5], TEST_SYNONYMS_WORDS[6]);
        assertTrue(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[7], TEST_SYNONYMS_WORDS[8]);
        assertTrue(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[6], TEST_SYNONYMS_WORDS[7]);
        assertTrue(ret);

        String ExpectBookName[] = {"agile software development methods review and analysis",
                "composite software construction",
                "embedded system design a unified hardware software approach",
                "mock objects in unit tests", "object oriented analysis and design",
                "object oriented software composition",
                "software engineering with reusable components"};
        String keyword = TEST_KEYWORDS[20];
        int Expectnumber = 7;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);

    }

    public void testCase21()
    {
        Demo demo = new Demo();
        String keyword = TEST_KEYWORDS[21];
        testExpectedNum(demo, keyword, 0);

        boolean ret = demo.addBook(TEST_BOOK_NAME[3]);
        assertTrue(ret);
        ret = demo.addBook(TEST_BOOK_NAME[3]);
        assertTrue(ret);

        String ExpectBookName[] = {"object oriented analysis and design"};
        int Expectnumber = 1;

        testExpectedValue(demo, keyword, ExpectBookName, Expectnumber);
    }

    public void testCase22()
    {
        Demo demo = new Demo();
        boolean ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[0], TEST_SYNONYMS_WORDS[1]);
        assertTrue(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[0], TEST_SYNONYMS_WORDS[1]);//测试重复加入近义词
        assertTrue(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[0], TEST_SYNONYMS_WORDS[0]);//测试不能加入相同的近义词
        assertFalse(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[0], TEST_BOOK_NAME[8]);//测试单词不超过50个字符
        assertFalse(ret);

        ret = demo.setSynonymy(TEST_SYNONYMS_WORDS[0], TEST_BOOK_NAME[10]);//测试不能包含空格
        assertFalse(ret);
    }

    public void testCase23()
    {
        Demo demo = new Demo();
        boolean ret = demo.addBook(TEST_BOOK_NAME[7]);//测试书名最大不能超过10个单词
        assertFalse(ret);

        ret = demo.addBook(TEST_BOOK_NAME[8]);//测试书名中包含的单词不超过50个字符
        assertFalse(ret);

        ret = demo.addBook(TEST_BOOK_NAME[10]);//测试书名中不能包含空格
        assertFalse(ret);
    }

    public void testCase24()
    {
        Demo demo = new Demo();
        String keyword = TEST_BOOK_NAME[8];
        String[] ret = testExpectedNum(demo, keyword, 0);
        assertNull(ret);
    }

    public void testCase25()
    {
        Demo demo = new Demo();

        boolean ret;
        for (int i = 1; i < 201; i++)
        {
            ret = demo.addBook("book name " + i);
            assertTrue(ret);
        }

        ret = demo.addBook("book name 200");//第201个重复的
        assertTrue(ret);

        ret = demo.addBook("book name 201");//超过200个
        assertFalse(ret);
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值