-
Notifications
You must be signed in to change notification settings - Fork 0
Create 387.First Unique Character in a String.md #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,178 @@ | ||||||
| //STEP1 | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 本筋とは関係ないですが、Markdownの記法に従っておくとレンダリングしたときに見やすいです。
Suggested change
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 返信が遅くなり、大変失礼いたしました。 |
||||||
|
|
||||||
| ■手作業でどうやるか? | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 手作業でやってみる、いいですね 👍 |
||||||
|
|
||||||
| 例:loveleetcode | ||||||
|
|
||||||
| l→後ろの文字を一つずつ見ていく。だめ | ||||||
|
|
||||||
| o→後ろの文字を一つずつ見ていく。だめ | ||||||
|
|
||||||
| v→後ろの文字を一つずつ見ていく。OK | ||||||
|
|
||||||
| 重複を見つけたらNGの文字一覧に放り込んで行く。 | ||||||
|
|
||||||
| もしNG一覧にあれば、その文字は調べず、次の文字の重複チェックをする。 | ||||||
|
|
||||||
| もしNG一覧になければ、その要素より後を調べる。 | ||||||
|
|
||||||
| NGリストはsetにすればいいかな? | ||||||
|
|
||||||
|
|
||||||
|
|
||||||
| ```java | ||||||
| class Solution { | ||||||
| public int firstUniqChar(String s) { | ||||||
| Set<Character> repeating = new HashSet<>(); | ||||||
| int n = s.length(); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nは定義せずに済ませても良いのではないかと思いました(好みの範囲かもしれません)
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 返信遅くなり、大変失礼いたしました。 |
||||||
| for (int i = 0; i < n; i++) { | ||||||
| char c = s.charAt(i); | ||||||
|
Comment on lines
+26
to
+29
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 最初に読んだ際に repeating が何を表しているのかが不明瞭であるように感じました。おそらく repeating と duplicated が、どちらも「重複」という同じ意味だが違う表現になっていることが原因だと思います。 命名としては seen などをよく見るので、repeating の代わりにこちらもご検討ください。 また、duplicated という命名の Set を持ってしまって、if (!duplicated) の部分をフラグではなく、if (!duplicated.contains(c))として、Set で条件分岐を行うのもありかなと思いました。 以下参考まで。 class Solution {
public int firstUniqChar(String s) {
Set<Character> duplicated = new HashSet<>();
int n = s.length();
for (int i = 0; i < n; i++) {
char c = s.charAt(i);
if (duplicated.contains(c)) {
continue;
}
for (int j = i + 1; j < n; j++) {
if (c == s.charAt(j)) {
duplicated.add(c);
break;
}
}
if (!duplicated.contains(c)) {
return i;
}
}
return -1;
}
}
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 返信が遅くなり、大変失礼いたしました。 |
||||||
| if (repeating.contains(c)) { | ||||||
| continue; | ||||||
| } | ||||||
| boolean duplicated = false; | ||||||
| for (int j = i + 1; j < n; j++) { | ||||||
| if (c == s.charAt(j)) { | ||||||
| repeating.add(c); | ||||||
| duplicated = true; | ||||||
| break; | ||||||
| } | ||||||
| } | ||||||
| if (!duplicated) { | ||||||
| return i; | ||||||
| } | ||||||
| } | ||||||
| return -1; | ||||||
| } | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| ■メモ | ||||||
|
|
||||||
| 初歩的で大変お恥ずかしいですが、 | ||||||
|
|
||||||
| やりたいことは構文的なところの知識が足りなかったので、実装がうまくできず | ||||||
|
|
||||||
| chatGPTにやりたいことをきれいに実装してもらった後、不明点を調べました。 | ||||||
|
|
||||||
| わからないところ、感想など | ||||||
|
|
||||||
| ・配列のようにインデックスを指定してString中の文字を取得したい | ||||||
|
|
||||||
| →インデックスを指定してStringのchar値を返すメソッド charAt | ||||||
|
|
||||||
| https://docs.oracle.com/javase/jp/8/docs/api/java/lang/String.html#charAt-int- | ||||||
|
|
||||||
| ・boolean duplicatedで重複のあるなしを管理しているのは、 | ||||||
|
|
||||||
| 自分で考えていた時は思いつかなかったが、見やすくていいなと思った。 | ||||||
|
|
||||||
| ・計算量について | ||||||
|
|
||||||
| 時間計算量は、O(N^2) (二重のforループ) | ||||||
|
|
||||||
| 空間計算量は、O(N) (重複文字数に比例してメモリが必要) | ||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
| //STEP2 | ||||||
|
|
||||||
| ■ほかの人の解答を読む | ||||||
|
|
||||||
| Leetcodeの解答例 | ||||||
|
|
||||||
| ```java | ||||||
| class Solution { | ||||||
| public int firstUniqChar(String s) { | ||||||
| int[] c=new int[26]; | ||||||
| for(int i=0;i<s.length();i++){ | ||||||
| c[s.charAt(i)-'a']++; | ||||||
| } | ||||||
| for(int i=0;i<s.length();i++){ | ||||||
| if(c[s.charAt(i)-'a']==1) | ||||||
| return i; | ||||||
| } | ||||||
| return -1; | ||||||
| } | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| 手作業で表現するなら、 | ||||||
|
|
||||||
| ①文字の表を作り、出現回数を記録する。 | ||||||
|
|
||||||
| ②文字列の順に表を確認し、最初に出現回数1が出てきたらそこでインデックスを返す。 | ||||||
|
|
||||||
| 計算量は以下の通りで、こちらの方が速くて省メモリ。 | ||||||
|
|
||||||
| 時間計算量は、O(N) (forループ2回) | ||||||
|
|
||||||
| 空間計算量は、O(1) (26文字分のメモリが必要) | ||||||
|
|
||||||
|
|
||||||
|
|
||||||
| 入力の文字列が英小文字26字という前提があるので、 | ||||||
|
|
||||||
| 26字分のサイズの配列しか用意しないのは計算量の観点でエコだと思った。 | ||||||
|
|
||||||
| 配列のインデックスの計算にc[s.charAt(i)-'a']ができるというのは、初めて知った。 | ||||||
|
|
||||||
| 調べたところ、javaでは文字を数字として扱うことができるから、このような書き方ができるということだった。 | ||||||
|
|
||||||
| ただし、もし入力値に英小文字以外が含まれていた場合、エラーとなる。 | ||||||
|
|
||||||
| 入力値が英小文字になるよう完全にコントロールできるか、エラーの処理を追加してあげれば、 | ||||||
|
|
||||||
| 大量の入力値や、とても長い入力値でも処理が速く、空間計算量も少ないので、効率的に動くと思う。 | ||||||
|
|
||||||
|
|
||||||
|
|
||||||
| 一方でこちらの解答 | ||||||
|
|
||||||
| https://github.com/kazukiii/leetcode/pull/16/files#diff-ab5f3d992bba7dfdbae5fb89c6211844968879aaa279be404afd515fc3d9229d | ||||||
|
|
||||||
| 同じやり方で処理を行っているが、配列ではなくMapを用いている。 | ||||||
|
|
||||||
| もし英小文字以外が入力値に入ってきた場合にも対応可能。 | ||||||
|
|
||||||
| 上記のC++の解答ではunordered_mapを使用しているが、javaではmapは最初からunorderedということなので、今回は気にしなくてよさそう。 | ||||||
|
|
||||||
| https://stackoverflow.com/questions/7792523/hashmap-gives-an-unordered-list-of-values | ||||||
|
Comment on lines
+140
to
+142
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 何を気にしているのか次第ですが、私の場合、この箇所を読んだときに Javaに詳しくないので調べてみました。 https://developer.android.com/reference/java/util/HashMap
https://developer.android.com/reference/java/util/LinkedHashMap
ちなみに、keyをソートしてくれる
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Java は TreeMap と HashMap があって、C++ の map と unordered_map に大まかに対応しています。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. mamo3grさん、odaさん |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
| https://github.com/t0hsumi/leetcode/pull/15#discussion_r1930362913 | ||||||
|
|
||||||
| 重複がないことの証明として、「左から読んだときと右から読んだときで、添字が変わらない」ことを使う方法があるとのこと。 | ||||||
|
|
||||||
| このやり方もスマートな感じがした。面白そうなので、時間があれば自分で書いてみたい。 | ||||||
|
|
||||||
| 今は、一つの問題にずっと取り組むより、いろいろな問題に触れることを優先しようと思うので、とりあえずメモに残す。 | ||||||
|
|
||||||
|
|
||||||
|
|
||||||
| //STEP3 | ||||||
|
|
||||||
| Mapのメソッドなどを調べつつSTEP2で見た方法を自分で実装する。 | ||||||
|
|
||||||
| ```java | ||||||
| class Solution { | ||||||
| public int firstUniqChar(String s) { | ||||||
| Map<Character, Integer> counter = new HashMap<>(); | ||||||
| for (int i = 0; i < s.length(); i++) { | ||||||
| counter.put(s.charAt(i), counter.getOrDefault(s.charAt(i), 0) + 1); | ||||||
| //ここは、counters.merge(s.charAt(i), 1, (oldValue, newValue) -> oldValue + newValue); | ||||||
| //でも同じことが可能。 | ||||||
| //ラムダ式というものらしい。 | ||||||
| } | ||||||
| for (int i = 0; i < s.length(); i++) { | ||||||
| if (counter.get(s.charAt(i)) == 1) { | ||||||
| return i; | ||||||
| } | ||||||
| } | ||||||
|
Comment on lines
+170
to
+174
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LinkedHashMap というものはあります。 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LinkedHashMap は、個人的には知らなくてもいいんですが、しかし、面接ではよく聞かれます。 |
||||||
| return -1; | ||||||
| } | ||||||
| } | ||||||
| ``` | ||||||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[IMO] コードとは関係ないのですが、ディレクトリ名やファイル名に
(スペース)を入れるのは好みではありません。CLIなどでエスケープが必要だったりと実務上の手間が増えるからです。私はKth_Largest_Element_in_a_Stream/memo.mdみたいな感じで
_を入れてます。There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
返信が遅くなり、大変失礼いたしました。
ファイル名の作法があまりわかっていませんでしたが
いろいろとデメリットがありそうですね。
次からは、スペースは使わず_を使用しようと思います。
レビューいただきありがとうございます。