[22231程序设计]课堂练习5:Finding Missing Cards
这道题我们采用打标签的方法可以在线性复杂度内完成。
思考这样的问题:
(1)如何表示是否出现过某一张牌,如何记录花色和数字。
(2)记录之后,我们怎么再次检查输出没有出现过的牌
考虑这样的一张表格(标记矩阵):
花色 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
S | false(无效) | true | false | false | false | true | false | false | false | false | false | false | false | false |
H | false(无效) | false | false | false | false | false | false | false | false | false | false | false | false | false |
C | false(无效) | true | false | false | false | true | false | false | false | false | false | false | false | false |
D | false(无效) | true | false | false | false | true | false | false | false | false | false | false | false | false |
以上矩阵表示输入为
S 1
S 5
C 1
C 5
D 1
D 5
在输出的时候,我们只需要遍历这个二维矩阵就可以找到所有没有出现过的牌了。
在此基础上,我们可以很容易运用二维矩阵解决问题,只需要将花色做[0,3]的映射即可。在输入S 5
的时候,我们就可以将二维矩阵的对应位置的布尔值标记为true,即 mat[0][5] = true
然而,如何不运用二维矩阵呢?
-
最简单的方式就是用四个单独的一维数组,比如命名为
s[N], h[N], c[N], d[N]
,其中N
为数组的长度,也就是标记矩阵的列数。 -
也可以将以上的M行N列的标记矩阵(M*N)平铺展开为一个一维数组(M*N)。
那么之前第 i 行,第 j 列的数据,展开到一维数组中就应该是第 i * N + j 个数据。
以下给出最简单的第一种方式的代码
#include <iostream>
#include <cstdio>
using namespace std;
int n;
int s[15], h[15], c[15], d[15]; // 标记数组
int main()
{
cin >> n;
while(n --){ // 这个方法可以代替单调的记录循环次数用的 for(int i = 0; i < n; i ++)
// 但需要注意的是 while(n--)这样的循环头会导致n的值发生变化,必须要确定之后不用n了
char ch;
cin >> ch; // 输入花色
int num;
switch(ch){
cin >> num;
case 'S':
s[num] = true; // 将该元素标记为出现过
break;
case 'H':
h[num] = true;
break;
case 'C':
c[num] = true;
break;
case 'D':
d[num] = true;
break;
}
}
for (int i = 1; i <= 13; i ++){
if(!s[i]) // 如果标记为false表示没出现过
cout << "S " << i << endl;
}
for (int i = 1; i <= 13; i ++){
if(!h[i])
cout << "H " << i << endl;
}
for (int i = 1; i <= 13; i ++){
if(!c[i])
cout << "C " << i << endl;
}
for (int i = 1; i <= 13; i ++){
if(!d[i])
cout << "D " << i << endl;
}
return 0;
}
以上是最简单的写法,那可以考虑以下如何把这个单独的四个数组拼接成一个长的一维数组吗?
只需要给出一个为每一个花色指定一个组号并弄明白一个计算下标的方式(之前已经提到了),下面给出提示代码。
bool appear[60]; // 标记数组
int ss = 0, hh = 1, cc = 2, dd = 3;
动手画一画想一想,写一写代码吧!
二维矩阵的做法其实非常直观,同学们学习了二维矩阵的知识之后可以自己再写一写这道题。
下面,我们来怼一下网上的代码
链接我就不放了(怕被骂),一搜题目就能搜到,优快云上的。
那一个用了sort排序。
大家可以手动跑一下这个代码的过程(就是把自己当成电脑,演算一下,别要觉得看起来挺傻,其实很有用,对思维很有益处)
可以看出,他是用一个标记矩阵依次记录了输入的每一张卡牌。
按照之前这样的输入
S 1
S 5
C 1
C 5
D 1
D 5
你们看看会得到怎样的一个矩阵(在sort之前)?
自己想一想跑一跑
然后其实我们可以不用sort,只需要遍历四遍1-13,看每一个数在那一个数组中是否出现,如果出现了表示输入包括这一张,就不输出,否则输出。
这样的作法复杂度是最高的,因为有双重循环,那么如何减小这样的复杂度呢?就是用sort.
sort之后矩阵会变成什么样呢?
遍历思辨1-13的过程我们在怎么比较呢?
可以思考一下,这样的做法与之前我给出的代码相比有什么区别?更优还是更劣?
大家可以进行积极的线上讨论或者在自习的时候我们可以统一说一下,发表一下各自的意见。