Conversation
| class KthLargest { | ||
| private final int k; | ||
| private TreeMap<Integer, Integer> scores; | ||
| private int scoreCount; |
There was a problem hiding this comment.
自分なら numScores と名付けると思います。チームの平均的な書き方に合わせることをお勧めいたします。
There was a problem hiding this comment.
ありがとうございます。たしかにそうですね。意識してみます。
| ## Step 3 | ||
|
|
||
| 今度は、時間を測りながら、もう一回書く。 | ||
| アクセプトされたら消すを 3 回連続できたら問題は OK。 |
| - > 平衡二分木が C++ だったら map があり、これは順番に並んでいます。 | ||
| - 平衡二分探索木 | ||
| - https://ja.wikipedia.org/wiki/%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8 | ||
| - Java だと TreeMap がそれに当たるっぽい(赤黒木) |
There was a problem hiding this comment.
この問題を解いたことないところからの質問失礼します。
上記priority_queueとmapの議論も読ませてもらったのですが、問題の要求的に
1.どうやってk番目の順位のスコアを知るか
2.新しいスコアが入ってきたときの適切な更新
の2つの要求があって、1と2どちらも解決できるデータ構造としてpriority_queueとmapどっちがいいか(まずよく使われるMapを思い出してもいいのでは)という議論だと認識してます。
しかしもっと単純にもしそれらのライブラリを知らなかったら、1を求めるために最初はソートでk番目のスコアを求める、それを保持しつつ新しいスコアと比べて更新するとかでもこの問題は問題ないのでしょうか
There was a problem hiding this comment.
コメントありがとうございます。仰るとおりコメントいただいた解法でも問題ないと思います。
以下に追加実装してみました。
https://github.com/katsukii/leetcode/pull/23/files#diff-2cbd596e05763f14077e25b7a93421a6edb70d86913362e022332db1f0073c34R179
| } else { | ||
| int kthScore = scores.firstKey(); | ||
| if (val > kthScore) { | ||
| scores.put(val, scores.getOrDefault(val, 0) + 1); |
There was a problem hiding this comment.
私はこの put と getOrDefault を一行に書くのは好みではないです。
2回 val が出てきて、あと目が左右に振られますね。
https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.kqo7dp4vlnzh
val を2回書かないならば compute を使うようなのもありますが、素直に2行にするのも一つです。
https://discord.com/channels/1084280443945353267/1300342682769686600/1357629082069893221
There was a problem hiding this comment.
たしかに素直に2行にした方が断然わかりやすいですね。今後そうします。
| } | ||
|
|
||
| public int add(int val) { | ||
| if (scores.size() < k) { |
There was a problem hiding this comment.
このif-else if文を読んでいて、elseのケースが大丈夫なのかなというのを考えるのに少し時間が取られたのでもう少し素直に書ける余地があるかなと思います。
とりあえずqueuに突っ込んでしまって、要素がサイズを超えていれば、減らしてあげるみたいな感じのほうがシンプルかなと個人的には思います。
public int add(int val) {
scores.offer(val);
if (scores.size() > k) {
scores.poll();
}
return scores.peek();
}There was a problem hiding this comment.
たしかにこちらの方が分かりやすいです。ありがとうございます。
| int kthScore = scores.firstKey(); | ||
| if (val > kthScore) { | ||
| scores.put(val, scores.getOrDefault(val, 0) + 1); | ||
| scoreCount++; |
There was a problem hiding this comment.
こことL128のコードが不要ですね。ソースコードを書いていて結果的に不要になった感じですかね。
| sortedList.add(insertPosition, val); | ||
|
|
||
| if (sortedList.size() > k) { | ||
| sortedList.remove(0); |
There was a problem hiding this comment.
L237でbinarySearchを使っているのは、この配列がソート済みなことを利用してO(log(k))で要素を追加したいということなのかなと思うのですが、結局ここで配列の先頭要素を削除しているので、O(k)になっていると思います(削除後に左詰めされるのでそこで線形に時間が掛かる)。
https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html
All of the other operations run in linear time (roughly speaking).
There was a problem hiding this comment.
ジャストアイデアですが、降順にソートしてあげて削除は末尾要素にすれば解決するかなと思いました。
There was a problem hiding this comment.
ご指摘ありがとうございます。おっしゃるとおりO(k)ですね。
降順にソートしてあげて削除は末尾要素にすれば解決するかなと思いました。
たしかに、削除の部分の時間計算量は削除がO(1)になるため平均時間計算量はマシになりますね。sortedList.add(insertPosition, val); が相変わらずシフトするので最悪時間計算量はO(k)のままですが。
問題
https://leetcode.com/problems/kth-largest-element-in-a-stream/
言語
Java
次の問題
Top K Frequent Elements