' P '

whatever I will forget

Java HashMap(連想配列)

すっげー適当なHashMapに対するメモを昔に書いてました。。

mankozooyork.hatenablog.com

この問題  

atcoder.jp

連想配列使ったほうがいいよとなってたのでチャレンジしてみました。
まーいつも通り小一時間悩んだんですが(ダブルループなんてしないでcontains()をすぐに思い浮かべられたら..と悔いが残ります。)

自分のクソロジックで申し訳ないですが一応自分なりに解けたのでメモ

考えたこと

  • st、それぞれの配列でいくつ重複した値があるのかを与えられたStringをキーとしてHashMapをつくる
  • tで与えられた配列の中にsとマッチする値があればsの重複値 - tの重複カウントを求める
  • tで与えられた配列の中にsとマッチしない値があれば、そのsの値の重複カウントを求める
  • 最大値の重複カウントが答え

HashMap

宣言は基本的には下記でいいはず(String, intを格納する場合)

import java.util.Map;
import java.util.HashMap;
Map<String, Integer> map = new HashMap<>();

ランクBくらいであれば基礎的な使い方だけ知っていればいいと勝手に思っておきます。

https://style.potepan.com/articles/16280.html

この記事もタメになりました。

Mapではダメで どうしてもHashMapのメソッドを使わないといけない
あるいは使った方が実装が楽、という場合に限り
HashMap map = new HashMap()と記述する。

topickup.web.fc2.com

リストに存在する重複値のカウント

これもぜひ覚えておきたいなーと思いました。基本はHashSetとセットで使う気がしている。

import java.util.Collections;
import java.util.Set;
import java.util.HashSet;
import java.util.ArrayList;

ArrayList<String> arrayList = {"a", "a", "b", "c"};
Set<String> set = new HashSet<>(arrayList);
for(String s: set) {
  map.put(s, Collections.frequency(arrayList, s));
}

今回は各String値をキーとして、HashMapにぶっ込みました。

www.geeksforgeeks.org

Sample

import java.util.Scanner;
import java.util.ArrayList;
import java.util.Set;
import java.util.HashSet;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;

public class Main45 {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        sc.nextLine();
        ArrayList<String> s = new ArrayList<>();
        for(int i=0; i<n; i++) {
            s.add(sc.nextLine());
        }

        int m = sc.nextInt();
        sc.nextLine();
        ArrayList<String> t = new ArrayList<>();
        for(int j=0; j<m; j++) {
            t.add(sc.nextLine());
        }

        Set<String> setS = new HashSet<>(s);
        Set<String> setT = new HashSet<>(t);

        Map<String,Integer> mapS = new HashMap<>();
        for(String str: setS) {
            mapS.put(str, Collections.frequency(s, str));
        }

        Map<String,Integer> mapT = new HashMap<>();
        for(String str: setT) {
            mapT.put(str, Collections.frequency(t, str));
        }

        int count = 0;
        int currentCount = 0;
        for(String str: setS) {
            if(setT.contains(str)) {
                count = mapS.get(str) - mapT.get(str);
            } else {
                count = mapS.get(str);
            }
            if(currentCount < count) {
                currentCount = count;
            }
        }

        System.out.println(currentCount);
        sc.close();
    }
}

追記 5/26

上記問題もおさらいしてて、長いコード書くのだるってなったのでもう少し簡潔にできないか探っていたところ... Set/HashSetのくだりをどうにか削れないかと調べました。
すると、いきなりInputからMapに放り込んでる人がいて、なるほどそうだよなと思ったので追記です。

  • containsKey()でMapの中にキーがあるかどうか探せる
        Map<String, Integer> s = new HashMap<>();
        for(int i=0; i<n; i++) {
            String str = sc.nextLine();
            if(s.containsKey(str)) {
                s.put(str, s.get(str)+1);
            } else {
                s.put(str, 1);
            }
        }

Mapのfor eachループのやり方

基本的には3通りあるらしい。

  • entrySet() : オフィシャルっぽい。(Map<String, Integer> entry: s.entrySet()){
  • keySet() : ループさせるMapに含まれるkeyを元にループ、valueを取り出したいときにおすすめ?
  • valueSet() : ループさせるMapに含まれるvalueを元にループ、keyを取り出したいときにおすすめ?(これは例があまりなかった)
for(String str: s.keySet()) {
//
}

stackoverflow.com