PAT练习笔记——4.2 散列

2019年9月PAT - 练习笔记——4.2

以下页码标注的是阅读器中实际页码,而不是书本身自印的页码。

第4章 入门篇(2)——算法初步

4.2 散列

注意

  1. 注意题目中是否隐含输入字符串可能为空的条件,见B1033

目录

  1. B1029 / A1084 旧键盘
  2. B1033 旧键盘打字
  3. B1038 统计同成绩学生
  4. B1039 / A1092 到底买不买
  5. B1042 字符统计
  6. B1043 输出PATest
  7. A1041 Be Unique
  8. A1050 String Subtraction
  9. B1005 继续(3n+1)猜想
  10. A1048 Find Coins

  1. B1029 / A1084 旧键盘

    旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及实际被输入的文字,请你列出肯定坏掉的那些键。

    输入格式:

    输入在 2 行中分别给出应该输入的文字、以及实际被输入的文字。每段文字是不超过 80 个字符的串,由字母 A-Z(包括大、小写)、数字 0-9、以及下划线 _(代表空格)组成。题目保证 2 个字符串均非空。

    输出格式:

    按照发现顺序,在一行中输出坏掉的键。其中英文字母只输出大写,每个坏键只输出一次。题目保证至少有 1 个坏键。

    输入样例:
    7_This_is_a_test
    _hs_s_a_es
    
    输出样例:
    7TI
    
    1. 我的

      方法一

      #include <iostream>
      #include <string>
      #include <map>
      
      using namespace std;
      
      int main(void)
      {
      	string str1 = "", str2 = "";
      	cin >> str1 >> str2;
      	
      	map<char, bool>keys;
      	map<char, bool>output;
      	for (int i = 0;i < str1.size();++i) keys[toupper(str1[i])] = true;
      	for (int i = 0;i < str2.size();++i) keys[toupper(str2[i])] = false;
      	for (int i = 0;i < str1.size();++i) {
      		char c = toupper(str1[i]);
      		if (keys[c] && !output[c]) {
      			cout << c;
      			output[c] = true;
      		}
      	}
      	
      	return 0;
      }
      

      方法二

      #include <iostream>
      #include <string>
      
      using namespace std;
      
      int main(void)
      {
      	string str1 = "", str2 = "";
      	cin >> str1 >> str2;
      	
      	map<char, bool>output;
      	int i = 0;
      	for (int j = 0;i < str1.size() && j < str2.size();) {
      		char c1 = toupper(str1[i]), c2 = toupper(str2[j]);
      		if (c1 == c2) {
      			++i;
      			++j;
      		}
      		else {
      			if (!output[c1]) {
      				cout << c1;
      				output[c1] = true;
      			}
      			++i;
      		}
      	}
      	for (;i < str1.size();++i) {
      		char c1 = toupper(str1[i]);
      		if (!output[c1]) {
      			cout << c1;
      			output[c1] = true;
      		}
      	}
      	
      	return 0;
      }
      

      第二种写法容易漏第一个字符串末尾的处理

    2. 《算法笔记》P136


  2. B1033 旧键盘打字

    旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及坏掉的那些键,打出的结果文字会是怎样?

    输入格式:

    输入在 2 行中分别给出坏掉的那些键、以及应该输入的文字。其中对应英文字母的坏键以大写给出;每段文字是不超过 105 个字符的串。可用的字符包括字母 [a-z, A-Z]、数字 0-9、以及下划线 _(代表空格)、,.-+(代表上档键)。题目保证第 2 行输入的文字串非空。

    注意:如果上档键坏掉了,那么大写的英文字母无法被打出。

    输出格式:

    在一行中输出能够被打出的结果文字。如果没有一个字符能被打出,则输出空行。

    输入样例:
    7+IE.
    7_This_is_a_test.
    
    输出样例:
    _hs_s_a_tst
    
    1. 我的

      #include <iostream>
      #include <string>
      #include <map>
      
      using namespace std;
      
      int main(void)
      {
      	string str1 = "", str2 = "";
      	getline(cin, str1);
      	getline(cin, str2);
      	
      	map<char, bool> broken;
      	for (int i = 0;i < str1.size();++i) broken[str1[i]] = true;
      	
      	for (int i = 0;i < str2.size();++i) {
      		if ('A' <= str2[i] && str2[i] <= 'Z') {
      			if (!broken['+'] && !broken[str2[i]]) cout << str2[i];
      		}
      		else if (!broken[toupper(str2[i])]) cout << str2[i];
      	}
      	
      	return 0;
      }
      

      注意第一个字符串可能为空!(测试点3):https://blog.csdn.net/weixin_35093872/article/details/86563886

    2. 《算法笔记》P137


  3. B1038 统计同成绩学生

    本题要求读入 N 名学生的成绩,将获得某一给定分数的学生人数输出。

    输入格式:

    输入在第 1 行给出不超过 105 的正整数 N,即学生总人数。随后一行给出 N 名学生的百分制整数成绩,中间以空格分隔。最后一行给出要查询的分数个数 K(不超过 N 的正整数),随后是 K 个分数,中间以空格分隔。

    输出格式:

    在一行中按查询顺序给出得分等于指定分数的学生人数,中间以空格分隔,但行末不得有多余空格。

    输入样例:
    10
    60 75 90 55 75 99 82 90 75 50
    3 75 90 88
    
    输出样例:
    3 2 0
    
    1. 我的

      #include <iostream>
      #include <string>
      #include <map>
      
      using namespace std;
      
      int main(void)
      {
      	int n = 0;
      	cin >> n;
      	map<int, int> counts;
      	for (int i = 0;i < n;++i) {
      		int grade = 0;
      		cin >> grade;
      		++counts[grade];
      	}
      	
      	int k = 0;
      	cin >> k;
      	for (int i = 0;i < k;++i) {
      		int grade = 0;
      		cin >> grade;
      		if (i) cout << " ";
      		cout << counts[grade];
      	}
      	
      	return 0;
      }
      
    2. 《算法笔记》P139


  4. B1039 / A1092 到底买不买

    红想买些珠子做一串自己喜欢的珠串。卖珠子的摊主有很多串五颜六色的珠串,但是不肯把任何一串拆散了卖。于是小红要你帮忙判断一下,某串珠子里是否包含了全部自己想要的珠子?如果是,那么告诉她有多少多余的珠子;如果不是,那么告诉她缺了多少珠子。

    为方便起见,我们用[0-9]、[a-z]、[A-Z]范围内的字符来表示颜色。例如在图1中,第3串是小红想做的珠串;那么第1串可以买,因为包含了全部她想要的珠子,还多了8颗不需要的珠子;第2串不能买,因为没有黑色珠子,并且少了一颗红色的珠子。

    figbuy.jpg

    图 1

    输入格式:

    每个输入包含 1 个测试用例。每个测试用例分别在 2 行中先后给出摊主的珠串和小红想做的珠串,两串都不超过 1000 个珠子。

    输出格式:

    如果可以买,则在一行中输出 Yes 以及有多少多余的珠子;如果不可以买,则在一行中输出 No 以及缺了多少珠子。其间以 1 个空格分隔。

    输入样例 1:
    ppRYYGrrYBR2258
    YrR8RrY
    
    输出样例 1:
    Yes 8
    
    输入样例 2:
    ppRYYGrrYB225
    YrR8RrY
    
    输出样例 2:
    No 2
    
    1. 我的

      #include <iostream>
      #include <string>
      #include <map>
      
      using namespace std;
      
      int main(void)
      {
      	string str1 = "", str2 = "";
      	getline(cin, str1);
      	getline(cin, str2);
      	
      	map<char, int> need;
      	for (int i = 0;i < str2.size();++i) ++need[str2[i]];
      	
      	int count = str2.size();
      	for (int i = 0;i < str1.size();++i) {
      		if (need[str1[i]]) {
      			--count;
      			--need[str1[i]];
      		}
      	}
      	if (count) cout << "No " << count;
      	else cout << "Yes " << str1.size() - str2.size();
      	
      	return 0;
      }
      
    2. 《算法笔记》P140


  5. B1042 字符统计

    请编写程序,找出一段给定文字中出现最频繁的那个英文字母。

    输入格式:

    输入在一行中给出一个长度不超过 1000 的字符串。字符串由 ASCII 码表中任意可见字符及空格组成,至少包含 1 个英文字母,以回车结束(回车不算在内)。

    输出格式:

    在一行中输出出现频率最高的那个英文字母及其出现次数,其间以空格分隔。如果有并列,则输出按字母序最小的那个字母。统计时不区分大小写,输出小写字母。

    输入样例:
    This is a simple TEST.  There ARE numbers and other symbols 1&2&3...........
    
    输出样例:
    e 7
    
    1. 我的

      #include <iostream>
      #include <string>
      #include <map>
      
      using namespace std;
      
      int main(void)
      {
      	string str = "";
      	getline(cin, str);
      	
      	map<char, int> counts;
      	char maxc = 0;
      	for (int i = 0;i < str.size();++i) {
      		char c = tolower(str[i]);
      		++counts[c];
      		if ('a' <= c && c <= 'z') {
      			if (counts[c] > counts[maxc] || (counts[c] == counts[maxc] && c < maxc)) maxc = c;
      		}
      	}
      	cout << maxc << " " << counts[maxc];
      	
      	return 0;
      }
      
    2. 《算法笔记》P142


  6. B1043 输出PATest

    给定一个长度不超过 104 的、仅由英文字母构成的字符串。请将字符重新调整顺序,按 PATestPATest.... 这样的顺序输出,并忽略其它字符。当然,六种字符的个数不一定是一样多的,若某种字符已经输出完,则余下的字符仍按 PATest 的顺序打印,直到所有字符都被输出。

    输入格式:

    输入在一行中给出一个长度不超过 104 的、仅由英文字母构成的非空字符串。

    输出格式:

    在一行中按题目要求输出排序后的字符串。题目保证输出非空。

    输入样例:
    redlesPayBestPATTopTeePHPereatitAPPT
    
    输出样例:
    PATestPATestPTetPTePePee
    
    1. 我的

      #include <iostream>
      #include <string>
      #include <map>
      
      using namespace std;
      
      int main(void)
      {
      	string str = "";
      	getline(cin, str);
      	
      	map<char, int> PATest;
      	for (int i = 0;i < str.size();++i) ++PATest[str[i]];
      	
      	const char PATEST[] = {'P', 'A', 'T', 'e', 's', 't'};
      	bool flag = true;
      	while (flag) {
      		flag = false;
      		for (int i = 0;i < 6;++i) {
      			if (PATest[PATEST[i]]) {
      				cout << PATEST[i];
      				--PATest[PATEST[i]];
      				flag = true;
      			}
      		}
      	}
      	
      	return 0;
      }
      
    2. 《算法笔记》P144


  7. A1041 Be Unique

    Being unique is so important to people on Mars that even their lottery is designed in a unique way. The rule of winning is simple: one bets on a number chosen from [1,104]. The first one who bets on a unique number wins. For example, if there are 7 people betting on { 5 31 5 88 67 88 17 }, then the second one who bets on 31 wins.

    Input Specification:

    Each input file contains one test case. Each case contains a line which begins with a positive integer N (≤105) and then followed by N bets. The numbers are separated by a space.

    Output Specification:

    For each test case, print the winning number in a line. If there is no winner, print None instead.

    Sample Input 1:
    7 5 31 5 88 67 88 17
    
    Sample Output 1:
    31
    
    Sample Input 2:
    5 888 666 666 888 888
    
    Sample Output 2:
    None
    
    1. 我的

      #include <iostream>
      #include <string>
      #include <vector>
      #include <map>
      
      using namespace std;
      
      int main(void)
      {
      	int n = 0;
      	cin >> n;
      	
      	vector<int> bets(n);
      	map<int, int> counts;
      	for (int i = 0;i < n;++i) {
      		cin >> bets[i];
      		++counts[bets[i]];
      	}
      	bool flag = true;
      	for (int i = 0;i < n;++i) {
      		if (1 == counts[bets[i]]) {
      			cout << bets[i];
      			flag = false;
      			break;
      		}
      	}
      	if (flag) cout << "None";
      	
      	return 0;
      }
      
    2. 《算法笔记》P145


  8. A1050 String Subtraction

    Given two strings S1 and S2, S=S1S2 is defined to be the remaining string after taking all the characters in S2 from S1. Your task is simply to calculate S1S2 for any given strings. However, it might not be that simple to do it fast.

    Input Specification:

    Each input file contains one test case. Each case consists of two lines which gives S1 and S2, respectively. The string lengths of both strings are no more than 104. It is guaranteed that all the characters are visible ASCII codes and white space, and a new line character signals the end of a string.

    Output Specification:

    For each test case, print S1S2 in one line.

    Sample Input:
    They are students.
    aeiou
    
    Sample Output:
    Thy r stdnts.
    
    1. 我的

      #include <iostream>
      #include <string>
      #include <vector>
      #include <map>
      
      using namespace std;
      
      int main(void)
      {
      	string s1 = "", s2 = "";
      	getline(cin, s1);
      	getline(cin, s2);
      	
      	map<char, bool> letters;
      	for (int i = 0;i < s2.size();++i) letters[s2[i]] = true;
      	
      	for (int i = 0;i < s1.size();++i) {
      		if (!letters[s1[i]]) cout << s1[i];
      	}
      	
      	return 0;
      }
      
    2. 《算法笔记》P148


  9. B1005 继续(3n+1)猜想

    卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。

    当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对 n=3 进行验证的时候,我们需要计算 3、5、8、4、2、1,则当我们对 n=5、8、4、2 进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这 4 个数已经在验证3的时候遇到过了,我们称 5、8、4、2 是被 3“覆盖”的数。我们称一个数列中的某个数 n 为“关键数”,如果 n 不能被数列中的其他数字所覆盖。

    现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。

    输入格式:

    每个测试输入包含 1 个测试用例,第 1 行给出一个正整数 K (<100),第 2 行给出 K 个互不相同的待验证的正整数 n (1<n≤100)的值,数字间用空格隔开。

    输出格式:

    每个测试用例的输出占一行,按从大到小的顺序输出关键数字。数字间用 1 个空格隔开,但一行中最后一个数字后没有空格。

    输入样例:
    6
    3 5 6 7 8 11
    
    输出样例:
    7 6
    
    1. 我的

      #include <iostream>
      #include <vector>
      #include <map>
      #include <algorithm>
      
      using namespace std;
      
      int main(void)
      {
      	int k = 0;
      	cin >> k;
      	
      	vector<int> nums(k);
      	map<int, bool> covers;
      	for (int i = 0;i < k;++i) {
      		int n = 0;
      		cin >> n;
      		nums[i] = n;
      		for (;n != 1;) {
      			if (0 == n % 2) n /= 2;
      			else n = (3 * n + 1) / 2;
      			covers[n] = true;
      		}
      	}
      	sort(nums.begin(), nums.end(), greater<int>());
      	
      	int count = 0;
      	for (int i = 0;i < k;++i) {
      		if (!covers[nums[i]]) {
      			if (count) cout << " ";
      			++count;
      			cout << nums[i];
      		}
      	}
      	
      	return 0;
      }
      
    2. 《算法笔记》P151


  10. A1048 Find Coins

    Eva loves to collect coins from all over the universe, including some other planets like Mars. One day she visited a universal shopping mall which could accept all kinds of coins as payments. However, there was a special requirement of the payment: for each bill, she could only use exactly two coins to pay the exact amount. Since she has as many as 105 coins with her, she definitely needs your help. You are supposed to tell her, for any given amount of money, whether or not she can find two coins to pay for it.

    Input Specification:

    Each input file contains one test case. For each case, the first line contains 2 positive numbers: N (≤105, the total number of coins) and M (≤103, the amount of money Eva has to pay). The second line contains N face values of the coins, which are all positive numbers no more than 500. All the numbers in a line are separated by a space.

    Output Specification:

    For each test case, print in one line the two face values V1 and V2 (separated by a space) such that V1+V2=M and V1≤V2. If such a solution is not unique, output the one with the smallest V1. If there is no solution, output No Solution instead.

    Sample Input 1:
    8 15
    1 2 8 7 2 4 11 15
    
    Sample Output 1:
    4 11
    
    Sample Input 2:
    7 14
    1 8 7 2 4 11 15
    
    Sample Output 2:
    No Solution
    
    1. 我的

      #include <iostream>
      #include <vector>
      #include <map>
      #include <algorithm>
      
      using namespace std;
      
      int main(void)
      {
      	int n = 0, m = 0;
      	cin >> n >> m;
      	
      	map<int, int> counts;
      	for (int i = 0;i < n;++i) {
      		int num = 0;
      		cin >> num;
      		++counts[num];
      	}
      	bool flag = true;
      	for (int i = 1;i <= m / 2;++i) {
      		if (counts[i]) {
      			--counts[i];
      			if (counts[m - i]) {
      				cout << i << " " << m - i;
      				flag = false;
      				break;
      			}
      		}
      	}
      	if (flag) cout << "No Solution";
      	
      	return 0;
      }
      
    2. 《算法笔记》P153

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值