c++ には set と map があります。setは重複を許さない順序付き集合です。重複データがある場合は、重複データは自動的に削除されます。またmapは各要素がキーと値を持ち、同じキーが重複することがありません。
C#にもset, mapはあるのか?
C#にもsetと同じようなものがあります。それが HashSet です。以下のコードでは 1 と 2 が複数回がaddされていますが、2回目以降は無視されます。それ以外はaddされた順に格納されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
using System; using System.Collections.Generic; class Program { static void Main() { HashSet<int> hashSet = new HashSet<int>(); hashSet.Add(1); hashSet.Add(2); hashSet.Add(1); hashSet.Add(3); hashSet.Add(2); hashSet.Add(0); foreach (int i in hashSet) Console.WriteLine(i); } } |
C#でmapと似ているのが Dictionary です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
using System; using System.Collections.Generic; class Program { static void Main() { Dictionary<string, int> dic = new Dictionary<string, int>(); dic.Add("one", 1); dic.Add("two", 2); dic["three"] = 3; // Addを使わずに追加することもできる // dic.Add("one", 11); // 同じキーが存在する場合は例外が発生するので注意 foreach (var pair in dic) Console.WriteLine($"{pair.Key} {pair.Value}"); } } |
HashSetとDictionaryを使ってみる
X 段重ねの鏡餅 (X ≦ 1) とは、X 枚の円形の餅を縦に積み重ねたものであって、どの餅もその真下の餅より直径が小さい(一番下の餅を除く)もののことです。例えば、直径 10、8、6 センチメートルの餅をこの順に下から積み重ねると 3 段重ねの鏡餅になり、餅を一枚だけ置くと 1 段重ねの鏡餅になります。
ダックスフンドのルンルンは N 枚の円形の餅を持っていて、そのうち i 枚目の餅の直径は d_i センチメートルです。これらの餅のうち一部または全部を使って鏡餅を作るとき、最大で何段重ねの鏡餅を作ることができるでしょうか。
入力されるデータ
N
d_1
d_2
…
d_N
(ただし 1 ≦ N, d_i ≦ 100)
同じ直径の餅でなければ並び替えることで全部使うことができます。そこで HashSet に d_i を格納していき、最後に HashSet の要素の数を求めることで解を得ることができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
using System; using System.Collections.Generic; class Program { static void Main() { int N = int.Parse(Console.ReadLine()); HashSet<int> hashSet = new HashSet<int>(); for (int i = 0; i < N; i++) { int d = int.Parse(Console.ReadLine()); hashSet.Add(d); } Console.WriteLine(hashSet.Count); } } |
高橋君は青いカードを N 枚,赤いカードを M 枚持っています。 カードにはそれぞれ文字列が書かれており,
i 枚目の青いカードに書かれている文字列は s_i,i 枚目の赤いカードに書かれている文字列は t_i です。高橋君は文字列を 1 つ言います。そして全てのカードを確認しその文字列が書かれた青いカードを 1 枚見つけるごとに 1 円貰えます。 また,その文字列が書かれた赤いカードを 1 枚見つけるごとに 1 円失います。
高橋君は最大で差し引き何円貰うことができるでしょうか?
ただし違うカードに同じ文字列が書かれていることもあることに注意してください。
入力されるデータ
N
s 1
s 2
…
s N
M
t 1
t 2
…
t M(ただし、1 ≦ N, M ≦ 100,
カードに書かれている文字列の長さは 1 以上 10 以下)
青いカードに書かれている文字列をKeyにして辞書に登録します。最初のValueは1です。同じ文字列があったら Value をインクリメントします。そのあと同じ辞書に赤いカードに書かれている文字列があったらValueをデクリメントします。存在しない文字列であれば Value = -1 で登録します。
これでどんな文字列を言われても差し引き何円貰えるかがわかります。もし辞書に登録されていなければ0円です。言われる文字列は任意なので辞書に登録されているデータのValueが最大値になるものが答えです。ただし最大値が負数の場合は 0 が解となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
using System; using System.Collections.Generic; using System.Linq; class Program { static void Main() { Dictionary<string, int> dic = new Dictionary<string, int>(); int N = int.Parse(Console.ReadLine()); for (int i = 0; i < N; i++) { string str = Console.ReadLine(); if(!dic.ContainsKey(str)) dic.Add(str, 1); else dic[str]++; } int M = int.Parse(Console.ReadLine()); for (int i = 0; i < M; i++) { string str = Console.ReadLine(); if (!dic.ContainsKey(str)) dic.Add(str, -1); else dic[str]--; } var list = dic.ToList(); int max = list.Max(_ => _.Value); if(max > 0) Console.WriteLine(max); else Console.WriteLine(0); } } |