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
178 changes: 178 additions & 0 deletions blind75/array/contains-duplicate/answer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
# 217. Contains Duplicate

## STEP1

### 想定されるユースケース

### 何が分からなかったか?

- 今回は特になし

### 発想 (手作業でやってみる)

* 数字の紙を持った人が一列に並んでいる。
* 先頭から以下の作業を行う。
* 数字と出現回数をノートにメモをする。
* 出現回数が2以上になった場合には、作業を中断し上司にtrueを報告する。
* 上司にfalseを報告する。

```javascript
const containsDuplicate = function(nums) {
const numToCount = new Map()
Copy link

Choose a reason for hiding this comment

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

各文のあとにセミコロンを書くことをおすすめします。

参考までにスタイルガイドへのリンクを貼ります。

https://google.github.io/styleguide/jsguide.html#formatting-semicolons-are-required

Every statement must be terminated with a semicolon.

ただし、上記のスタイルガイドは唯一絶対のルールではなく、複数あるスタイルガイドの一つに過ぎないということを念頭に置くことをお勧めします。また、所属するチームにより何が良いとされているかは変わります。自分の中で良い書き方の基準を持ちつつ、チームの平均的な書き方で書くことをお勧めいたします。

Copy link
Owner Author

Choose a reason for hiding this comment

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

こちらもスタイルガイドにおいて推奨されていることを把握できておりませんでした。
ありがとうございます。

for (const num of nums){
const count = numToCount.get(num) || 0
numToCount.set(num, count + 1)
if (count > 0) {
return true
}
}
return false
};
```

## STEP2

```javascript
const containsDuplicate = function(nums) {
const numToCount = new Map()
for (const num of nums) {
if (numToCount.get(num) !== undefined) {
return true
}
numToCount.set(num, (numToCount.get(num) || 0) + 1)
}
return false
};
```

## STEP3

```javascript
const containsDuplicate = function(nums) {
const numToCount = new Map()
for (const num of nums) {
if (numToCount.get(num) !== undefined) {
Copy link

Choose a reason for hiding this comment

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

numの存在判定をしているので、 Map.prototype.has() を用いる方が自然だと感じました。
あと今回のケースでは問題になりませんが、numToCountに undefined を入れるような場合値が登録されているのかどうか判別できませんね。

$ node
Welcome to Node.js v22.16.0.
Type ".help" for more information.
> var m = new Map();
undefined
> m.set(1, undefined)
Map(1) { 1 => undefined }
> m.get(1)
undefined
> m.get(2)
undefined
> m.has(1)
true
> m.has(2)
false

そもそも存在しているかしか見る必要がないので、Setを用いる方が自然な気はしますが。

Copy link
Owner Author

@syoshida20 syoshida20 Jun 22, 2025

Choose a reason for hiding this comment

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

Map.prototype.has() を用いる方が自然だと感じました。

確かに、set関数でundefined以外の値(boolean)を設定することを前提としたコードになっていますね。
ご指摘の通りだと思いました。

そもそも存在しているかしか見る必要がないので、Setを用いる方が自然な気はしますが。

同じ感想を持ちました!

Choose a reason for hiding this comment

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

私も、出現回数を保持する意図がなく、出現したかどうかだけを見ているので、Setの解法が一番最初に思いつきやすい・読む人にも意図が伝わりやすいかなと思いました!

return true
}
numToCount.set(num, (numToCount.get(num) || 0) + 1)
}
return false
};
```

## 感想

### コメント集を読んで

## 他の人のPRを読んで

- https://github.com/azriel1rf/leetcode-prep/pull/1/

- https://github.com/rihib/leetcode/pull/4/
- setの要素数で比較する方法もある (`*4`)

- https://github.com/erutako/leetcode/pull/5
- Javaでのsortアルゴリズムは、QuickSortの亜種を用いている。

- https://github.com/NobukiFukui/Grind75-ProgrammingTraining/pull/39/

## その他の方法

* (`*1`) For文を2周回す

```javascript
const containsDuplicate = function(nums) {
for (let i=0; i < nums.length; i++) {
Copy link

Choose a reason for hiding this comment

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

二項演算子の両側にスペースを空けることをおすすめします。

https://google.github.io/styleguide/jsguide.html#formatting-horizontal-whitespace

On both sides of any binary or ternary operator.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Google Style Guide でスペースについて書いている記載と場所を把握できておりませんでした。

教えてくださり、ありがとうございます。

for (let j=i+1; j < nums.length; j++) {
if (nums[i] === nums[j]) {
return true
}
}
}
return false
};
```

* (`*2`) ソートして、先頭から前後の値が一致するかを確認する。

```javascript
const containsDuplicate = function(nums) {
nums.sort((a, b) => a - b)
for (let i = 0; i < nums.length - 1; i++) {
if (nums[i] === nums[i + 1]) {
return true
}
}
return false
};
```

- `*3` Mapではなく、Setを使う方法も可能。
出現回数ではなく、出現の有無を保持すれば良いため。

```javascript
const containsDuplicate = function(nums) {
const uniqueNums = new Set()

for (const num of nums) {
if (uniqueNums.has(num)) {
return true
}
uniqueNums.add(num)
}
return false
};
```

- `*4` 重複している場合には、Uniqueな要素数と配列数が一致しなくなることを利用

```javascript
var containsDuplicate = function(nums) {
const uniqueNums = new Set()
for (const num of nums) {
uniqueNums.add(num)
}
// 一致しない ---> 重複あり (回答はTrue)
// 一致する ---> 重複なし (回答はFalse)
return uniqueNums.size !== nums.length
};
```

### コードの良し悪し

numsの配列の長さをNとする。

* 時間計算量は、ハッシュテーブルを使う方法がO(N)で最も優れており、
空間計算量は、For文を2周回す方法、ソートをする方法が優れている。
* 配列が十分に長い際には、ソートをする方法を検討し、
配列が長くない際には、ハッシュテーブルを用いる方法を検討する。

* `*0`
* 時間計算量: O(N)
* 空間計算量: O(N)

* `*1`
* 時間計算量: O(N^2)
* 空間計算量: O(1)

* `*2`
* 時間計算量: O(N log N)
* 空間計算量: O(1)
* Javasciprtにおいては、sort関数はin-placeで行われるため、O(1)の空間計算量で、sortをできる。

Choose a reason for hiding this comment

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

JavaScriptに明るくなく、軽く調べただけの知識で恐縮ですが、JavaScriptにおいてのsort()はブラウザの実装によって異なるため、時間・空間計算量はJavaScriptという括りでは括れなさそうな気がします。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

The time and space complexity of the sort cannot be guaranteed as it depends on the implementation.

はっきりとしたReferenceは軽く調べた限りでは手に入れられなかったのですが、最近のChromeなどはTimsortを使用しているらしく、空間計算量O(1)を保証できないような気がします。


## 調べたこと

- JavaのSort実装
_ https://docs.oracle.com/javase/jp/8/docs/api/java/util/Arrays.html
- https://kluedo.ub.rptu.de/frontdoor/index/index/docId/3463

> 実装にあたっての注意: ソート・アルゴリズムは、Vladimir Yaroslavskiy氏、Jon Bentley氏、およびJoshua Bloch氏によるDual-Pivot Quicksortです。
> このアルゴリズムは、ほかのクイックソート・アルゴリズムではnの2乗のパフォーマンスに低下させる多くのデータ・セットで、
> O(n log(n))のパフォーマンスを提供し、一般的に従来の(1ピボットの) Quicksortの実装よりも高速です。

JavaではSort Algorithmに、Quicksortよりも早いDual Pivot Quick Sortが用いられている。

- Javascriptにおけるsortの実装
- arrayの中身の種類によってソートアルゴリズムが異なるらしい。
- https://stackoverflow.com/questions/234683/javascript-array-sort-implementation