From db1bf388498f609e6f1d8fffecc917c57170180b Mon Sep 17 00:00:00 2001 From: busker <165013324+hiroki-horiguchi-dev@users.noreply.github.com> Date: Sun, 10 May 2026 23:14:39 +0900 Subject: [PATCH] Create 387.md --- hashmap/387.md | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 hashmap/387.md diff --git a/hashmap/387.md b/hashmap/387.md new file mode 100644 index 0000000..96f75de --- /dev/null +++ b/hashmap/387.md @@ -0,0 +1,99 @@ +- 問題: [387. First Unique Character in a String](https://leetcode.com/problems/first-unique-character-in-a-string/) +- コメント集: [387. First Unique Character in a String](https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/mobilebasic#h.hdbcrwo3urck) + - [コメント1](https://discord.com/channels/1084280443945353267/1201211204547383386/1210484389692313610) + - LinkedHashMap を使って解く方針もある、Javaは残念ながら HashMap に保存した順序を保持してくれないが、最後に LinkedHahsMap を頭から走査して value に出現回数が1なら、そのインデックスの番号を返せば即答えになる + - Python は3.7からデフォルトで順序維持される + - [異常入力をどうハンドリングするか?](https://github.com/quinn-sasha/leetcode/pull/15#discussion_r1970861088) + - 異常入力が来た時にこのプログラムがどう言う挙動をするかというと、「返却する値がプログラムの目的と合致しない可能性がある。小文字でかつユニークでかつ最初に出現するもじのインデックスを返すわけではなくなる」 + - じゃあ上記の時にどう言う挙動をしてくれた方がいいんだっけ?を考えると、例外を投げて呼び出し元にハンドリングしてもらうか、異常値として-1を返すか、気にせずそのまま処理する等がある + - 例としてあげた3パターンは当然このメソッドが呼ばれるコンテキストに依存するのでどんなケースがあるか大雑把に考えると、、 + 1. ユーザの入力等 + 2. バッチとかで夜動いている + - なんかがあって、1 はエラーメッセージが出た方が良さそうだから例外投げた方がいいんだろうし、後者は落ちていたほうがいいのだろう。。正解はない。 +- 条件 + - 1 <= s.length <= 10^5 + - s consists of only lowercase English letters. +- 方針 + - HashMap を使う方針 + - 一度、s を走査して、文字と出現回数を登録していく + - 次のループで s を走査しつつ、mapを確認して出現回数が1のものがあればそのまま走査しているindexを返却する +- 時間計算量: `O(N)` ※HashMap 登録時の hash() は基本的に O(K)かかるが、今回は char が一文字であることから O(1)で済む +- 空間計算量: `O(1)` ※制約から、アルファベットは最大26文字なので + +# 1st +- 初期方針 +```java +class Solution { + public int firstUniqChar(String s) { + Map frequency = new HashMap<>(); + for (char character : s) { + frequency.put(character, frequency.getOrDefault(character, 0) + 1); + } + + for (char character : s) { + if (frequency.get(character) == 1) { + return frequency.get(character); + } + } + + return -1; + } +} +``` +- 動くように修正 +```java +class Solution { + public int firstUniqChar(String s) { + Map frequency = new HashMap<>(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + frequency.put(c, frequency.getOrDefault(c, 0) + 1); + } + + for (int i = 0; i < s.length(); i++) { + if (frequency.get(s.charAt(i)) == 1) { + return i; + } + } + + return -1; + } +} +``` + +# Claudeレビュー結果 + +## 387. First Unique Character in a String レビュー + +### 文法・API +- `for (char c : s)` はJavaのStringに対して拡張for文は使えない。`charAt(i)` か `toCharArray()` を使う +- `characterIndex.getValue()` というメソッドは存在しない。`get()` を使う +- `s.get(index)` はStringのメソッドではない。`s.charAt(index)` を使う + +### 計算量 +- 空間計算量は `O(N)` としているが、`s` が小文字アルファベットのみという制約から `frequency` のエントリー数は最大26なので `O(1)` + +### Integer比較 +- `frequency.get(s.charAt(i)) == 1` の `==` はオブジェクトの参照比較になる。1はIntegerキャッシュ範囲内(-128〜127)なのでたまたま動くが、`.equals(1)` を使う方が意図が明確で安全 +- 参考: [Java Language Specification - Boxing Conversion](https://docs.oracle.com/javase/specs/jls/se8/html/jls-5.html#jls-5.1.7) + +# レビューを受けて書き直し +```java +class Solution { + public int firstUniqChar(String s) { + Map frequency = new HashMap<>(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + frequency.put(c, frequency.getOrDefault(c, 0) + 1); + } + + for (int i = 0; i < s.length(); i++) { + if (frequency.get(s.charAt(i)).equals(1)) { + return i; + } + } + + return -1; + } +} +``` \ No newline at end of file