Conversation
|
初めての投稿です。 |
| vector<int> scores; | ||
| int kth; |
There was a problem hiding this comment.
以前野田さんにおすすめされたのですが、「effective c++」にこの辺りのことが記載されておりますので読んでみるといいと思いました。
| scores=nums; | ||
| sort(scores.rbegin(),scores.rend()); | ||
| kth=k; |
There was a problem hiding this comment.
スペースの空け方のルールはなにか統一的なものがあればなんでもいいと思います。
Google Style Guide は一つです。
https://google.github.io/styleguide/cppguide.html
There was a problem hiding this comment.
ありがとうございます。
リンク参考にさせていただきます。
違和感を持たれないようにコードを書くことを心がけます。
| if((int)size(scores)>kth){ | ||
| return scores[kth-1]; | ||
| }else{ | ||
| return scores[kth-1]; | ||
| } |
There was a problem hiding this comment.
これ、条件分岐して同じ式ですね。それだったらまとめていいですが、なんか意図があったんじゃないでしょうか。全体の大きさを小さくするとか。kth より多いときには減らせますね。
(int) もこの場合は不要ですかね。
There was a problem hiding this comment.
すみません。
vectorの要素数がkthよりも大きいことが前提ならば必要ないですが、vectorの要素数がkthより小さいときはエラーを知らせるように書こうとしてました。
教えていただいた通り、vectorの長さを減らすようにします!
| if(canditates.count(nums[i])!=0){ | ||
| canditates[nums[i]]++; | ||
| }else{ | ||
| canditates[nums[i]]=1; |
There was a problem hiding this comment.
アクセスするだけで要素が作られること知りませんでした...
そのような知識はリファレンスを日頃から読んで少しづつ身につけていくのがよいでしょうか。
There was a problem hiding this comment.
https://cpprefjp.github.io/reference/map/map/op_at.html
「対応する要素が存在しない場合は、要素を値初期化して参照を返す。」
そうですね。とりあえず、読みましょう。
だから canditates[nums[i]]++; だけでいいですね。
| if(canditates.begin()->second==1){ | ||
| canditates.erase(canditates.begin()); | ||
| }else{ | ||
| canditates.begin()->second--; | ||
| } |
There was a problem hiding this comment.
ありがとうございます。
条件分岐のelseが1つ減ってわかりやすくなりそうです。
| auto iter=canditates.begin(); | ||
| int ans= iter->first; | ||
| return ans; |
| } | ||
| } | ||
|
|
||
| for(int i=k;i<(int) size(nums);i++){ |
There was a problem hiding this comment.
なんだかfor, if, else文のスペースの開け方に違和感を感じてしまいます.
https://ttsuki.github.io/styleguide/cppguide.ja.html#Formatting_Looping_Branching
こちらにGoogle Coding Style Guideのifのスペースの開け方があります
There was a problem hiding this comment.
違和感を教えていただきありがとうございます。
いただいたリンクに目を通して、少しずつ修正していきます!
|
|
||
| 今度は、時間を測りながら、もう一回、書きましょう。書いてアクセプトされたら文字消してもう一回書く。これを10分以内に一回もエラーを出さずに書ける状態になるまで続ける。3回続けてそれができたらその問題はOK。 | ||
|
|
||
| 実施しました。 No newline at end of file |
|
|
||
| 実施しました。 No newline at end of file | ||
| 実施しました。 | ||
|
|
There was a problem hiding this comment.
step4として、レビューを受けてコードを修正いたしました。
| class KthLargest { | ||
| public: | ||
|
|
||
| map<int,int> canditates; |
There was a problem hiding this comment.
multimap を使っても同様の処理が書けると思います。余裕があれば挑戦してみてください。
There was a problem hiding this comment.
ありがとうございます。
multimapを使用する場合は、keyを問題で与えられた値として、keyの値がmultimap全体の中で何個目であるかをvalueに入れるイメージでしょうか。
There was a problem hiding this comment.
いえ、 multipmap の要素数が k を超えるたびに、一番小さい値を削除していくことになると思います。
There was a problem hiding this comment.
multimapではkey,valueともに同じものが複数存在できるという理解でいいでしょうか。
https://cpprefjp.github.io/reference/map/multimap.html
There was a problem hiding this comment.
multiset教えていただきありがとうございます!
実装のイメージつきました!
| class KthLargest { | ||
| public: | ||
|
|
||
| map<int,int> canditates; |
| } | ||
|
|
||
| auto iter=canditates.begin(); | ||
| int ans= iter->first; |
There was a problem hiding this comment.
ansだと何が格納されているのか分からないので、変数名から何が入っているのか分かるような変数名がいいと思いました。
There was a problem hiding this comment.
ありがとうございます。
kth_numとかがいいかと思いました。
| canditates[nums[i]]++; | ||
| canditates.begin()->second--; | ||
| if (canditates.begin()->second<=0) { | ||
| canditates.erase(canditates.begin()); | ||
| } |
There was a problem hiding this comment.
ありがとうございます。
privateに関数を追加して処理をまとめました。
class KthLargest {
private:
map<int,int> candidates;
int kth;
void add_num_to_candidates(int nums_add){
candidates[nums_add]++;
candidates.begin()->second--;
if (candidates.begin()->second<=0) {
candidates.erase(candidates.begin());
}
}
public:
KthLargest(int k, vector<int>& nums) {
kth=k;
for (int i=0; i<k; i++) candidates[nums[i]]++;
for (int i=k; i<size(nums); i++) add_num_to_candidates(nums[i]);
}
int add(int val) {
add_num_to_candidates(val);
return candidates.begin()->first;
}
};There was a problem hiding this comment.
下のテストケースがパスしないようです。
["KthLargest","add","add","add","add","add"]
[[1,[]],[-3],[-2],[-4],[0],[4]]
There was a problem hiding this comment.
初期配列が空だと
for (int i=0; i<k; i++) candidates[nums[i]]++;
のnums[i]で存在しない要素を呼び出していて、エラーが出るようでした。
for文の実行条件をi<k && i<size(nums)に修正しました。
また、add_num_to_candidatesの中で、配列の数がkthに満たない場合も
加えた値を削除してしまっていたので、candidates_counterの変数を用意して、
要素数がkthより大きい時のみ、削除する処理をするように条件分けしました。
class KthLargest {
private:
map<int,int> candidates;
int candidates_counter=0;
int kth;
void add_num_to_candidates(int nums_add){
candidates[nums_add]++;
candidates_counter++;
if (candidates_counter>kth) {
candidates.begin()->second--;
if (candidates.begin()->second<=0) {
candidates.erase(candidates.begin());
}
}
}
public:
KthLargest(int k, vector<int>& nums) {
kth=k;
for (int i=0; i<k && i<size(nums); i++){
candidates[nums[i]]++;
candidates_counter++;
}
for (int i=k; i<size(nums); i++) add_num_to_candidates(nums[i]);
}
int add(int val) {
add_num_to_candidates(val);
return candidates.begin()->first;
}
};There was a problem hiding this comment.
一回、自然言語にしてみるんですが、重複している感じがしませんか。
kth は、「この KthLargest のインスタンスがいくつまで管理するか」
candidates は、「大きいものから k 個(追加された数が k に満たない場合はすべて)の分布」
candidates_counter は、「消去したものも含めて追加された数」ですね。
add_num_to_candidates は、意味は「数字を追加して candidates の分布を更新」、操作としては「数字を追加し、k を超えていたら一番小さいのを消す」
KthLargest は、意味は「k と nums で初期化」、操作としては「入力の配列に対して、k 番目までは candidates を更新し、それ以降 add_num_to_candidates を呼ぶ」
add は、意味は「数字を追加して、k 番目に大きいものを返す」、操作としては「add_num_to_candidates を呼んで、k 番目を返す」
There was a problem hiding this comment.
個人的には
KthLargest は add_num_to_candidates を nums に対して呼ぶのでよいでしょう。
add_num_to_candidates と add は一緒にしてしまうかもしれません。
candidates_counter は、意味を「中に入っている個数」にして消したら減らしたいです。
There was a problem hiding this comment.
変数、関数ともに自然言語にしてみると、
・addがadd_num_to_candidatesを呼んでるだけになっている。
・KthLargestのk番目とそれ以降で分けていることを、すでにadd_num_to_candidatesで処置している。
ことがよくわかります...
candidates_counterの変数の意味は中に入っている個数という意味で使いたかったのですが、
実装上は違う意味になっていました...
コードを頭の中でミスなく動かす練習をしていきたいです。
以下の通り直してみました。
class KthLargest {
private:
map<int,int> candidates;
int candidates_counter=0;
int kth;
public:
KthLargest(int k, vector<int>& nums) {
kth=k;
for (int i=0; i<size(nums); i++) add(nums[i]);
}
int add(int val) {
candidates[val]++;
candidates_counter++;
if (candidates_counter>kth) {
candidates.begin()->second--;
if (candidates.begin()->second<=0) {
candidates.erase(candidates.begin());
}
candidates_counter--;
}
return candidates.begin()->first;
}
};There was a problem hiding this comment.
いいかと思います。
削除の際のcandidates.begin()は三回繰り返しているので変数においてもいいかもしれませんね。
他に気になるのは、スタイル(演算子の前後にスペースをいれるか、ぶら下がり for を使うか、インクリメント・デクリメントは前置が好きか、など)ですが、趣味の範囲です。
<問題>
https://leetcode.com/problems/kth-largest-element-in-a-stream/