一道简单的 c++编程题求解答

2018-02-18 23:26:55 +08:00
 greenhat233

题目描述

小陈上了一天的课后,走在回宿舍的路上。走着走着,突然发现前面一位食堂的阿姨一不小心把刚洗好的筷子打翻了。

小陈很热心,于是飞快地走上前去帮她捡。阿姨说:“谢谢你哈!但是,这些筷子都乱了,你能帮我把它们凑成一对一对的吗?啊!对了,里面还有一只筷子是落单的。帮我把它找出来吧!谢谢你哈”(哇……你要求怎么这么多)

请你帮忙数一下一共有多少双筷子并找出那只落单的筷子吧!

输入

输入包含多组测试用例。

每组测试用例中第一行为一个正整数 N,代表筷子的只数。( 1≤N≤5×106 )

接下来一行有 N 个正整数,代表筷子的长度 Li ( 1≤Li≤109 )。

输出

对于每组测试用例,输出两个数字。

第一个数字为能凑成的不同长度的筷子的种类数,第二个数字是落单的筷子的长度。这两个数字用一个空格隔开。

样例输入

5 1 2 3 1 2 7 1 1 1 2 2 2 2

样例输出

2 3 2 1 下面是我的代码: https://paste.ubuntu.com/p/RJ7TFZ6fVD/ 思路是先存放在 multiset,然后用 count()查看容器里面每个值的个数,每处理完一个,就删除掉,处理下一个,但是 erase 那里出了问题,我不知道是什么问题,麻烦 v 友解答下。

下面给出一个失败输出样例: 43 31 9 3 8 12 22 13 18 16 23 1 21 20 26 25 4 27 30 11 15 31 9 3 8 12 22 13 18 16 23 1 21 20 26 25 7 4 27 30 11 15 15 15

谢谢

4344 次点击
所在节点    问与答
39 条回复
greenhat233
2018-02-18 23:28:11 +08:00
输入那里是
5
1 2 3 1 2
7
1 1 1 2 2 2 2
输出是
2 3
2 1
skadi
2018-02-18 23:58:05 +08:00
惊了.直接一个 map 就解决了的事情.

map[ element ]++;
monkeymonkey
2018-02-19 00:02:48 +08:00
```
int main()
{
int N = 0;
int hash[1000] = {0};
int l = 0;

cin >> N;
for (int i = 0; i < N; i++) {
cin >> l;
hash[l]++;
}

int count = 0, single = 0;
for (int i = 0; i < 1000; i++) {
if (hash[i] >= 2)
count++;
if (hash[i] % 2 != 0)
single = i;
}

cout << count << " " << single << endl;
return 0;
}
```
vegito2002
2018-02-19 00:09:11 +08:00
所有筷子长度异或到一起, 结果就是落单筷子的长度
x86vk
2018-02-19 00:15:37 +08:00
其实没必要那么复杂吧,直接全部读入后排序,从头到尾撸一遍就行。复杂度 nlogn
vegito2002
2018-02-19 00:19:07 +08:00
落单筷子长度=0;
map count;
筷子种类数;
for each 筷子
{
落单筷子长度 ^= 这个筷子长度;
if (count[这个筷子长度]++ == 0): 筷子种类数++;
}
if (--count[落单筷子长度] == 0): 筷子种类数--;
return (落单筷子长度, 筷子种类数);
Yourshell
2018-02-19 00:20:23 +08:00
我觉得和编程珠玑第一章那个问题挺像的。你的代码我就看不懂了
di94sh
2018-02-19 01:19:42 +08:00
建一个 map 长度为键:该长度个数为值 如果为奇数就是落单的。
Mirage09
2018-02-19 01:47:23 +08:00
排序后遍历一遍,奇数个就是落单的。
hackpro
2018-02-19 02:26:38 +08:00
@vegito2002 厉害!
greenhat233
2018-02-19 02:35:40 +08:00
@skadi 主要是想熟悉下 set
greenhat233
2018-02-19 02:37:38 +08:00
@Yourshell 是某个 oj 里面的
greenhat233
2018-02-19 02:38:19 +08:00
@x86vk 主要是想熟悉下 set
wallriding
2018-02-19 03:45:40 +08:00
楼主你要的用 set 的方法

#include <iostream>
#include <unordered_set>
using namespace std;

int main() {
unordered_set<int> singles;
unordered_set<int> pairs;
int N = 0;
cin >> N;
for (int i = 0; i < N; i++) {
int l;
cin >> l;
if (singles.find(l) == singles.end()) {
singles.insert(l);
}
else {
singles.erase(l);
pairs.insert(l);
}
}
cout << pairs.size() << " " << *singles.begin() << endl;
return 0;
}
SuperFashi
2018-02-19 08:54:00 +08:00
@vegito2002 正解,时间 O(n)空间 O(1)
SuperFashi
2018-02-19 08:58:17 +08:00
等,不一定,如果要算种类那还不如直接 hashmap
x86vk
2018-02-19 09:15:50 +08:00
@SuperFashi set 我记得查找是 logn 啊,如果套哈希的话数据可以把你卡成 n2 的复杂度
vegito2002
2018-02-19 10:21:32 +08:00
@SuperFashi 我 6L 的代码是 O(N)时间而且是 1-pass. 这题 O(1)空间是做不到的, 只能抢一个常数因子的时间差距; 只用 count 来做的话, 我觉得可能要两个 pass? 筷子本身过一个 pass, 然后 count 要过一个 pass;
kiwi95
2018-02-19 10:29:55 +08:00
筷子的长度取值空间这么小,一个位图表示,空间和 N 没有关系,可以看成 O(1)的空间,O(n)的时间,类似 6L 的方法
SuperFashi
2018-02-19 12:15:07 +08:00
@vegito2002 不用 map,直接数组就行

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/431181

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX