Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions 739. Daily Temperatures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
## step1 とりあえず解く
- 計算量
- 時間:O(N^2)
- 空間:O(N)
- 時間計算量をO(N)にする解決策を思いつけず、安直に全探索

```java
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int[] ans = new int[temperatures.length];
for (int i = 0; i < temperatures.length - 1; i++) {
for (int j = i + 1; j < temperatures.length; j++) {
if (temperatures[i] < temperatures[j]) {
ans[i] = j - i;
break;
}
}
}
return ans;
}
}
```

## step2 他の人の回答を見て気になるところを修正
- 計算量
- 時間: O(N)
- 空間: O(N)
- 単調増加、単調減少するように要素が並べられたStackはMonotonic Stackというらしい
- for文の中にwhile文があるためぱっと見時間計算量がO(N^2)に見えたが、各要素一度しかpop, pushされないためO(N)になる
- 単にstackに積むだけではなく、stackに積む前に積むあたいがstackの一番上の値より大きいか確認する
- 大きければ、stackからpopする
- この一連の動作により単調減少のstackが作れる
- stackに積むのはindexだけでいいかなと思ったが、おそらくわかりやすさのために温度もセットで積んでいる

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

この stack 何が入っているかというと、「日付と温度の組で、その日よりも高温になった日がまだ出てきていないもの、日付の昇順、温度の降順」ですかね。コードがこのことを発見するパズルになっているという言い方もできるでしょう。どういうヒントを与えたら一番そのことに容易に気がつくでしょうか。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

どういうヒントを与えたら一番そのことに容易に気がつくでしょうか。

コード上でヒントを与えるとしたら別コメントで野田さんからいただいた指摘になるのですが、1つ目にstackの中身をRecord型で定義し日付と温度の組であることを分かりやすくすることがあると思います。
2つ目にstackという変数名を変更し、この変数の使われ方を明確化するというのがあるかと思います。

「日付と温度の組で、その日よりも高温になった日がまだ出てきていないもの、日付の昇順、温度の降順」

stackに変わる変数名の候補としては、これら全ての特性を表現するのは難しいと思いつつ下記のような候補があるかと思います。

  • unresolvedTemperatureIndices
    • stackに積まれているものがまだ最終的な答えを持っていないことを明確化できる
    • ただ、stackが温度の降順であるという核心は伝えられない
  • decreasingTemperatureIndices
    • stackが温度の降順である単調スタックということが明確化される

以上から、野田さんに提案いただいたdecreasingTemperatureIndicesが最適なのかなと思いました。

ヒントを与えるなら、という視点から他者にいかにして自分の組んだパズルを理解してもらうかという思考に至り、参考になりました。
ありがとうございますmm

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

私は unresolved 気に入りました。
unresolvedDays くらいで日付のみ載せるなどでもいいかもしれません。

いずれにせよ工夫や趣味で評価はぶれるものですが、パズルのヒントを(コメントも利用しながら)どう与えるか考えれば間違いはないでしょう。(管理しやすいコードにして、エンジニアリングをしやすくするという目的に沿っています。)


```java
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
ArrayDeque<int[]> stack = new ArrayDeque<>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

int[] の 0 番目と 1 番目にどのような値が含まれているのか、やや分かりづらいように感じました。 クラスやレコードクラスを作り、変数名やアクセサメソッド名で、どのような値が含まれているか、読み手にとって分かりやすくするとよいと思いました。

@yamashita-ki yamashita-ki Sep 18, 2025

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ご確認ありがとうございます!
おっしゃる通りでしたmm
なぜかRecordクラスはEntityの定義周りでしか使わないという認識をいただいており、コーディングテストでは使えていませんでした 🙇
試しにrecordクラスで書き直したところ見通しがグッと良くなったので今後に活かしますmm
下記コミットでstep1を修正したものをstep4として実装しました。
Step4でStep1に関していただいた指摘の修正

int[] ans = new int[temperatures.length];

for (int t = 0; t < temperatures.length; t++) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

t という変数名が何を表しているのわかりませんでした。短いスコープで、インデックスを表す 1 文字の変数には i がよく使われると思います。また、もう少しスコープが長くなる場合は、 i ですと何を表すか分かりにくくなると思います。その場合は、 day 等、中にどのような値が含まれているかが分かる英単語・英語句にするとよいと思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ありがとうございますm
temperaturesという配列名から一文字とってきてtとしていました。
自分でも実装中にtとiがごっちゃになってタイポしていたのでそこで気づくべきでした。

その場合は、 day 等、中にどのような値が含まれているかが分かる英単語・英語句にするとよいと思います。

今回は上記コメントでいただき、実装したRecordクラスのフィールド名に合わせてdayとしました。
Step4でStep1に関していただいた指摘の修正

int temperature = temperatures[t];
while (!stack.isEmpty() && temperature > stack.peekLast()[0]) {
int[] pairs = stack.pollLast();
ans[pairs[1]] = t - pairs[1];
}
stack.add(new int[]{temperature, t});
}
return ans;
}
}
```

- 計算量
- 時間: O(N)
- 空間: O(N)
- 上記とは異なり右から(配列の後ろから)みていく方法
- ただ配列を右から見ていくというのが直感的ではない、若干認知負荷が高く感じてしまった

```java
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int length = temperatures.length;
Deque<Integer> stack = new ArrayDeque<>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

stack という変数名からは、中にどのような値が含まれているか分かりにくく感じました。 decreasingTemperatureIndices 等、中に含まれる値を想起しやすい名前を付けるとよいと思います。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

おっしゃる通りですね、、、
既存では変数名からは抽象的なデータ構造しかわからないことは課題だと思いました。
今後安易にstackなど抽象的なデータ構造を変数名とすることは避けようと思います!

int[] result = new int[length];

for (int currentIndex = length - 1; currentIndex >= 0; currentIndex--) {
while (!stack.isEmpty() && temperatures[stack.peek()] <= temperatures[currentIndex]) {
stack.pop();
}

if (!stack.isEmpty()) {
result[currentIndex] = stack.peek() - currentIndex;
}

stack.push(currentIndex);
}

return result;
}
}
```

## step3 3回とく
- step2の配列の左から見ていく方法解いた

```java
class Solution {
public int[] dailyTemperatures(int[] temperatures) {
int[] ans = new int[temperatures.length];
Deque<int[]> stack = new ArrayDeque<>();

for (int t = 0; t < temperatures.length; t++) {
int temperature = temperatures[t];
while (!stack.isEmpty() && stack.peekLast()[1] < temperature) {
int[] pair = stack.pollLast();
ans[pair[0]] = t - pair[0];
}
stack.add(new int[]{t, temperature});
}
return ans;
}
}
```

## step4 いただいた指摘を元に書き直す
- step1で書いたコード関していただいた指摘:
>クラスやレコードクラスを作り、変数名やアクセサメソッド名で、どのような値が含まれているか、読み手にとって分かりやすくするとよいと思いました。
>https://github.com/yamashita-ki/codingTest/pull/10#discussion_r2358390279

>t という変数名が何を表しているのわかりませんでした。短いスコープで、インデックスを表す 1 文字の変数には i がよく使われると思います。また、もう少しスコープが長くなる場合は、 i ですと何を表すか分かりにくくなると思います。その場合は、 day 等、中にどのような値が含まれているかが分かる英単語・英語句にするとよいと思います。
>https://github.com/yamashita-ki/codingTest/pull/10#discussion_r2358402338

- いただいた指摘通り、Record型を新たに定義し、for文の中で使われる変数名を修正する

```java
class Solution {

private record DayTemperature(int day, int temperature) {}

public int[] dailyTemperatures(int[] temperatures) {
Deque<DayTemperature> stack = new ArrayDeque<>();
int[] ans = new int[temperatures.length];

for (int day = 0; day < temperatures.length; day++) {
int temperature = temperatures[day];
while (!stack.isEmpty() && temperature > stack.peekLast().temperature()) {
DayTemperature previousDay = stack.pollLast();
ans[previousDay.day()] = day - previousDay.day();
}
stack.add(new DayTemperature(day, temperature));
}
return ans;
}
}

```