chore(i18n,learn): processed translations (#44851)
This commit is contained in:
@ -0,0 +1,191 @@
|
||||
---
|
||||
id: 587d8257367417b2b2512c7b
|
||||
title: 二分探索木に新しい要素を追加する
|
||||
challengeType: 1
|
||||
forumTopicId: 301618
|
||||
dashedName: add-a-new-element-to-a-binary-search-tree
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
この一連のチャレンジでは、ツリーデータ構造について学びます。 木 (ツリー) は、コンピュータサイエンスにおいて重要かつ汎用的なデータ構造です。 もちろん名称の由来は、そのデータ構造を視覚化すると自然界の木に似ていることです。 ツリーデータ構造は、一般に「根」と呼ばれる 1 つのノードで始まり、ここから追加のノードに枝分かれします。それぞれのノードがいくつかの子ノードに枝分かれし、その子ノードがさらに枝分かれしていきます。 データ構造を視覚化する際、通常は根ノードを一番上に置くので、木を逆さにした状態と考えることができます。
|
||||
|
||||
最初に、木に関してよく使われる用語について説明します。 「根ノード」は木の一番上にあります。 木の中のデータポイントは「ノード」と呼ばれます。 他のノードにつながる枝を持つノードは、枝の先にあるノード (子) の親と呼ばれます。 他に複雑な関連用語がありますが、それぞれ言葉通りの意味です。 「部分木」は特定ノードのすべての子孫を指し、枝は「エッジ」と呼ばれることもあります。「葉ノード」は、子を持たず木の末端にあるノードです。 最後に、木は本質的に再帰的なデータ構造であることに注目してください。 つまり、あるノードの子はそれが持つ部分木の親でもあり、それが子孫で繰り返されていきます。 木に対する一般的な操作のアルゴリズムを設計する際には、木の再帰性を理解することが重要です。
|
||||
|
||||
最初に、特別な種類の木 (二分木) について説明します。 実際には、特別な二分木である「二分探索木」についてです。 これが何を意味するのかを以下に説明します。 ツリーデータ構造では 1 つの ノードが何本でも枝を持てますが、二分木ではすべてのノードに枝が 2 本しかありません。 さらに二分探索木では、左部分木の各ノードの値が親ノードの値以下になり、右部分木の各ノードの値が親ノードの値以上になるという形で、子部分木を基準にして順序が決まります。 視覚化すると、この関係は一目瞭然です。
|
||||
|
||||
<div style='width: 100%; display: flex; justify-content: center; align-items: center;'><img style='width: 100%; max-width: 350px; background-color: var(--gray-05);' src='https://user-images.githubusercontent.com/18563015/32136009-1e665d98-bbd6-11e7-9133-63184f9f9182.png'></div>
|
||||
|
||||
これで、順序付けの関係が簡単に分かります。 注目すべき点は、根ノードである 8 の左側の値はすべて 8 より小さく、右側の値はすべて 8 より大きいということです。 また、この関係がそれぞれの部分木にも当てはまるという点に注意してください。 例えば、左側にある最初の子は部分木です。 3 は親ノードであり、ちょうど 2 つの子ノードを持っています。二分探索木のルールにより、このノードの左側の子 (およびそのすべての子) は 3 より小さく、右側の子 (およびそのすべての子) は 3 よりも大きい (ただし、この構造の根の値よりも小さい) ということは、もう見なくても分かります。
|
||||
|
||||
二分探索木は、検索、挿入、削除などの一般的な操作の平均ケースで対数時間計算量なので、非常によく使われる便利なデータ構造です。
|
||||
|
||||
# --instructions--
|
||||
|
||||
シンプルなもので始めましょう。 ここでは、木のノードを作成する関数に加えて、二分探索木構造のスケルトンを定義してあります。 各ノードの左右に値があることを確認してください (ない場合もあります)。 それらには子部分木が割り当てられます (それらが存在する場合)。 ここで、この二分探索木に新しい値を追加するメソッドを作成してください。 そのメソッドは `add` と呼ばれ、木に追加する整数値を受け入れる必要があります。 二分探索木の不変条件を必ず守ってください。つまり、左側のそれぞれの子の値は親値以下、右側のそれぞれ子の値は親値以上でなければなりません。 ここでは、ツリーが重複値を保持できないようにしましょう。 既に存在する値を追加しようとした場合、メソッドから `null` が返される必要があります。 それ以外の場合、追加が成功したら `undefined` が返される必要があります。
|
||||
|
||||
**ヒント:** 木は本質的に再帰的なデータ構造です!
|
||||
|
||||
# --hints--
|
||||
|
||||
`BinarySearchTree` データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `add` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.add == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
add メソッドは二分探索木のルールに従って要素を追加する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.add !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(4);
|
||||
test.add(1);
|
||||
test.add(7);
|
||||
test.add(87);
|
||||
test.add(34);
|
||||
test.add(45);
|
||||
test.add(73);
|
||||
test.add(8);
|
||||
const expectedResult = [1, 4, 7, 8, 34, 45, 73, 87];
|
||||
const result = test.inOrder();
|
||||
return expectedResult.toString() === result.toString();
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
既に存在する要素を追加すると、`null` が返される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.add !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(4);
|
||||
return test.add(4) == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
BinarySearchTree.prototype = Object.assign(
|
||||
BinarySearchTree.prototype,
|
||||
{
|
||||
inOrder() {
|
||||
if (!this.root) {
|
||||
return null;
|
||||
}
|
||||
var result = new Array();
|
||||
function traverseInOrder(node) {
|
||||
node.left && traverseInOrder(node.left);
|
||||
result.push(node.value);
|
||||
node.right && traverseInOrder(node.right);
|
||||
}
|
||||
traverseInOrder(this.root);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
this.add = function(element) {
|
||||
let current = this.root;
|
||||
if (!current) {
|
||||
this.root = new Node(element);
|
||||
return;
|
||||
} else {
|
||||
const searchTree = function(current) {
|
||||
if (current.value > element) {
|
||||
if (current.left) {
|
||||
return searchTree(current.left);
|
||||
} else {
|
||||
current.left = new Node(element);
|
||||
return;
|
||||
}
|
||||
} else if (current.value < element) {
|
||||
if (current.right) {
|
||||
return searchTree(current.right);
|
||||
} else {
|
||||
current.right = new Node(element);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
return searchTree(current);
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
@ -0,0 +1,161 @@
|
||||
---
|
||||
id: 587d8252367417b2b2512c67
|
||||
title: リンクリストの特定のインデックスに要素を追加する
|
||||
challengeType: 1
|
||||
forumTopicId: 301619
|
||||
dashedName: add-elements-at-a-specific-index-in-a-linked-list
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
与えられたインデックスの位置に要素を追加する addAt(index,element) メソッドを作成しましょう。 与えられたインデックスの位置にある要素を削除する方法と同様に、リンクリストを走査する際に currentIndex を追跡する必要があります。 currentIndex と与えられたインデックスとが一致する場合、前のノードの next プロパティを再び割り当て、追加された新しいノードを参照する必要があります。 新しいノードは、currentIndex 内の次のノードを参照する必要があります。 コンガラインの例に戻りましょう。新しい人がラインの途中に加わりたいと考えています。 あなたは列の途中にいるので、自分の手を前の人から離します。 新しい人が歩いてきて、今まであなたが手を置いていた人に手を置きます。そしてあなたは新しい人に手を置きます。
|
||||
|
||||
# --instructions--
|
||||
|
||||
与えられたインデックスの位置に要素を追加する `addAt(index,element)` メソッドを作成してください。 要素を追加できなかった場合は false を返してください。 **注:** 与えられたインデックスが負であるか、リンクリストの長さよりも長いかを必ず調べてください。
|
||||
|
||||
# --hints--
|
||||
|
||||
与えられたインデックスが 0 の場合、`addAt` メソッドは `head` を新しいノードに再割り当てする必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.addAt(0, 'fish');
|
||||
return test.head().element === 'fish' && test.head().next.element === 'cat';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`addAt` メソッドは、リンクリストに新しいノードが追加されるたびに、リンクリストの長さを 1 ずつ増やす必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.addAt(0, 'cat');
|
||||
return test.size() === 3;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`addAt` メソッドは、ノードを追加できなかった場合に `false` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
return test.addAt(4, 'cat') === false;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function LinkedList() {
|
||||
var length = 0;
|
||||
var head = null;
|
||||
|
||||
var Node = function(element) {
|
||||
this.element = element;
|
||||
this.next = null;
|
||||
};
|
||||
|
||||
this.size = function() {
|
||||
return length;
|
||||
};
|
||||
|
||||
this.head = function() {
|
||||
return head;
|
||||
};
|
||||
|
||||
this.add = function(element) {
|
||||
var node = new Node(element);
|
||||
if (head === null) {
|
||||
head = node;
|
||||
} else {
|
||||
var currentNode = head;
|
||||
|
||||
while (currentNode.next) {
|
||||
currentNode = currentNode.next;
|
||||
}
|
||||
|
||||
currentNode.next = node;
|
||||
}
|
||||
length++;
|
||||
};
|
||||
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function LinkedList() {
|
||||
var length = 0;
|
||||
var head = null;
|
||||
|
||||
var Node = function(element){
|
||||
this.element = element;
|
||||
this.next = null;
|
||||
};
|
||||
|
||||
this.size = function(){
|
||||
return length;
|
||||
};
|
||||
|
||||
this.head = function(){
|
||||
return head;
|
||||
};
|
||||
|
||||
this.add = function(element){
|
||||
var node = new Node(element);
|
||||
if (head === null){
|
||||
head = node;
|
||||
} else {
|
||||
var currentNode = head;
|
||||
|
||||
while (currentNode.next) {
|
||||
currentNode = currentNode.next;
|
||||
}
|
||||
|
||||
currentNode.next = node;
|
||||
}
|
||||
length++;
|
||||
};
|
||||
this.addAt = function (index, element) {
|
||||
if (index > length || index < 0) {
|
||||
return false;
|
||||
}
|
||||
var newNode = new Node(element);
|
||||
var currentNode = head;
|
||||
if (index === 0) {
|
||||
head = newNode;
|
||||
} else {
|
||||
var previousNode = null;
|
||||
var i = 0;
|
||||
while (currentNode && i < index) {
|
||||
previousNode = currentNode;
|
||||
currentNode = currentNode.next;
|
||||
i++;
|
||||
}
|
||||
previousNode.next = newNode;
|
||||
}
|
||||
newNode.next = currentNode;
|
||||
length++;
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,91 @@
|
||||
---
|
||||
id: 587d8256367417b2b2512c77
|
||||
title: 隣接リスト
|
||||
challengeType: 1
|
||||
forumTopicId: 301620
|
||||
dashedName: adjacency-list
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
グラフはさまざまな方法で表すことができます。 ここでは、<dfn>隣接リスト</dfn>と呼ばれる方法について説明します。 隣接リストは基本的に箇条書きリストで、左側がノードであり、右側にはそのノードが接続されている他のすべてのノードが列挙されます。 隣接リストの表現を次に示します。
|
||||
|
||||
<blockquote>Node1: Node2, Node3<br>Node2: Node1<br>Node3: Node1</blockquote>
|
||||
|
||||
上のリストでは、`Node1` が `Node2` と `Node3` に接続されており、その情報は `Node2` と `Node3` が示す接続と一致しているので、無向グラフです。 有向グラフの隣接リストとは、リストの各行が方向を示しているリストのことです。 これが有向グラフであった場合、`Node2: Node1` とは、そこでは有向エッジ (枝) が `Node2` から `Node1` へ向かっているという意味です。 JavaScript オブジェクトの中に入れることで、上の無向グラフを隣接リストとして表すことができます。
|
||||
|
||||
```js
|
||||
var undirectedG = {
|
||||
Node1: ["Node2", "Node3"],
|
||||
Node2: ["Node1"],
|
||||
Node3: ["Node1"]
|
||||
};
|
||||
```
|
||||
|
||||
これは、ノードが文字列ラベルではなく数字だけを持つ配列として、より単純に表現することもできます。
|
||||
|
||||
```js
|
||||
var undirectedGArr = [
|
||||
[1, 2], // Node1
|
||||
[0], // Node2
|
||||
[0] // Node3
|
||||
];
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
`James`、`Jill`、`Jenny`、`Jeff` という 4 つ (4人) のノードを持つ無向グラフとしてソーシャルネットワークを作成してください。 James と Jeff の間、Jill と Jenny の間、および Jeff と Jenny の間にはエッジ / 関係があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
`undirected AdjList` には 4 つのノードのみが含まれている必要があります。
|
||||
|
||||
```js
|
||||
assert(Object.keys(undirectedAdjList).length === 4);
|
||||
```
|
||||
|
||||
`Jeff` と `James` の間にはエッジが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
undirectedAdjList.James.indexOf('Jeff') !== -1 &&
|
||||
undirectedAdjList.Jeff.indexOf('James') !== -1
|
||||
);
|
||||
```
|
||||
|
||||
`Jill` と `Jenny` の間にはエッジが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
undirectedAdjList.Jill.indexOf('Jenny') !== -1 &&
|
||||
undirectedAdjList.Jenny.indexOf('Jill') !== -1
|
||||
);
|
||||
```
|
||||
|
||||
`Jeff` と `Jenny` の間にはエッジが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
undirectedAdjList.Jeff.indexOf('Jenny') !== -1 &&
|
||||
undirectedAdjList.Jenny.indexOf('Jeff') !== -1
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var undirectedAdjList = {};
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var undirectedAdjList = {
|
||||
James: ['Jeff'],
|
||||
Jill: ['Jenny'],
|
||||
Jenny: ['Jill', 'Jeff'],
|
||||
Jeff: ['James', 'Jenny']
|
||||
};
|
||||
```
|
@ -0,0 +1,108 @@
|
||||
---
|
||||
id: 587d8256367417b2b2512c78
|
||||
title: 隣接行列
|
||||
challengeType: 1
|
||||
forumTopicId: 301621
|
||||
dashedName: adjacency-matrix
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
グラフを表すもう一つの方法は、<dfn>隣接行列</dfn>に入れることです。 <dfn>隣接行列</dfn>は二次元 (2D) 配列で、入れ子になった各配列は外側の配列と同じ数の要素を持っています。 言い換えれば、数字の行列または格子であり、数字はエッジ (枝) を表します。
|
||||
|
||||
**注**: 行列の上と左の数字は、ノードの単なるラベルです。 行列内の 1 は、行と列を表す頂点 (ノード) の間にエッジが存在することを意味します。 最後に、0 はエッジ (関係) がないことを意味します。
|
||||
|
||||
<pre>
|
||||
1 2 3
|
||||
\------
|
||||
1 | 0 1 1
|
||||
2 | 1 0 0
|
||||
3 | 1 0 0
|
||||
</pre>
|
||||
|
||||
上記は非常にシンプルな無向グラフで、3 つのノードがあり、最初のノードが 2 番目と 3 番目のノードに接続されています。 下記は、同じことを JavaScript で実装したものです。
|
||||
|
||||
```js
|
||||
var adjMat = [
|
||||
[0, 1, 1],
|
||||
[1, 0, 0],
|
||||
[1, 0, 0]
|
||||
];
|
||||
```
|
||||
|
||||
隣接リストとは異なり、行列の各「行」は、グラフ内のノードと同じ数の要素を持たなければなりません。 これは 3 × 3 の行列であり、つまりグラフに 3 つのノードがあります。 有向グラフもこれに似ています。 下のグラフでは、最初のノードは 2 番目のノードに向かうエッジを持ち、2 番目のノードは 3 番目のノードに向かうエッジを持っています。
|
||||
|
||||
```js
|
||||
var adjMatDirected = [
|
||||
[0, 1, 0],
|
||||
[0, 0, 1],
|
||||
[0, 0, 0]
|
||||
];
|
||||
```
|
||||
|
||||
グラフのエッジに<dfn>重み</dfn>を付けることもできます。 これまでに見てきたエッジは、単にエッジの有無が二項 (`0` または `1`) で表された、<dfn>重み付けされていない</dfn>エッジです。 用途によって重みを変えることができます。
|
||||
|
||||
# --instructions--
|
||||
|
||||
5 つのノードを持つ無向グラフの隣接行列を作成してください。 この行列は多次元配列でなければなりません。 これら 5 つのノードは、1 番目と 4 番目のノード、1 番目と 3 番目のノード、3 番目と 5 番目のノード、および 4 番目と 5 番目のノードの間に関係があります。 エッジの重みはすべて 1 です。
|
||||
|
||||
# --hints--
|
||||
|
||||
`undirectedAdjList` には 5 つのノードのみが含まれている必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
adjMatUndirected.length === 5 &&
|
||||
adjMatUndirected
|
||||
.map(function (x) {
|
||||
return x.length === 5;
|
||||
})
|
||||
.reduce(function (a, b) {
|
||||
return a && b;
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
1 番目と 4 番目のノードの間にはエッジが必要です。
|
||||
|
||||
```js
|
||||
assert(adjMatUndirected[0][3] === 1 && adjMatUndirected[3][0] === 1);
|
||||
```
|
||||
|
||||
1 番目と 3 番目のノードの間にはエッジが必要です。
|
||||
|
||||
```js
|
||||
assert(adjMatUndirected[0][2] === 1 && adjMatUndirected[2][0] === 1);
|
||||
```
|
||||
|
||||
3 番目と 5 番目のノードの間にはエッジが必要です。
|
||||
|
||||
```js
|
||||
assert(adjMatUndirected[2][4] === 1 && adjMatUndirected[4][2] === 1);
|
||||
```
|
||||
|
||||
There should be an edge between the fourth and fifth node.
|
||||
|
||||
```js
|
||||
assert(adjMatUndirected[3][4] === 1 && adjMatUndirected[4][3] === 1);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var adjMatUndirected = [];
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var adjMatUndirected = [
|
||||
[0, 0, 1, 1, 0],
|
||||
[0, 0, 0, 0, 0],
|
||||
[1, 0, 0, 0, 1],
|
||||
[1, 0, 0, 0, 1],
|
||||
[0, 0, 1, 1, 0]
|
||||
];
|
||||
```
|
@ -0,0 +1,182 @@
|
||||
---
|
||||
id: 587d825c367417b2b2512c90
|
||||
title: 幅優先探索
|
||||
challengeType: 1
|
||||
forumTopicId: 301622
|
||||
dashedName: breadth-first-search
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
これまで、グラフを表現するさまざまな方法を学びました。 次は何でしょう? 自然に生まれる問いは、グラフ内の 2 つのノード間の距離はどのくらいかということです。 そこで、<dfn>グラフ走査アルゴリズム</dfn>の出番です。
|
||||
|
||||
<dfn>走査アルゴリズム</dfn>は、グラフ内のノードを走査したり訪問したりするためのアルゴリズムです。 走査アルゴリズムのタイプの一つは、幅優先探索アルゴリズムです。
|
||||
|
||||
このアルゴリズムは 1 つのノードから始まり、エッジ 1 本分だけ離れているすべての隣接ノードを訪問します。 その後、すべてのノードに到達するまで、それぞれの隣接ノードを訪れ続けます。
|
||||
|
||||
幅優先探索アルゴリズムを実装するのに役立つ重要なデータ構造は、キューです。 これは、一方の端に要素を追加し、もう一方の端から要素を削除することができる配列です。 これは、<dfn>FIFO</dfn> または<dfn>先入れ先出し</dfn>のデータ構造とも呼ばれます。
|
||||
|
||||
このアルゴリズムが行っていることを視覚的に表すと、このようになります。 
|
||||
|
||||
灰色はキューに追加されるノードを表し、黒はキューから削除されるノードを表します。 ノードがキューから削除される (ノードが黒に変わる) たびに、すべての隣接ノードがキューに追加される (ノードが灰色に変わる) 様子を確認してください。
|
||||
|
||||
このアルゴリズムを実装するには、グラフ構造と開始ノードを入力する必要があります。
|
||||
|
||||
まず、開始ノードからの距離、すなわち開始ノードからのエッジの数を知る必要があります。 `Infinity` のような大きな数字ですべての距離を開始します。 これにより、開始ノードから到達できないノードがある場合のカウントの問題を防ぎます。 次に、開始ノードから隣接ノードに移動します。 これらの隣接ノードはエッジ 1 本分だけ離れており、この時点で、あなたが追跡している距離に 1 単位の距離を追加する必要があります。
|
||||
|
||||
# --instructions--
|
||||
|
||||
隣接行列グラフ (二次元配列) とノードラベルの根 (開始ノード) をパラメータとして取る関数、`bfs()` を記述してください。 ノードラベルは単に `0` から `n - 1` の間の整数値です (`n` はグラフ内のノードの総数)。
|
||||
|
||||
Your function will output a JavaScript object key-value pairs with the node and its distance from the root. そのノードに到達できなかった場合、そのノードは `Infinity` の距離を持つ必要があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
`1` の開始ノードを持つ入力グラフ `[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]` は、`{0: 1, 1: 0, 2: 1, 3: 2}` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var graph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 1, 0],
|
||||
[0, 1, 0, 1],
|
||||
[0, 0, 1, 0]
|
||||
];
|
||||
var results = bfs(graph, 1);
|
||||
return isEquivalent(results, { 0: 1, 1: 0, 2: 1, 3: 2 });
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`1` の開始ノードを持つ入力グラフ `[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]]` は、`{0: 1, 1: 0, 2: 1, 3: Infinity}` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var graph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 1, 0],
|
||||
[0, 1, 0, 0],
|
||||
[0, 0, 0, 0]
|
||||
];
|
||||
var results = bfs(graph, 1);
|
||||
return isEquivalent(results, { 0: 1, 1: 0, 2: 1, 3: Infinity });
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`0` の開始ノードを持つ入力グラフ `[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]` は、`{0: 0, 1: 1, 2: 2, 3: 3}` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var graph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 1, 0],
|
||||
[0, 1, 0, 1],
|
||||
[0, 0, 1, 0]
|
||||
];
|
||||
var results = bfs(graph, 0);
|
||||
return isEquivalent(results, { 0: 0, 1: 1, 2: 2, 3: 3 });
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
入力グラフ `[[0, 1], [1, 0]]` の開始ノードが `0` の場合、`{0: 0, 1: 1}` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var graph = [
|
||||
[0, 1],
|
||||
[1, 0]
|
||||
];
|
||||
var results = bfs(graph, 0);
|
||||
return isEquivalent(results, { 0: 0, 1: 1 });
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
// Source: http://adripofjavascript.com/blog/drips/object-equality-in-javascript.html
|
||||
function isEquivalent(a, b) {
|
||||
// Create arrays of property names
|
||||
var aProps = Object.getOwnPropertyNames(a);
|
||||
var bProps = Object.getOwnPropertyNames(b);
|
||||
// If number of properties is different,
|
||||
// objects are not equivalent
|
||||
if (aProps.length != bProps.length) {
|
||||
return false;
|
||||
}
|
||||
for (var i = 0; i < aProps.length; i++) {
|
||||
var propName = aProps[i];
|
||||
// If values of same property are not equal,
|
||||
// objects are not equivalent
|
||||
if (a[propName] !== b[propName]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If we made it this far, objects
|
||||
// are considered equivalent
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function bfs(graph, root) {
|
||||
var nodesLen = {};
|
||||
|
||||
return nodesLen;
|
||||
};
|
||||
|
||||
var exBFSGraph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 1, 0],
|
||||
[0, 1, 0, 1],
|
||||
[0, 0, 1, 0]
|
||||
];
|
||||
console.log(bfs(exBFSGraph, 3));
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function bfs(graph, root) {
|
||||
var nodesLen = {};
|
||||
// Set all distances to infinity
|
||||
for (var i = 0; i < graph.length; i++) {
|
||||
nodesLen[i] = Infinity;
|
||||
}
|
||||
nodesLen[root] = 0; // ...except root node
|
||||
var queue = [root]; // Keep track of nodes to visit
|
||||
var current; // Current node traversing
|
||||
// Keep on going until no more nodes to traverse
|
||||
while (queue.length !== 0) {
|
||||
current = queue.shift();
|
||||
// Get adjacent nodes from current node
|
||||
var curConnected = graph[current]; // Get layer of edges from current
|
||||
var neighborIdx = []; // List of nodes with edges
|
||||
var idx = curConnected.indexOf(1); // Get first edge connection
|
||||
while (idx !== -1) {
|
||||
neighborIdx.push(idx); // Add to list of neighbors
|
||||
idx = curConnected.indexOf(1, idx + 1); // Keep on searching
|
||||
}
|
||||
// Loop through neighbors and get lengths
|
||||
for (var j = 0; j < neighborIdx.length; j++) {
|
||||
// Increment distance for nodes traversed
|
||||
if (nodesLen[neighborIdx[j]] === Infinity) {
|
||||
nodesLen[neighborIdx[j]] = nodesLen[current] + 1;
|
||||
queue.push(neighborIdx[j]); // Add new neighbors to queue
|
||||
}
|
||||
}
|
||||
}
|
||||
return nodesLen;
|
||||
}
|
||||
```
|
@ -0,0 +1,175 @@
|
||||
---
|
||||
id: 587d8257367417b2b2512c7c
|
||||
title: 二分探索木に要素が存在するかを調べる
|
||||
challengeType: 1
|
||||
forumTopicId: 301623
|
||||
dashedName: check-if-an-element-is-present-in-a-binary-search-tree
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
二分探索木について大まかに理解できたので、もう少し詳しく見ていきましょう。 二分探索木は、検索、挿入、削除という一般的操作の平均ケースでは対数時間計算量、最悪ケースでは線形時間計算量になります。 なぜでしょうか? これらの基本操作のそれぞれで、木の中の要素を見つける (または、挿入の場合は挿入先を見つける) 必要があります。また、各親ノードのツリー構造上、操作は左または右に分岐し、残りの木の半分のサイズを完全に排除します。 そのため検索は木のノード数の対数に比例し、これらの操作は平均ケースで対数時間計算量になります。 しかし最悪ケースについてはどうでしょうか? では、`10`, `12`, `17`, `25` という値を左から右に足していくことで、木を構成してみましょう。 二分探索木のルールに従って、`12` を `10` の右に、`17` をその右に、そして `25` をその右に追加します。 出来上がった木はリンクリストに似ており、`25` を見つけるために木を走査するには、すべての要素を線形に走査する必要があります。 したがって、最悪ケースでは線形時間計算量になります。 ここでの問題は、木が平衡でないことです。 それが何を意味するのかについては、以降のチャレンジでもう少し詳しく説明します。
|
||||
|
||||
# --instructions--
|
||||
|
||||
このチャレンジでは、私たちの木に対するユーティリティを作成します。 整数値を入力として受け取り、二分探索木でその値が存在するかどうかのブール値を返す、`isPresent` メソッドを記述してください。
|
||||
|
||||
# --hints--
|
||||
|
||||
`BinarySearchTree` データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `isPresent` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.isPresent == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`isPresent` メソッドは、木に追加された要素の有無を正しく調べる必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.isPresent !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(4);
|
||||
test.add(7);
|
||||
test.add(411);
|
||||
test.add(452);
|
||||
return (
|
||||
test.isPresent(452) &&
|
||||
test.isPresent(411) &&
|
||||
test.isPresent(7) &&
|
||||
!test.isPresent(100)
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`isPresent` は、木が空であるケースを処理する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.isPresent !== 'function') {
|
||||
return false;
|
||||
}
|
||||
return test.isPresent(5) == false;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
BinarySearchTree.prototype = Object.assign(
|
||||
BinarySearchTree.prototype,
|
||||
{
|
||||
add: function(value) {
|
||||
var node = this.root;
|
||||
if (node == null) {
|
||||
this.root = new Node(value);
|
||||
return;
|
||||
} else {
|
||||
function searchTree(node) {
|
||||
if (value < node.value) {
|
||||
if (node.left == null) {
|
||||
node.left = new Node(value);
|
||||
return;
|
||||
} else if (node.left != null) {
|
||||
return searchTree(node.left);
|
||||
}
|
||||
} else if (value > node.value) {
|
||||
if (node.right == null) {
|
||||
node.right = new Node(value);
|
||||
return;
|
||||
} else if (node.right != null) {
|
||||
return searchTree(node.right);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return searchTree(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
this.isPresent = function (value) {
|
||||
var current = this.root
|
||||
while (current) {
|
||||
if (value === current.value) {
|
||||
return true;
|
||||
}
|
||||
current = value < current.value ? current.left : current.right;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,136 @@
|
||||
---
|
||||
id: 5cc0c1b32479e176caf3b422
|
||||
title: 木が二分探索木であるかを調べる
|
||||
challengeType: 1
|
||||
forumTopicId: 301624
|
||||
dashedName: check-if-tree-is-binary-search-tree
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
二分探索木がどのようなものかはもう分かったので、このチャレンジでは、ある木が二分探索木であるかどうかを知る方法を学びます。
|
||||
|
||||
二分探索木の主な特徴は、ノードが整然と順序付けられることです。 ノードは、子ノードの値が親ノード以上なのか (右)、親ノードより小さいのか (左) に基づいて、最大 2 つの子ノード (右か左、またはその両方) を持ちます。
|
||||
|
||||
# --instructions--
|
||||
|
||||
このチャレンジでは、あなたの木に対するユーティリティを作成します。 木を入力として受け取り、その木が二分探索木であるかどうかのブール値を返す、JavaScript メソッド `isBinarySearchTree` を記述してください。 可能な限り再帰を使用してください。
|
||||
|
||||
# --hints--
|
||||
|
||||
二分探索木は、`isBinarySearchTree()` で調べられたときに true を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
test.push(1);
|
||||
test.push(5);
|
||||
test.push(3);
|
||||
test.push(2);
|
||||
test.push(4);
|
||||
return isBinarySearchTree(test) == true;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
BinarySearchTree.prototype.push = function(val) {
|
||||
var root = this.root;
|
||||
|
||||
if (!root) {
|
||||
this.root = new Node(val);
|
||||
return;
|
||||
}
|
||||
|
||||
var currentNode = root;
|
||||
var newNode = new Node(val);
|
||||
|
||||
while (currentNode) {
|
||||
if (val < currentNode.value) {
|
||||
if (!currentNode.left) {
|
||||
currentNode.left = newNode;
|
||||
break;
|
||||
} else {
|
||||
currentNode = currentNode.left;
|
||||
}
|
||||
} else {
|
||||
if (!currentNode.right) {
|
||||
currentNode.right = newNode;
|
||||
break;
|
||||
} else {
|
||||
currentNode = currentNode.right;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
}
|
||||
function isBinarySearchTree(tree) {
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
}
|
||||
function isBinarySearchTree(tree) {
|
||||
if (tree.root == null) {
|
||||
return null;
|
||||
} else {
|
||||
let isBST = true;
|
||||
function checkTree(node) {
|
||||
if (node.left != null) {
|
||||
const left = node.left;
|
||||
if (left.value > node.value) {
|
||||
isBST = false;
|
||||
} else {
|
||||
checkTree(left);
|
||||
}
|
||||
}
|
||||
if (node.right != null) {
|
||||
const right = node.right;
|
||||
if (right.value < node.value) {
|
||||
isBST = false;
|
||||
} else {
|
||||
checkTree(right);
|
||||
}
|
||||
}
|
||||
}
|
||||
checkTree(tree.root);
|
||||
return isBST;
|
||||
}
|
||||
};
|
||||
```
|
@ -0,0 +1,235 @@
|
||||
---
|
||||
id: 587d8255367417b2b2512c75
|
||||
title: 循環キューを作成する
|
||||
challengeType: 1
|
||||
forumTopicId: 301625
|
||||
dashedName: create-a-circular-queue
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
このチャレンジでは、循環キューを作成します。 循環キューとは、コレクションの末尾にデータを書き込んだ後にコレクションの先頭から上書きを始めるキューです。 このタイプのデータ構造は、特定の状況で便利です。 例えば、ストリーミングメディアに循環キューを使用できます。 キューがいっぱいになると、新しいメディアデータが古いデータを上書きします。
|
||||
|
||||
この概念を分かりやすく説明するために、次のような、長さが `5` の配列を使います。
|
||||
|
||||
```js
|
||||
[null, null, null, null, null]
|
||||
^Read @ 0
|
||||
^Write @ 0
|
||||
```
|
||||
|
||||
今、読み取りと書き込みの両方が位置 `0` にあります。 ここでキューは `a`、`b`、`c` という 3 つの新しいレコードを取得します。 キューは次のようになりました。
|
||||
|
||||
```js
|
||||
[a, b, c, null, null]
|
||||
^Read @ 0
|
||||
^Write @ 3
|
||||
```
|
||||
|
||||
読み取りヘッドは、値を読み取るときに、次のように値を削除したり保持したりできます。
|
||||
|
||||
```js
|
||||
[null, null, null, null, null]
|
||||
^Read @ 3
|
||||
^Write @ 3
|
||||
```
|
||||
|
||||
次に、値 `d`、`e`、`f` をキューに書き込みましょう。 書き込みが配列の末尾に達すると、先頭に戻って書き込みが行われます。
|
||||
|
||||
```js
|
||||
[f, null, null, d, e]
|
||||
^Read @ 3
|
||||
^Write @ 1
|
||||
```
|
||||
|
||||
このアプローチは一定量のメモリを必要としますが、他のアプローチと比べ、はるかに大きなサイズのファイルを処理できます。
|
||||
|
||||
# --instructions--
|
||||
|
||||
このチャレンジでは、循環キューを実装してください。 循環キューには、キューからの読み取りとキューへの書き込みを可能にする `enqueue` メソッドと `dequeue` メソッドが必要です。 キューの作成時にそのサイズ指定に使用できる整数引数を、クラス自体が受け入れる必要があります。 このクラスの最初のバージョンが、コードエディタ内に既に用意されています。
|
||||
|
||||
要素をキューに入れると、書き込みポインタは前に進み、キューの末尾に達したら先頭に戻ります。 `enqueue` メソッドは、成功した場合、キューに追加された要素を返す必要があります。それ以外の場合は、`null` を返します。
|
||||
|
||||
同様に、要素をキューから取り除くと読み取りポインタが前進する必要があります。 要素をキューから取り除く際は、その要素を返す必要があります。 要素をキューから取り除けない場合は、`null` を返す必要があります。
|
||||
|
||||
書き込みポインタが読み取りポインタを追い越せないようにする必要があります (このクラスは、まだ読み取っていないデータを上書きすることはできません)。また、読み取りポインタは、書き込まれた過去のデータを前進させることはできません。
|
||||
|
||||
# --hints--
|
||||
|
||||
`enqueue` メソッドは、循環キューに要素を追加する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new CircularQueue(3);
|
||||
test.enqueue(17);
|
||||
test.enqueue(32);
|
||||
test.enqueue(591);
|
||||
var print = test.print();
|
||||
return print[0] === 17 && print[1] === 32 && print[2] === 591;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
読み取りポインタを追い越して要素をキューに入れてはいけません。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new CircularQueue(3);
|
||||
test.enqueue(17);
|
||||
test.enqueue(32);
|
||||
test.enqueue(591);
|
||||
test.enqueue(13);
|
||||
test.enqueue(25);
|
||||
test.enqueue(59);
|
||||
var print = test.print();
|
||||
return print[0] === 17 && print[1] === 32 && print[2] === 591;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`dequeue` メソッドは、キューから要素を取り除く必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new CircularQueue(3);
|
||||
test.enqueue(17);
|
||||
test.enqueue(32);
|
||||
test.enqueue(591);
|
||||
return (
|
||||
test.dequeue() === 17 && test.dequeue() === 32 && test.dequeue() === 591
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
要素がキューから取り除かれた後、キュー内におけるその要素の位置が `null` にリセットされる必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new CircularQueue(3);
|
||||
test.enqueue(17);
|
||||
test.enqueue(32);
|
||||
test.enqueue(672);
|
||||
test.dequeue();
|
||||
test.dequeue();
|
||||
var print = test.print();
|
||||
return print[0] === null && print[1] === null && print[2] === 672;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
書き込みポインタを越えてキューから取り除こうとすると `null` が返される必要があります。この場合、書き込みポインタは前進しません。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new CircularQueue(3);
|
||||
test.enqueue(17);
|
||||
test.enqueue(32);
|
||||
test.enqueue(591);
|
||||
return (
|
||||
test.dequeue() === 17 &&
|
||||
test.dequeue() === 32 &&
|
||||
test.dequeue() === 591 &&
|
||||
test.dequeue() === null &&
|
||||
test.dequeue() === null &&
|
||||
test.dequeue() === null &&
|
||||
test.dequeue() === null &&
|
||||
test.enqueue(100) === 100 &&
|
||||
test.dequeue() === 100
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
class CircularQueue {
|
||||
constructor(size) {
|
||||
|
||||
this.queue = [];
|
||||
this.read = 0;
|
||||
this.write = 0;
|
||||
this.max = size - 1;
|
||||
|
||||
while (size > 0) {
|
||||
this.queue.push(null);
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
print() {
|
||||
return this.queue;
|
||||
}
|
||||
|
||||
enqueue(item) {
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
|
||||
dequeue() {
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
class CircularQueue {
|
||||
constructor(size) {
|
||||
this.queue = [];
|
||||
this.read = 0;
|
||||
this.write = 0;
|
||||
this.max = size - 1;
|
||||
|
||||
while (size > 0) {
|
||||
this.queue.push(null);
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
print() {
|
||||
return this.queue;
|
||||
}
|
||||
|
||||
enqueue(item) {
|
||||
// Only change code below this line
|
||||
console.log(this.write, this.max);
|
||||
if (this.queue[this.write] === null) {
|
||||
this.queue[this.write++] = item;
|
||||
|
||||
if (this.write > this.max) {
|
||||
this.write = 0;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
// Only change code above this line
|
||||
}
|
||||
|
||||
dequeue() {
|
||||
// Only change code below this line
|
||||
if (this.queue[this.read] !== null) {
|
||||
let item = this.queue[this.read];
|
||||
this.queue[this.read++] = null;
|
||||
if (this.read > this.max) {
|
||||
this.read = 0;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
// Only change code above this line
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,216 @@
|
||||
---
|
||||
id: 587d825a367417b2b2512c87
|
||||
title: 二重リンクリストを作成する
|
||||
challengeType: 1
|
||||
forumTopicId: 301626
|
||||
dashedName: create-a-doubly-linked-list
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
これまでに作成したリンクリストは、すべて単独でリンクされたリストです。 ここでは<dfn>二重リンクリスト</dfn>を作成します。 名前が示すように、二重リンクリスト内のノードは、リスト内の次ノードと前ノードへの参照を持っています。
|
||||
|
||||
これにより両方向でリストを走査することができますが、すべてのノードにリスト内の前ノードへの参照を追加する必要があるため、より多くのメモリを使用することになります。
|
||||
|
||||
# --instructions--
|
||||
|
||||
`Node` オブジェクトが既に用意され、`DoublyLinkedList` が開始しています。 二重リンクリストに、`add`、`remove` と呼ばれる 2 つのメソッドを追加しましょう。 `add` メソッドは与えられた要素をリストに追加する必要があります。`remove` メソッドは、リスト内で、与えられた要素のすべての出現を削除する必要があります。
|
||||
|
||||
これらのメソッドを記述する際は、先頭または末尾の要素の削除など、起こり得るエッジケースを慎重に処理してください。 また、空のリスト上で要素を削除すると、`null` が返される必要があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
DoublyLinkedList データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
DoublyLinkedList に add というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
if (test.add == undefined) {
|
||||
return false;
|
||||
}
|
||||
return typeof test.add == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
DoublyLinkedList に remove というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
if (test.remove == undefined) {
|
||||
return false;
|
||||
}
|
||||
return typeof test.remove == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
また、空のリストから要素を削除すると、null が返される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
return test.remove(100) == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
add メソッドはリストに要素を追加する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
test.add(5);
|
||||
test.add(6);
|
||||
test.add(723);
|
||||
return test.print().join('') == '56723';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
各ノードは前のノードを追跡する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
test.add(50);
|
||||
test.add(68);
|
||||
test.add(73);
|
||||
return test.printReverse().join('') == '736850';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
先頭の要素はリストから削除可能である必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
test.add(25);
|
||||
test.add(35);
|
||||
test.add(60);
|
||||
test.remove(25);
|
||||
return test.print().join('') == '3560';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
末尾の要素はリストから削除可能である必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
test.add(25);
|
||||
test.add(35);
|
||||
test.add(60);
|
||||
test.remove(60);
|
||||
return test.print().join('') == '2535';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
DoublyLinkedList.prototype = Object.assign(
|
||||
DoublyLinkedList.prototype,
|
||||
{
|
||||
|
||||
print() {
|
||||
if (this.head == null) {
|
||||
return null;
|
||||
} else {
|
||||
var result = new Array();
|
||||
var node = this.head;
|
||||
while (node.next != null) {
|
||||
result.push(node.data);
|
||||
node = node.next;
|
||||
};
|
||||
result.push(node.data);
|
||||
return result;
|
||||
};
|
||||
},
|
||||
printReverse() {
|
||||
if (this.tail == null) {
|
||||
return null;
|
||||
} else {
|
||||
var result = new Array();
|
||||
var node = this.tail;
|
||||
while (node.prev != null) {
|
||||
result.push(node.data);
|
||||
node = node.prev;
|
||||
};
|
||||
result.push(node.data);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var Node = function(data, prev) {
|
||||
this.data = data;
|
||||
this.prev = prev;
|
||||
this.next = null;
|
||||
};
|
||||
var DoublyLinkedList = function() {
|
||||
this.head = null;
|
||||
this.tail = null;
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
};
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,260 @@
|
||||
---
|
||||
id: 587d825b367417b2b2512c8e
|
||||
title: ハッシュテーブルを作成する
|
||||
challengeType: 1
|
||||
forumTopicId: 301627
|
||||
dashedName: create-a-hash-table
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
このチャレンジでは、ハッシュテーブルについて学びます。 ハッシュテーブルは、連想配列、すなわちキーと値のペアのマッピング (例えば、これまでに学んだオブジェクトやマップ) を実装するために使用されます。 例えば、JavaScript オブジェクトはハッシュテーブルとして実装することができます (実際の実装は実行環境によって異なります)。 ハッシュテーブルの仕組みは、キー入力を受け取り、決定論的方法でこのキーを何らかの数値にハッシュすることです。 この数値は、関連付けられた値が格納される際の実際のキーとして使用されます。 次に、同じキーにアクセスしようとすると、ハッシュ関数はそのキーを処理して同じ数値結果を返し、それは関連付けられた値の検索に使用されます。 これにより、平均ケースでの検索時間は非常に効率的な O(1) になります。
|
||||
|
||||
ハッシュテーブルは、指定された範囲内で配列インデックスを生成するハッシュ関数を持つ配列として実装できます。 この方法では、ハッシュ関数と同様に配列サイズの選択が重要です。 例えば、ハッシュ関数が 2 つの異なるキーに対して同じ値を生成したらどうなりますか? これは衝突と呼ばれます。 衝突を処理する方法の一つは、キーと値のペアを両方ともそのインデックスに格納することです。 その場合、そのどちらかを検索するとき、あなたが探しているキーを見つけるために大量の要素に対して検索を繰り返す必要があります。 優れたハッシュ関数は、高い検索効率を維持するために衝突を最小限に抑えます。
|
||||
|
||||
ここではハッシュ法やハッシュテーブル実装を詳しく知る必要はなく、それらの大まかな仕組みを理解すれば十分です。
|
||||
|
||||
# --instructions--
|
||||
|
||||
ハッシュテーブルの基本的な機能を作成しましょう。 単純なハッシュ関数が既に用意されています。 関数 `hash` に文字列値を渡すと、ストレージのキーとして使用できるハッシュ値が返されます。 このハッシュ値に基づいて要素を `this.collection` オブジェクトに格納します。 `add`、`remove`、`lookup` という 3 つのメソッドを作成してください。 最初のメソッドで、ハッシュテーブルに追加するキーと値のペアを受け入れます。 2 番目のメソッドで、キーを渡すときにキーと値のペアを削除します。 3 番目のメソッドで、キーを受け入れ、関連付けられた値を返すか、キーが存在しない場合は `null` を返します。
|
||||
|
||||
衝突を考慮しながらコードを記述してください!
|
||||
|
||||
**注:** `remove` メソッドのテストは、`add` メソッドと `lookup` メソッドが正しく実装されるまで合格しません。
|
||||
|
||||
# --hints--
|
||||
|
||||
HashTable データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof HashTable !== 'undefined') {
|
||||
test = new HashTable();
|
||||
}
|
||||
return typeof test === 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
HashTable に add メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof HashTable !== 'undefined') {
|
||||
test = new HashTable();
|
||||
}
|
||||
return typeof test.add === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
HashTable に lookup メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof HashTable !== 'undefined') {
|
||||
test = new HashTable();
|
||||
}
|
||||
return typeof test.lookup === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
HashTable に remove メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof HashTable !== 'undefined') {
|
||||
test = new HashTable();
|
||||
}
|
||||
return typeof test.remove === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
add メソッドはキーと値のペアを追加し、lookup メソッドは与えられたキーに関連付けられた値を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof HashTable !== 'undefined') {
|
||||
test = new HashTable();
|
||||
}
|
||||
test.add('key', 'value');
|
||||
return test.lookup('key') === 'value';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
remove メソッドはキーを入力として受け入れ、関連付けられたキーと値のペアを削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
var hashValue = hash('key');
|
||||
if (typeof HashTable !== 'undefined') {
|
||||
test = new HashTable();
|
||||
}
|
||||
test.add('key', 'value');
|
||||
|
||||
test.remove('key');
|
||||
return !test.collection.hasOwnProperty(hashValue);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
remove メソッドは、キーと値の正しいペアのみを削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
var hashValue = hash('key');
|
||||
if (typeof HashTable !== 'undefined') {
|
||||
test = new HashTable();
|
||||
}
|
||||
test.add('key', 'value');
|
||||
test.add('yek', 'value');
|
||||
test.add('altKey', 'value');
|
||||
|
||||
test.remove('yek');
|
||||
if (test.lookup('yek') || !test.lookup('key') || !test.lookup('altKey')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
test.remove('key');
|
||||
|
||||
return !test.collection.hasOwnProperty(hashValue) && test.lookup('altKey');
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
要素はハッシュ関数を使用して追加される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof HashTable !== 'undefined') {
|
||||
test = new HashTable();
|
||||
}
|
||||
called = 0;
|
||||
test.add('key1', 'value1');
|
||||
test.add('key2', 'value2');
|
||||
test.add('key3', 'value3');
|
||||
return called >= 3 && called % 3 === 0;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
ハッシュテーブルは衝突を処理する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof HashTable !== 'undefined') {
|
||||
test = new HashTable();
|
||||
}
|
||||
called = 0;
|
||||
test.add('key1', 'value1');
|
||||
test.add('1key', 'value2');
|
||||
test.add('ke1y', 'value3');
|
||||
return (
|
||||
test.lookup('key1') === 'value1' &&
|
||||
test.lookup('1key') == 'value2' &&
|
||||
test.lookup('ke1y') == 'value3'
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --before-user-code--
|
||||
|
||||
```js
|
||||
var called = 0;
|
||||
var hash = string => {
|
||||
called++;
|
||||
var hash = 0;
|
||||
for (var i = 0; i < string.length; i++) {
|
||||
hash += string.charCodeAt(i);
|
||||
}
|
||||
return hash;
|
||||
};
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var called = 0;
|
||||
var hash = string => {
|
||||
called++;
|
||||
var hashed = 0;
|
||||
for (var i = 0; i < string.length; i++) {
|
||||
hashed += string.charCodeAt(i);
|
||||
}
|
||||
return hashed;
|
||||
};
|
||||
var HashTable = function() {
|
||||
this.collection = {};
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
};
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var called = 0;
|
||||
var hash = (string) => {
|
||||
called++;
|
||||
var hash = 0;
|
||||
for (var i = 0; i < string.length; i++) { hash += string.charCodeAt(i); }
|
||||
return hash;
|
||||
};
|
||||
var HashTable = function() {
|
||||
this.collection = {};
|
||||
// Only change code below this line
|
||||
|
||||
this.add = function(key, val) {
|
||||
var theHash = hash(key);
|
||||
if (!this.collection.hasOwnProperty(theHash)) {
|
||||
this.collection[theHash] = {};
|
||||
}
|
||||
this.collection[theHash][key] = val;
|
||||
}
|
||||
|
||||
this.remove = function(key) {
|
||||
var theHash = hash(key);
|
||||
var hashedObj = this.collection[theHash];
|
||||
if (hashedObj.hasOwnProperty(key)) {
|
||||
delete hashedObj[key];
|
||||
}
|
||||
if (!Object.keys(hashedObj).length) {
|
||||
delete this.collection[theHash];
|
||||
}
|
||||
}
|
||||
|
||||
this.lookup = function(key) {
|
||||
var theHash = hash(key);
|
||||
if (this.collection.hasOwnProperty(theHash)) {
|
||||
return this.collection[theHash][key];
|
||||
}
|
||||
return null
|
||||
}
|
||||
// Only change code above this line
|
||||
};
|
||||
```
|
@ -0,0 +1,146 @@
|
||||
---
|
||||
id: 587d8251367417b2b2512c62
|
||||
title: リンクリスト・クラスを作成する
|
||||
challengeType: 1
|
||||
forumTopicId: 301628
|
||||
dashedName: create-a-linked-list-class
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
`linked list` (リンクリスト) クラスを作成しましょう。 どのリンクリストでも、まずは基本プロパティ、すなわち `head` (リストの最初の要素) と `length` (リストの要素数) を定義する必要があります。 リストの最後の要素に `tail` を組み込んだリンクリストの実装も時々見かけますが、今はこの 2 つだけを使いましょう。 リンクリストに要素を追加するたびに、`length` プロパティが 1 ずつ増分される必要があります。
|
||||
|
||||
リンクリストに要素を追加する方法が必要なので、最初に作成したいのは `add` メソッドです。
|
||||
|
||||
リストが空の場合、リンクリストに要素を追加するのは簡単です。その要素を `Node` クラスにラップし、そのノードをリンクリストの `head` に割り当てるだけです。
|
||||
|
||||
しかし、このリストに既に 1 つ以上のメンバーがある場合はどうなるでしょう? どうすればリストに要素を追加できるでしょうか? リンクリストの各ノードに `next` プロパティがあることを思い出してください。 リストにノードを追加するには、リスト内の最後のノードを探し、最後のノードの `next` プロパティが新しいノードを指すようにします。 (ヒント: ノードの `next` プロパティが `null` のとき、リンクリストの末尾に到達したことが分かります。)
|
||||
|
||||
# --instructions--
|
||||
|
||||
リンクリストにプッシュした最初のノードを `head` に割り当てる add メソッドを記述してください。割り当ての後、ノードを追加するたびに、そのノードは前のノードの `next` プロパティによって参照される必要があります。
|
||||
|
||||
注
|
||||
|
||||
リストの `length` は、リンクリストに要素が追加されるたびに 1 ずつ増加する必要があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
`LinkedList` クラスに `add` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
return typeof test.add === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`LinkedList` クラスは、追加された最初のノードに `head` を割り当てる必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
return test.head().element === 'cat';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`LinkedList` クラスの以前の `node` は、作成された最新ノードへの参照を持つ必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('fish');
|
||||
return test.head().next.element === 'dog' && test.head().next.next.element === 'fish';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`LinkedList` クラスの `size` は、リンクリスト内のノードの数と同じである必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
return test.size() === 2;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function LinkedList() {
|
||||
var length = 0;
|
||||
var head = null;
|
||||
|
||||
var Node = function(element){
|
||||
this.element = element;
|
||||
this.next = null;
|
||||
};
|
||||
|
||||
this.head = function(){
|
||||
return head;
|
||||
};
|
||||
|
||||
this.size = function(){
|
||||
return length;
|
||||
};
|
||||
|
||||
this.add = function(element){
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function LinkedList() {
|
||||
var length = 0;
|
||||
var head = null;
|
||||
|
||||
var Node = function(element){
|
||||
this.element = element;
|
||||
this.next = null;
|
||||
};
|
||||
|
||||
this.head = function(){
|
||||
return head;
|
||||
};
|
||||
|
||||
this.size = function(){
|
||||
return length;
|
||||
};
|
||||
|
||||
this.add = function(element){
|
||||
// Only change code below this line
|
||||
if (head == null) {
|
||||
head = new Node(element);
|
||||
}
|
||||
else {
|
||||
let currentNode = head;
|
||||
while (currentNode.next != null) {
|
||||
// currentNode.next will be last node of linked list after loop
|
||||
currentNode = currentNode.next;
|
||||
}
|
||||
currentNode.next = new Node(element);
|
||||
}
|
||||
length++;
|
||||
// Only change code above this line
|
||||
};
|
||||
}
|
||||
```
|
@ -0,0 +1,204 @@
|
||||
---
|
||||
id: 8d5823c8c441eddfaeb5bdef
|
||||
title: マップデータ構造を作成する
|
||||
challengeType: 1
|
||||
forumTopicId: 301629
|
||||
dashedName: create-a-map-data-structure
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
次のいくつかのチャレンジでは、マップとハッシュテーブルについて学びます。 マップはキーと値のペアを格納するデータ構造です。 JavaScript では、これらをオブジェクトとして利用できます。 マップは、キー値に基づいて格納された要素の迅速な検索を可能にする、非常に一般的で便利なデータ構造です。
|
||||
|
||||
# --instructions--
|
||||
|
||||
自分だけのマップを作る練習をしましょう。 JavaScript オブジェクトは、ここで書けるものよりもはるかに効率的なマップ構造を提供しているので、ここでの主な目的は学習のために練習することです。 ただし、JavaScript オブジェクトは特定の操作のみを提供します。 カスタム操作を定義したい場合はどうなるでしょう? ここで提供されている `Map` オブジェクトを JavaScript `object` のラッパーとして使用します。 Map オブジェクトに対する以下のメソッドと操作を作成してください。
|
||||
|
||||
<ul>
|
||||
<li><code>add</code> は <code>key、value</code> のペアを受け入れてマップに追加します</li>
|
||||
<li><code>remove</code> はキーを受け入れ、関連付けられた <code>key、value</code> のペア を削除します</li>
|
||||
<li><code>get</code> は <code>key</code> を受け入れ、格納された <code>value</code> を返します</li>
|
||||
<li><code>has</code> は <code>key</code> を受け入れ、キーが存在する場合は <dfn>true</dfn> を返し、そうでない場合は <dfn>false</dfn> を返します</li>
|
||||
<li><code>values</code> はマップ内のすべての値の配列を返します</li>
|
||||
<li><code>size</code> はマップ内の要素数を返します</li>
|
||||
<li><code>clear</code> はマップを空にします</li>
|
||||
</ul>
|
||||
|
||||
# --hints--
|
||||
|
||||
Map データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof Map !== 'undefined') {
|
||||
test = new Map();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
Map オブジェクトには add、remove、get、has、value、clear、size の各メソッドが必要です 。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof Map !== 'undefined') {
|
||||
test = new Map();
|
||||
}
|
||||
return (
|
||||
typeof test.add == 'function' &&
|
||||
typeof test.remove == 'function' &&
|
||||
typeof test.get == 'function' &&
|
||||
typeof test.has == 'function' &&
|
||||
typeof test.values == 'function' &&
|
||||
typeof test.clear == 'function' &&
|
||||
typeof test.size == 'function'
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
add メソッドはマップに要素を追加する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof Map !== 'undefined') {
|
||||
test = new Map();
|
||||
}
|
||||
test.add(5, 6);
|
||||
test.add(2, 3);
|
||||
test.add(2, 5);
|
||||
return test.size() == 2;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
has メソッドは、追加された要素に対して true を、存在しない要素に対して false を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof Map !== 'undefined') {
|
||||
test = new Map();
|
||||
}
|
||||
test.add('test', 'value');
|
||||
return test.has('test') && !test.has('false');
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
get メソッドはキーを入力として受け入れ、関連付けられた値を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof Map !== 'undefined') {
|
||||
test = new Map();
|
||||
}
|
||||
test.add('abc', 'def');
|
||||
return test.get('abc') == 'def';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
values メソッドは、マップに格納されているすべての値を、文字列の配列として返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof Map !== 'undefined') {
|
||||
test = new Map();
|
||||
}
|
||||
test.add('a', 'b');
|
||||
test.add('c', 'd');
|
||||
test.add('e', 'f');
|
||||
var vals = test.values();
|
||||
return (
|
||||
vals.indexOf('b') != -1 &&
|
||||
vals.indexOf('d') != -1 &&
|
||||
vals.indexOf('f') != -1
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
clear メソッドはマップを空にし、size メソッドはマップに存在する要素の数を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof Map !== 'undefined') {
|
||||
test = new Map();
|
||||
}
|
||||
test.add('b', 'b');
|
||||
test.add('c', 'd');
|
||||
test.remove('asdfas');
|
||||
var init = test.size();
|
||||
test.clear();
|
||||
return init == 2 && test.size() == 0;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var Map = function() {
|
||||
this.collection = {};
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
};
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var Map = function() {
|
||||
this.collection = {};
|
||||
// Only change code below this line
|
||||
|
||||
this.add = function(key,value) {
|
||||
this.collection[key] = value;
|
||||
}
|
||||
|
||||
this.remove = function(key) {
|
||||
delete this.collection[key];
|
||||
}
|
||||
|
||||
this.get = function(key) {
|
||||
return this.collection[key];
|
||||
}
|
||||
|
||||
this.has = function(key) {
|
||||
return this.collection.hasOwnProperty(key)
|
||||
}
|
||||
|
||||
this.values = function() {
|
||||
return Object.values(this.collection);
|
||||
}
|
||||
|
||||
this.size = function() {
|
||||
return Object.keys(this.collection).length;
|
||||
}
|
||||
|
||||
this.clear = function() {
|
||||
for(let item of Object.keys(this.collection)) {
|
||||
delete this.collection[item];
|
||||
}
|
||||
}
|
||||
// Only change code above this line
|
||||
};
|
||||
```
|
@ -0,0 +1,231 @@
|
||||
---
|
||||
id: 587d8255367417b2b2512c74
|
||||
title: 優先度付きキュークラスを作成する
|
||||
challengeType: 1
|
||||
forumTopicId: 301630
|
||||
dashedName: create-a-priority-queue-class
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
このチャレンジでは、優先度付きキューを作成します。 優先度付きキューとは、要素の優先度を指定する追加情報をその要素が持てるという、特殊なタイプのキューです。 優先度は単純に整数で表すことができます。 ある数列要素がキューから取り出されるかどうかの決定は、その要素の位置よりも優先度に基づきます。 優先度の高い要素が優先度の低い要素の後にキューに追加されると、優先度の高い要素は他のすべての要素よりも先にキューから取り出されます。
|
||||
|
||||
例えば、3 つの要素を持つ優先度付きキューがあるとします。
|
||||
|
||||
```js
|
||||
[['kitten', 2], ['dog', 2], ['rabbit', 2]]
|
||||
```
|
||||
|
||||
ここでは、2 番目の値 (整数) が要素の優先度を表します。 優先度が `1` の `['human', 1]` をキューに入れると (優先度の数値が小さいほど優先されると仮定)、その要素はキューから最初に取り出されます。 コレクションは次のようになります。
|
||||
|
||||
```js
|
||||
[['human', 1], ['kitten', 2], ['dog', 2], ['rabbit', 2]]
|
||||
```
|
||||
|
||||
コードエディタ内に `PriorityQueue` の最初の部分が記述されています。 優先度を付けて要素を追加する `enqueue` メソッド、要素を削除して返す `dequeue` メソッド、キューの要素数を返す `size` メソッド、キューの先頭にある要素を返す `front` メソッド、そして最後に、キューが空の場合は `true`、空でない場合は `false` を返す `isEmpty` メソッドを追加してください。
|
||||
|
||||
`enqueue` は、上記のフォーマット (`['human', 1]`) の要素を受け入れる必要があります。ここで、`1` は優先度を表します。 `dequeue` と `front` は、その要素の優先度ではなく名前のみを返す必要があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
`PriorityQueue` クラスに `enqueue` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new PriorityQueue();
|
||||
return typeof test.enqueue === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`PriorityQueue` クラスに `dequeue` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new PriorityQueue();
|
||||
return typeof test.dequeue === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`PriorityQueue` クラスに `size` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new PriorityQueue();
|
||||
return typeof test.size === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`PriorityQueue` クラスに `front` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new PriorityQueue();
|
||||
return typeof test.front === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`PriorityQueue` クラスに `isEmpty` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new PriorityQueue();
|
||||
return typeof test.isEmpty === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`PriorityQueue` クラスは、要素がキューから出し入れされる際、 `size` メソッドを使用して現在の要素数を正しく追跡する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new PriorityQueue();
|
||||
test.enqueue(['David Brown', 2]);
|
||||
test.enqueue(['Jon Snow', 1]);
|
||||
var size1 = test.size();
|
||||
test.dequeue();
|
||||
var size2 = test.size();
|
||||
test.enqueue(['A', 3]);
|
||||
test.enqueue(['B', 3]);
|
||||
test.enqueue(['C', 3]);
|
||||
return size1 === 2 && size2 === 1 && test.size() === 4;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`front` メソッドは、要素がキューから出し入れされる際、キューの先頭にある正しい要素を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new PriorityQueue();
|
||||
test.enqueue(['David Brown', 2]);
|
||||
var front1 = test.front();
|
||||
test.enqueue(['Jon Snow', 1]);
|
||||
var front2 = test.front();
|
||||
test.dequeue();
|
||||
test.enqueue(['A', 3]);
|
||||
var front3 = test.front();
|
||||
test.enqueue(['B', 3]);
|
||||
test.enqueue(['C', 3]);
|
||||
test.dequeue();
|
||||
var front4 = test.front();
|
||||
return (
|
||||
front1 === 'David Brown' &&
|
||||
front2 === 'Jon Snow' &&
|
||||
front3 === 'David Brown' &&
|
||||
front4 === 'A'
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`isEmpty` メソッドは、キューが空の場合に `true` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new PriorityQueue();
|
||||
test.enqueue(['A', 1]);
|
||||
test.enqueue(['B', 1]);
|
||||
test.dequeue();
|
||||
var first = test.isEmpty();
|
||||
test.dequeue();
|
||||
return !first && test.isEmpty();
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
優先度付きキューは、優先度の低い要素よりも先に優先度の高い要素を返し、そうしない場合は先入れ先出しの順序で返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new PriorityQueue();
|
||||
test.enqueue(['A', 5]);
|
||||
test.enqueue(['B', 5]);
|
||||
test.enqueue(['C', 5]);
|
||||
test.enqueue(['D', 3]);
|
||||
test.enqueue(['E', 1]);
|
||||
test.enqueue(['F', 7]);
|
||||
var result = [];
|
||||
result.push(test.dequeue());
|
||||
result.push(test.dequeue());
|
||||
result.push(test.dequeue());
|
||||
result.push(test.dequeue());
|
||||
result.push(test.dequeue());
|
||||
result.push(test.dequeue());
|
||||
return result.join('') === 'EDABCF';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function PriorityQueue () {
|
||||
this.collection = [];
|
||||
this.printCollection = function() {
|
||||
console.log(this.collection);
|
||||
};
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function PriorityQueue() {
|
||||
this.collection = [];
|
||||
this.printCollection = function () {
|
||||
console.log(this.collection);
|
||||
};
|
||||
// Only change code below this line
|
||||
this.enqueue = function (newitem) {
|
||||
if (this.isEmpty()) {
|
||||
return this.collection.push(newitem);
|
||||
}
|
||||
|
||||
this.collection = this.collection.reverse();
|
||||
var found_index = this.collection.findIndex(function (item) {
|
||||
return newitem[1] >= item[1];
|
||||
});
|
||||
if (found_index === -1) {
|
||||
this.collection.push(newitem);
|
||||
} else {
|
||||
this.collection.splice(found_index, 0, newitem);
|
||||
}
|
||||
this.collection = this.collection.reverse();
|
||||
};
|
||||
this.dequeue = function () {
|
||||
if (!this.isEmpty()) {
|
||||
return this.collection.shift()[0];
|
||||
} else {
|
||||
return "The queue is empty.";
|
||||
}
|
||||
};
|
||||
this.size = function () {
|
||||
return this.collection.length;
|
||||
};
|
||||
this.front = function () {
|
||||
return this.collection[0][0];
|
||||
};
|
||||
this.isEmpty = function () {
|
||||
return this.size() > 0 ? false : true;
|
||||
};
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
@ -0,0 +1,174 @@
|
||||
---
|
||||
id: 587d8250367417b2b2512c60
|
||||
title: キュークラスを作成する
|
||||
challengeType: 1
|
||||
forumTopicId: 301631
|
||||
dashedName: create-a-queue-class
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
スタックと同様に、キューは要素の集まりです。 しかしスタックとは異なり、キューは FIFO (先入れ先出し) の原則に従います。 キューに追加された要素はキューのテール (末尾) にプッシュされ、取り除くことができる要素はキューの先頭にある要素だけです。
|
||||
|
||||
キューは配列を使用して表すことができますが、スタックと同じように、ここではキューに対する制御量を制限したいのです。
|
||||
|
||||
キュークラスの 2 つの主なメソッドは enqueue と dequeue です。 enqueue メソッドは要素をキューの末尾にプッシュし、dequeue メソッドはキューの先頭にある要素を削除して返します。 他の便利なメソッドとしては front、size、isEmpty があります。
|
||||
|
||||
# --instructions--
|
||||
|
||||
要素をキューの末尾にプッシュする `enqueue` メソッド、先頭の要素を削除して返す `dequeue` メソッド、先頭の要素を確認するための `front` メソッド、長さを示す `size` メソッド、および、キューが空かどうかを調べる `isEmpty` メソッドを記述してください。
|
||||
|
||||
# --hints--
|
||||
|
||||
`Queue` クラスに `enqueue` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Queue();
|
||||
return typeof test.enqueue === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`Queue` クラスに `dequeue` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Queue();
|
||||
return typeof test.dequeue === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`Queue` クラスに `front` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Queue();
|
||||
return typeof test.front === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`Queue` クラスに `size` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Queue();
|
||||
return typeof test.size === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`Queue` クラスに `isEmpty` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Queue();
|
||||
return typeof test.isEmpty === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`dequeue` メソッドはキューの先頭の要素を削除して返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Queue();
|
||||
test.enqueue('Smith');
|
||||
test.enqueue('John');
|
||||
return test.dequeue() === 'Smith';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`front` メソッドはキューの先頭の要素の値を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Queue();
|
||||
test.enqueue('Smith');
|
||||
test.enqueue('John');
|
||||
return test.front() === 'Smith';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`size` メソッドはキューの長さを返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Queue();
|
||||
test.enqueue('Smith');
|
||||
return test.size() === 1;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`isEmpty` メソッドは、キュー内に要素がある場合に `false` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Queue();
|
||||
test.enqueue('Smith');
|
||||
return !test.isEmpty();
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function Queue() {
|
||||
var collection = [];
|
||||
this.print = function() {
|
||||
console.log(collection);
|
||||
};
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function Queue () {
|
||||
var collection = [];
|
||||
this.print = function() {
|
||||
console.log(collection);
|
||||
};
|
||||
// Only change code below this line
|
||||
this.enqueue = function(item) {
|
||||
collection.push(item);
|
||||
}
|
||||
|
||||
this.dequeue = function() {
|
||||
return collection.shift();
|
||||
}
|
||||
|
||||
this.front = function() {
|
||||
return collection[0];
|
||||
}
|
||||
|
||||
this.size = function(){
|
||||
return collection.length;
|
||||
}
|
||||
|
||||
this.isEmpty = function() {
|
||||
return collection.length === 0 ? true : false;
|
||||
}
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
@ -0,0 +1,219 @@
|
||||
---
|
||||
id: 8d1323c8c441eddfaeb5bdef
|
||||
title: セットクラスを作成する
|
||||
challengeType: 1
|
||||
forumTopicId: 301632
|
||||
dashedName: create-a-set-class
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
この課題では、「セット (集合)」と呼ばれる抽象的なデータ構造を模倣するために、`Set` という名前のクラスを作成します。 セットは配列と似ていますが、重複した値を含むことはできません。 セットの典型的な使用方法は、単純に要素の有無を確認することです。 次の例を見れば、ES6 `Set` オブジェクトの仕組みが分かります。
|
||||
|
||||
```js
|
||||
const set1 = new Set([1, 2, 3, 5, 5, 2, 0]);
|
||||
console.log(set1);
|
||||
// output: {1, 2, 3, 5, 0}
|
||||
console.log(set1.has(1));
|
||||
// output: true
|
||||
console.log(set1.has(6));
|
||||
// output: false
|
||||
```
|
||||
|
||||
まず、セットに値が存在しない場合は、セットコレクションに値を追加する add メソッドを作成します。 次に、値が既に存在する場合は、セットコレクションから値を削除する remove メソッドを作成します。 最後に、セットコレクション内の要素の数を返す size メソッドを作成します。
|
||||
|
||||
# --instructions--
|
||||
|
||||
セットコレクションに一意の値を追加する `add` メソッドを作成し、値が正常に追加された場合は `true`、それ以外の場合は `false` を返してください。
|
||||
|
||||
値を受け入れてそれがセット内に存在するかどうかを調べる、`remove` メソッドを作成してください。 値が存在する場合、このメソッドはセットコレクションからそれを削除し、`true` を返す必要があります。 値が存在しない場合は、`false` を返す必要があります。 セットコレクションのサイズを返す `size` メソッドを作成してください。
|
||||
|
||||
# --hints--
|
||||
|
||||
`Set` クラスに `add` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
return typeof test.add === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`add` メソッドは重複値を追加してはいけません。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
test.add('a');
|
||||
test.add('b');
|
||||
test.add('a');
|
||||
var vals = test.values();
|
||||
return vals[0] === 'a' && vals[1] === 'b' && vals.length === 2;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`add` メソッドは、値が正常に追加された場合に `true` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
var result = test.add('a');
|
||||
return result != undefined && result === true;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`add` メソッドは、重複値が追加された場合に `false` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
test.add('a');
|
||||
var result = test.add('a');
|
||||
return result != undefined && result === false;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`Set` クラスに `remove` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
return typeof test.remove === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`remove` メソッドは、セット内に存在する要素のみを削除する必要があります。
|
||||
|
||||
```js
|
||||
assert.deepEqual(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
test.add('a');
|
||||
test.add('b');
|
||||
test.remove('c');
|
||||
return test.values();
|
||||
})(),
|
||||
['a', 'b']
|
||||
);
|
||||
```
|
||||
|
||||
`remove` メソッドは、指定された要素をセットから削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
test.add('a');
|
||||
test.add('b');
|
||||
test.remove('a');
|
||||
var vals = test.values();
|
||||
return vals[0] === 'b' && vals.length === 1;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`Set` クラスに `size` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
return typeof test.size === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`size` メソッドはコレクション内の要素の数を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
test.add('a');
|
||||
test.add('b');
|
||||
test.remove('a');
|
||||
return test.size() === 1;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
class Set {
|
||||
constructor() {
|
||||
// Dictionary will hold the items of our set
|
||||
this.dictionary = {};
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
// This method will check for the presence of an element and return true or false
|
||||
has(element) {
|
||||
return this.dictionary[element] !== undefined;
|
||||
}
|
||||
|
||||
// This method will return all the values in the set
|
||||
values() {
|
||||
return Object.values(this.dictionary);
|
||||
}
|
||||
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
class Set {
|
||||
constructor() {
|
||||
this.dictionary = {};
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
has(element) {
|
||||
return this.dictionary[element] !== undefined;
|
||||
}
|
||||
|
||||
values() {
|
||||
return Object.values(this.dictionary);
|
||||
}
|
||||
|
||||
add(element) {
|
||||
if (!this.has(element)) {
|
||||
this.dictionary[element] = element;
|
||||
this.length++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
remove(element) {
|
||||
if (this.has(element)) {
|
||||
delete this.dictionary[element];
|
||||
this.length--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size() {
|
||||
return this.length;
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,167 @@
|
||||
---
|
||||
id: 587d8250367417b2b2512c5f
|
||||
title: スタッククラスを作成する
|
||||
challengeType: 1
|
||||
forumTopicId: 301633
|
||||
dashedName: create-a-stack-class
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
前のセクションでは、スタックとは何か、配列を使用してスタックを表すにはどうすれば良いかについて説明しました。 このセクションでは、独自のスタッククラスを作成します。 配列を使ってスタックを作成することはできますが、スタックに対する制御量を制限するのがベストです。 スタックには、`push` メソッドと `pop` メソッド以外にも便利なメソッドがあります。 スタッククラスに `peek`、`isEmpty`、`clear` メソッドを追加しましょう。
|
||||
|
||||
# --instructions--
|
||||
|
||||
スタックの一番上に要素をプッシュする `push` メソッド、スタックの一番上の要素を削除して返す `pop` メソッド、スタックの一番上の要素を見る `peek` メソッド、スタックが空かどうかを調べる `isEmpty` メソッド、および、スタックからすべての要素を削除する `clear` メソッドを記述してください。 今回は、コレクションのコンソールログを取得する `print` ヘルパーメソッドを追加しました (通常、スタックにはこれがありませんが)。
|
||||
|
||||
# --hints--
|
||||
|
||||
`Stack` クラスに `push` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Stack();
|
||||
return typeof test.push === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`Stack` クラスに `pop` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Stack();
|
||||
return typeof test.pop === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`Stack` クラスに `peek` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Stack();
|
||||
return typeof test.peek === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`Stack` クラスに `isEmpty` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Stack();
|
||||
return typeof test.isEmpty === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`Stack` クラスに `clear` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Stack();
|
||||
return typeof test.clear === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`peek` メソッドはスタックの一番上の要素を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Stack();
|
||||
test.push('CS61');
|
||||
test.push('CS50');
|
||||
return test.peek() === 'CS50' && test.peek() === 'CS50';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`pop` メソッドはスタックの一番上の要素を削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Stack();
|
||||
test.push('CS61');
|
||||
test.push('CS50');
|
||||
return test.pop() === 'CS50' && test.pop() === 'CS61';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
スタックに要素が含まれていない場合、`isEmpty` メソッドは true を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Stack();
|
||||
return test.isEmpty();
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`clear` メソッドはスタックのすべての要素を削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Stack();
|
||||
test.push('CS61');
|
||||
test.push('CS50');
|
||||
test.clear();
|
||||
return test.isEmpty();
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function Stack() {
|
||||
var collection = [];
|
||||
this.print = function() {
|
||||
console.log(collection);
|
||||
};
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
class Stack {
|
||||
constructor() {
|
||||
this.collection = [];
|
||||
}
|
||||
print() {
|
||||
console.log(this.collection);
|
||||
}
|
||||
push(val) {
|
||||
this.collection.push(val);
|
||||
}
|
||||
pop() {
|
||||
return this.collection.pop();
|
||||
}
|
||||
peek() {
|
||||
return this.collection[this.collection.length - 1];
|
||||
}
|
||||
isEmpty() {
|
||||
return this.collection.length === 0;
|
||||
}
|
||||
clear() {
|
||||
return (this.collection.length = 0);
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,151 @@
|
||||
---
|
||||
id: 587d8259367417b2b2512c84
|
||||
title: トライ探索木を作成する
|
||||
challengeType: 1
|
||||
forumTopicId: 301634
|
||||
dashedName: create-a-trie-search-tree
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
二分探索木の次は、トライ (trie) と呼ばれる別のタイプのツリー構造を見てみましょう。 トライは、文字列を保持するためや、より一般的には、キーが文字列である連想配列や動的データセットを保持するために広く使われる、順序付き探索木です。 それらは、多数のキーの接頭辞が重複している場合に (例えば辞書内のすべての単語)、データセットを格納することに非常に適しています。 二分木とは異なり、ノードは実際の値と関連付けられません。 代わりに、ノードへの経路が特定のキーを表します。 例えば、文字列 "code" をトライに格納したい場合、c — o — d — e の文字のそれぞれに 1 つずつ、計 4 つのノードがあります。 これらすべてのノードを通る経路をたどると、文字列 "code" が作成されます。私たちはその経路をキーとして保存します。 次に、文字列 "coding" を追加したいとします。そのキーは、d の後に分岐する前の "code" の最初の 3 つのノードを共有します。 こうすれば、大規模なデータセットを非常にコンパクトに保存できます。 また、保存する文字列の長さに完全に限定されるため、検索を非常に素早く行えます。 さらに、二分木とは異なり、ノードは任意の数の子ノードを格納できます。 上の例から分かるように、後の走査でも引き続きキーを取得できるように、そのキーの末尾を持つノードに何らかのメタデータを格納することが一般的です。 例えば、上の例でコードを追加した場合、"code" の "e" は以前に入力されたキーの末尾を表すということを、何らかの方法で知る必要があります。 そうしなければ、コードを追加したときにこの情報は完全に失われます。
|
||||
|
||||
# --instructions--
|
||||
|
||||
単語を格納するためのトライを作成しましょう。 そのトライは、`add` メソッドで単語を受け入れ、それらをトライデータ構造に格納します。 また、与えられた文字列が単語かどうかを問い合わせるために `isWord` メソッドを使ったり、トライに格納されたすべての単語を取得するために `print` メソッドを使ったりできます。 `isWord` はブール値を返し、print はこれらすべての単語の配列を文字列値として返す必要があります。 このデータ構造が正しく実装されていることを確認するために、木の各ノードに `Node` 構造が用意されています。 各ノードは、JavaScript Map オブジェクトである `keys` プロパティを持つオブジェクトです。 これには、各ノードの有効なキーである個々の文字が格納されます。 また、各ノードには `end` プロパティが既に作成されており、ノードが単語の終了を表す場合にこのプロパティを `true` に設定することができます。
|
||||
|
||||
# --hints--
|
||||
|
||||
Trie に add メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function testTrie() {
|
||||
var test = false;
|
||||
if (typeof Trie !== 'undefined') {
|
||||
test = new Trie();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.add == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
Trie に print メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function testTrie() {
|
||||
var test = false;
|
||||
if (typeof Trie !== 'undefined') {
|
||||
test = new Trie();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.print == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
Trie に isWord メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function testTrie() {
|
||||
var test = false;
|
||||
if (typeof Trie !== 'undefined') {
|
||||
test = new Trie();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.isWord == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
print メソッドは、トライに追加されたすべての値を文字列の配列として返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function testTrie() {
|
||||
var test = false;
|
||||
if (typeof Trie !== 'undefined') {
|
||||
test = new Trie();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
test.add('jump');
|
||||
test.add('jumps');
|
||||
test.add('jumped');
|
||||
test.add('house');
|
||||
test.add('mouse');
|
||||
var added = test.print();
|
||||
return (
|
||||
added.indexOf('jump') != -1 &&
|
||||
added.indexOf('jumps') != -1 &&
|
||||
added.indexOf('jumped') != -1 &&
|
||||
added.indexOf('house') != -1 &&
|
||||
added.indexOf('mouse') != -1 &&
|
||||
added.length == 5
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
isWord メソッドは、トライに追加された単語に対してのみ true を返し、他のすべての単語に対して false を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function testTrie() {
|
||||
var test = false;
|
||||
if (typeof Trie !== 'undefined') {
|
||||
test = new Trie();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
test.add('hop');
|
||||
test.add('hops');
|
||||
test.add('hopped');
|
||||
test.add('hoppy');
|
||||
test.add('hope');
|
||||
return (
|
||||
test.isWord('hop') &&
|
||||
!test.isWord('ho') &&
|
||||
test.isWord('hopped') &&
|
||||
!test.isWord('hopp') &&
|
||||
test.isWord('hoppy') &&
|
||||
!test.isWord('hoping')
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
var Node = function() {
|
||||
this.keys = new Map();
|
||||
this.end = false;
|
||||
this.setEnd = function() {
|
||||
this.end = true;
|
||||
};
|
||||
this.isEnd = function() {
|
||||
return this.end;
|
||||
};
|
||||
};
|
||||
var Trie = function() {
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
};
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,45 @@
|
||||
---
|
||||
id: 587d825b367417b2b2512c8d
|
||||
title: ES6 JavaScript マップを作成する
|
||||
challengeType: 1
|
||||
forumTopicId: 301635
|
||||
dashedName: create-an-es6-javascript-map
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
JavaScript の新バージョンでは、前回のチャレンジで手書きした機能の多くを提供する、組み込みの Map ブジェクトが提供されています。 This Map object, although similar to regular JavaScript objects, provides some useful functionality that normal objects lack. For example, an ES6 Map tracks the insertion order of items that are added to it. より網羅的なメソッドの概要を次に示します。`.has(key)` はキーの有無に基づいて true または false を返します。`.get(key)` はキーに関連付けられた値を返します。`.set(key, value)` は新しいキーと値のペアを設定します。`.delete(key)` はキーと値のペアを削除します。`.clear()` はすべてのキーと値のペアを削除します。`.entries()` は挿入順にすべてのキーの配列を返します。`.values()` は挿入順にすべての値の配列を返します。
|
||||
|
||||
# --instructions--
|
||||
|
||||
JavaScript Map オブジェクトを定義し、変数 myMap をそのオブジェクトに割り当ててください。 キーと値のペア `freeCodeCamp`、`Awesome!` (すばらしい!) を追加してください。
|
||||
|
||||
# --hints--
|
||||
|
||||
myMap オブジェクトが存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(typeof myMap === 'object');
|
||||
```
|
||||
|
||||
myMap にはキーと値のペア `freeCodeCamp`、`Awesome!` が含まれている必要があります。
|
||||
|
||||
```js
|
||||
assert(myMap.get('freeCodeCamp') === 'Awesome!');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
const myMap = new Map();
|
||||
|
||||
myMap.set("freeCodeCamp", "Awesome!");
|
||||
```
|
@ -0,0 +1,92 @@
|
||||
---
|
||||
id: 587d8254367417b2b2512c70
|
||||
title: ES6 で Set を作成する・Set に追加する
|
||||
challengeType: 1
|
||||
forumTopicId: 301636
|
||||
dashedName: create-and-add-to-sets-in-es6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
これまで ES5 を使って作業してきた方も、これから ES6 で同じようなことを行います。 その方がはるかに簡単です。 ES6 には `Set` というデータ構造が組み込まれており、これまで手作業で書いていた操作の多くが既に用意されています。 それを見てみましょう。
|
||||
|
||||
新しい空のセット (集合) を作成するには次のようにします。
|
||||
|
||||
```js
|
||||
var set = new Set();
|
||||
```
|
||||
|
||||
1 つの値を持つセットを作成できます。
|
||||
|
||||
```js
|
||||
var set = new Set(1);
|
||||
```
|
||||
|
||||
配列を使用してセットを作成できます。
|
||||
|
||||
```js
|
||||
var set = new Set([1, 2, 3]);
|
||||
```
|
||||
|
||||
セットを作成したら、`add` メソッドを使用して任意の値を追加できます。
|
||||
|
||||
```js
|
||||
var set = new Set([1, 2, 3]);
|
||||
set.add([4, 5, 6]);
|
||||
```
|
||||
|
||||
セットは重複値を含むことができないデータ構造であることを思い出してください。
|
||||
|
||||
```js
|
||||
var set = new Set([1, 2, 3, 1, 2, 3]);
|
||||
// set contains [1, 2, 3] only
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
この演習では、`1、2、3、'Taco'、'Cat'、'Awesome'` という値のセットを返してください。
|
||||
|
||||
# --hints--
|
||||
|
||||
`Set` には `1、2、3、Taco、Cat、Awesome` という値のみを含める必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = checkSet();
|
||||
return (
|
||||
test.size == 6 &&
|
||||
test.has(1) &&
|
||||
test.has(2) &&
|
||||
test.has(3) &&
|
||||
test.has('Taco') &&
|
||||
test.has('Cat') &&
|
||||
test.has('Awesome')
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function checkSet() {
|
||||
var set = new Set([1, 2, 3, 3, 2, 1, 2, 3, 1]);
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
console.log(Array.from(set));
|
||||
return set;
|
||||
}
|
||||
|
||||
checkSet();
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function checkSet(){var set = new Set([1,2,3,'Taco','Cat','Awesome']);
|
||||
return set;}
|
||||
```
|
@ -0,0 +1,216 @@
|
||||
---
|
||||
id: 587d8258367417b2b2512c80
|
||||
title: 二分探索木の葉ノードを削除する
|
||||
challengeType: 1
|
||||
forumTopicId: 301637
|
||||
dashedName: delete-a-leaf-node-in-a-binary-search-tree
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
これは、二分探索木でやや難しい操作を実装する 3 つのチャレンジの 1 つ目、「削除」です。 削除がなぜ難しいかというと、ノードを削除すると木の中でリンクが切れてしまうからです。 二分木構造が維持されるように、これらのリンクを注意深く作り直す必要があります。 つまり、場合によっては削除の際に木の中を再配置する必要があります。 一般的に、ノードを削除しようとすると次の 3 つのケースのいずれかが起こります。「葉ノード」: 削除対象ノードは子を持っていません。 「子が 1 つ」: 削除対象ノードは子を 1 つ持っています。 「子が 2 つ」: 削除対象ノードは子を 2 つ持っています。 葉ノードを削除するのは簡単で、単純にそれを削除します。 1 つの子を持つノードを削除することも比較的簡単です。単純に削除し、その親を、削除したノードの子とリンクさせます。 しかし 2 つの子を持つノードを削除するのは少しやっかいです。親木に再接続する必要のある子ノードが 2 つ生じるからです。 3 つ目のチャレンジで、このケースに対処する方法を見ていきます。 さらに、削除を処理する際には、いくつかのエッジケースに注意する必要があります。 木が空だったらどうでしょうか? 削除するノードが根ノードである場合はどうなるでしょうか? 木に 2 つの要素しかない場合はどうでしょうか? まずは、葉ノードを削除する最初のケースを処理しましょう。
|
||||
|
||||
# --instructions--
|
||||
|
||||
二分木に対して `remove` というメソッドを作成してください。 ここに、削除操作のロジックを構築します。 まず、現在の木で削除しようとしているノードを見つける関数を remove 内に作成します。 木の中にそのノードが存在しない場合、`remove` は `null` を返す必要があります。 対象ノードが子を持たない葉ノードの場合、それへの親参照を `null` に設定する必要があります。 これにより、ノードが木から完全に削除されます。 これを行うには、削除しようとしているノードの親も追跡する必要があります。 また、対象ノードが持つ子の数を追跡するための手段を作ることも有用です。そうすれば、その削除がどのケースに該当するかを判断できるからです。 次のチャレンジでは、第 2 および 第 3 のケースを処理します。 頑張ってください!
|
||||
|
||||
# --hints--
|
||||
|
||||
`BinarySearchTree` データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `remove` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.remove == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
空の木から要素を削除しようすると、`null` が返される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
return test.remove(100) == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
存在しない要素を削除しようとすると、`null` が返される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(15);
|
||||
test.add(30);
|
||||
return test.remove(100) == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
根ノードに子がない場合は、削除すると根が `null` に設定される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(500);
|
||||
test.remove(500);
|
||||
return test.inorder() == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`remove` メソッドは、葉ノードを木から削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(5);
|
||||
test.add(3);
|
||||
test.add(7);
|
||||
test.add(6);
|
||||
test.add(10);
|
||||
test.add(12);
|
||||
test.remove(3);
|
||||
test.remove(12);
|
||||
test.remove(10);
|
||||
return test.inorder().join('') == '567';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
BinarySearchTree.prototype = Object.assign(
|
||||
BinarySearchTree.prototype,
|
||||
{
|
||||
add: function(value) {
|
||||
var node = this.root;
|
||||
if (node == null) {
|
||||
this.root = new Node(value);
|
||||
return;
|
||||
} else {
|
||||
function searchTree(node) {
|
||||
if (value < node.value) {
|
||||
if (node.left == null) {
|
||||
node.left = new Node(value);
|
||||
return;
|
||||
} else if (node.left != null) {
|
||||
return searchTree(node.left);
|
||||
}
|
||||
} else if (value > node.value) {
|
||||
if (node.right == null) {
|
||||
node.right = new Node(value);
|
||||
return;
|
||||
} else if (node.right != null) {
|
||||
return searchTree(node.right);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return searchTree(node);
|
||||
}
|
||||
},
|
||||
inorder: function() {
|
||||
if (this.root == null) {
|
||||
return null;
|
||||
} else {
|
||||
var result = new Array();
|
||||
function traverseInOrder(node) {
|
||||
if (node.left != null) {
|
||||
traverseInOrder(node.left);
|
||||
}
|
||||
result.push(node.value);
|
||||
if (node.right != null) {
|
||||
traverseInOrder(node.right);
|
||||
}
|
||||
}
|
||||
traverseInOrder(this.root);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
// Only change code below this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,285 @@
|
||||
---
|
||||
id: 587d8258367417b2b2512c81
|
||||
title: 1 つの子を持つノードを二分探索木で削除する
|
||||
challengeType: 1
|
||||
forumTopicId: 301638
|
||||
dashedName: delete-a-node-with-one-child-in-a-binary-search-tree
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
葉ノードを削除できるようになったので、2 つ目のケースに進みましょう。つまり、1 つの子を持つノードを削除します。 このケースでは、ノード 1 - 2 - 3 を持つ木があるとします。ここで、1 は根です。 2 を削除するには、1 から 3 への適切な参照を行うだけです。 より一般的には、子を 1 つだけ持つノードを削除するには、そのノードの親がツリー内の次のノードを参照するようにします。
|
||||
|
||||
# --instructions--
|
||||
|
||||
前回のチャレンジのタスクを実行する `remove` メソッドに、既にいくらかコードが記述されています。 削除の対象ノードとその親を見つけ、対象ノードが持つ子の数を定義してください。 ここでは、子を 1 つだけ持つ対象ノードに対して次のケースを追加しましょう。 ここで、その単一の子がツリー内の左側の枝なのか右側の枝なのかを判断し、このノードを指す正しい参照を親に設定する必要があります。 さらに、対象ノードが根ノードであるケース (すなわち親ノードが `null`) を考えてみましょう。 提供されている開始コードをすべて独自のものに書き換えても構いません (それがテストに合格するコードであれば)。
|
||||
|
||||
# --hints--
|
||||
|
||||
`BinarySearchTree` データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `remove` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.remove == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
存在しない要素を削除しようとすると、`null` が返される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
return test.remove(100) == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
根ノードに子がない場合は、根ノードを削除すると根が `null` に設定される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(500);
|
||||
test.remove(500);
|
||||
return test.inorder() == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`remove` メソッドは、葉ノードをツリーから削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(5);
|
||||
test.add(3);
|
||||
test.add(7);
|
||||
test.add(6);
|
||||
test.add(10);
|
||||
test.add(12);
|
||||
test.remove(3);
|
||||
test.remove(12);
|
||||
test.remove(10);
|
||||
return test.inorder().join('') == '567';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`remove` メソッドは、子を 1 つ持つノードを削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(-1);
|
||||
test.add(3);
|
||||
test.add(7);
|
||||
test.add(16);
|
||||
test.remove(16);
|
||||
test.remove(7);
|
||||
test.remove(3);
|
||||
return test.inorder().join('') == '-1';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
2 つのノードを持つ木の根を削除すると、2 番目のノードが根として設定される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(15);
|
||||
test.add(27);
|
||||
test.remove(15);
|
||||
return test.inorder().join('') == '27';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
BinarySearchTree.prototype = Object.assign(
|
||||
BinarySearchTree.prototype,
|
||||
{
|
||||
add: function(value) {
|
||||
var node = this.root;
|
||||
if (node == null) {
|
||||
this.root = new Node(value);
|
||||
return;
|
||||
} else {
|
||||
function searchTree(node) {
|
||||
if (value < node.value) {
|
||||
if (node.left == null) {
|
||||
node.left = new Node(value);
|
||||
return;
|
||||
} else if (node.left != null) {
|
||||
return searchTree(node.left);
|
||||
}
|
||||
} else if (value > node.value) {
|
||||
if (node.right == null) {
|
||||
node.right = new Node(value);
|
||||
return;
|
||||
} else if (node.right != null) {
|
||||
return searchTree(node.right);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return searchTree(node);
|
||||
}
|
||||
},
|
||||
inorder: function() {
|
||||
if (this.root == null) {
|
||||
return null;
|
||||
} else {
|
||||
var result = new Array();
|
||||
function traverseInOrder(node) {
|
||||
if (node.left != null) {
|
||||
traverseInOrder(node.left);
|
||||
}
|
||||
result.push(node.value);
|
||||
if (node.right != null) {
|
||||
traverseInOrder(node.right);
|
||||
}
|
||||
}
|
||||
traverseInOrder(this.root);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
this.remove = function(value) {
|
||||
if (this.root === null) {
|
||||
return null;
|
||||
}
|
||||
var target;
|
||||
var parent = null;
|
||||
// Find the target value and its parent
|
||||
(function findValue(node = this.root) {
|
||||
if (value == node.value) {
|
||||
target = node;
|
||||
} else if (value < node.value && node.left !== null) {
|
||||
parent = node;
|
||||
return findValue(node.left);
|
||||
} else if (value < node.value && node.left === null) {
|
||||
return null;
|
||||
} else if (value > node.value && node.right !== null) {
|
||||
parent = node;
|
||||
return findValue(node.right);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}.bind(this)());
|
||||
if (target === null) {
|
||||
return null;
|
||||
}
|
||||
// Count the children of the target to delete
|
||||
var children =
|
||||
(target.left !== null ? 1 : 0) + (target.right !== null ? 1 : 0);
|
||||
// Case 1: Target has no children
|
||||
if (children === 0) {
|
||||
if (target == this.root) {
|
||||
this.root = null;
|
||||
} else {
|
||||
if (parent.left == target) {
|
||||
parent.left = null;
|
||||
} else {
|
||||
parent.right = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Case 2: Target has one child
|
||||
// Only change code below this line
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,399 @@
|
||||
---
|
||||
id: 587d8258367417b2b2512c82
|
||||
title: 2 つの子を持つノードを二分探索木で削除する
|
||||
challengeType: 1
|
||||
forumTopicId: 301639
|
||||
dashedName: delete-a-node-with-two-children-in-a-binary-search-tree
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
2 つの子を持つノードを削除するのは、最も実装が難しいケースです。 このようなノードを削除すると、元のツリー構造との接続が切れた 2 つの部分木が生じます。 どうすれば再接続できるでしょうか? 一つの方法は、削除対象ノードの右部分木で最小の値を見つけ、対象ノードをこの値に置き換えることです。 このような方法で置き換えると、削除対象ノードは、それが新しい親として持つ、左部分木にあるすべてのノードよりも必ず大きくなると同時に、それが新しい親として持つ、右部分木にあるすべてのノードよりも必ず小さくなります。 この置換が行われたら、置換ノードは右部分木から削除されなければなりません。 この操作でさえ用心が必要です。置換ノードが葉ノードであったり、それ自体が右部分木の親であったりする可能性があるためです。 それが葉ノードである場合は、それに対する親の参照を削除する必要があります。 葉ノードでない場合は、それは削除対象ノードの右側の子でなければなりません。 この場合、削除対象ノードの値を置換値に置き換え、削除対象ノードが置換ノードの右側の子を参照するように設定しなければなりません。
|
||||
|
||||
# --instructions--
|
||||
|
||||
最後に、`remove` メソッドで 3 つ目のケースを処理しましょう。 最初の 2 つのケースのために、今回もコードが用意されています。 2 つの子を持つ対象ノードを処理するコードを追加してください。 意識すべきエッジケースがありますか? 木にノードが 3 つしかない場合はどうでしょうか? これを終えれば、二分探索木の削除操作が完了します。 よくできました、これはかなり難しい問題です!
|
||||
|
||||
# --hints--
|
||||
|
||||
`BinarySearchTree` データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `remove` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.remove == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
存在しない要素を削除しようとすると、`null` が返される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.remove == 'function' ? test.remove(100) == null : false;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
根ノードに子がない場合は、根ノードを削除すると根が `null` に設定される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
test.add(500);
|
||||
test.remove(500);
|
||||
return typeof test.remove == 'function' ? test.inorder() == null : false;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`remove` メソッドは、葉ノードを木から削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
test.add(5);
|
||||
test.add(3);
|
||||
test.add(7);
|
||||
test.add(6);
|
||||
test.add(10);
|
||||
test.add(12);
|
||||
test.remove(3);
|
||||
test.remove(12);
|
||||
test.remove(10);
|
||||
return typeof test.remove == 'function'
|
||||
? test.inorder().join('') == '567'
|
||||
: false;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`remove` メソッドは、子を 1 つ持つノードを削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(-1);
|
||||
test.add(3);
|
||||
test.add(7);
|
||||
test.add(16);
|
||||
test.remove(16);
|
||||
test.remove(7);
|
||||
test.remove(3);
|
||||
return test.inorder().join('') == '-1';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
2 つのノードを持つ木の根を削除すると、2 番目のノードが根として設定される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(15);
|
||||
test.add(27);
|
||||
test.remove(15);
|
||||
return test.inorder().join('') == '27';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`remove` メソッドは二分探索木構造を維持しながら、2 つの子を持つノードを削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(1);
|
||||
test.add(4);
|
||||
test.add(3);
|
||||
test.add(7);
|
||||
test.add(9);
|
||||
test.add(11);
|
||||
test.add(14);
|
||||
test.add(15);
|
||||
test.add(19);
|
||||
test.add(50);
|
||||
test.remove(9);
|
||||
if (!test.isBinarySearchTree()) {
|
||||
return false;
|
||||
}
|
||||
test.remove(11);
|
||||
if (!test.isBinarySearchTree()) {
|
||||
return false;
|
||||
}
|
||||
test.remove(14);
|
||||
if (!test.isBinarySearchTree()) {
|
||||
return false;
|
||||
}
|
||||
test.remove(19);
|
||||
if (!test.isBinarySearchTree()) {
|
||||
return false;
|
||||
}
|
||||
test.remove(3);
|
||||
if (!test.isBinarySearchTree()) {
|
||||
return false;
|
||||
}
|
||||
test.remove(50);
|
||||
if (!test.isBinarySearchTree()) {
|
||||
return false;
|
||||
}
|
||||
test.remove(15);
|
||||
if (!test.isBinarySearchTree()) {
|
||||
return false;
|
||||
}
|
||||
return test.inorder().join('') == '147';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
3 つのノードを持つ木において根を削除できる必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.remove !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(100);
|
||||
test.add(50);
|
||||
test.add(300);
|
||||
test.remove(100);
|
||||
return test.inorder().join('') == 50300;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
BinarySearchTree.prototype = Object.assign(
|
||||
BinarySearchTree.prototype,
|
||||
{
|
||||
add: function(value) {
|
||||
var node = this.root;
|
||||
if (node == null) {
|
||||
this.root = new Node(value);
|
||||
return;
|
||||
} else {
|
||||
function searchTree(node) {
|
||||
if (value < node.value) {
|
||||
if (node.left == null) {
|
||||
node.left = new Node(value);
|
||||
return;
|
||||
} else if (node.left != null) {
|
||||
return searchTree(node.left);
|
||||
}
|
||||
} else if (value > node.value) {
|
||||
if (node.right == null) {
|
||||
node.right = new Node(value);
|
||||
return;
|
||||
} else if (node.right != null) {
|
||||
return searchTree(node.right);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return searchTree(node);
|
||||
}
|
||||
},
|
||||
inorder: function() {
|
||||
if (this.root == null) {
|
||||
return null;
|
||||
} else {
|
||||
var result = new Array();
|
||||
function traverseInOrder(node) {
|
||||
if (node.left != null) {
|
||||
traverseInOrder(node.left);
|
||||
}
|
||||
result.push(node.value);
|
||||
if (node.right != null) {
|
||||
traverseInOrder(node.right);
|
||||
}
|
||||
}
|
||||
traverseInOrder(this.root);
|
||||
return result;
|
||||
}
|
||||
},
|
||||
isBinarySearchTree() {
|
||||
if (this.root == null) {
|
||||
return null;
|
||||
} else {
|
||||
var check = true;
|
||||
function checkTree(node) {
|
||||
if (node.left != null) {
|
||||
var left = node.left;
|
||||
if (left.value > node.value) {
|
||||
check = false;
|
||||
} else {
|
||||
checkTree(left);
|
||||
}
|
||||
}
|
||||
if (node.right != null) {
|
||||
var right = node.right;
|
||||
if (right.value < node.value) {
|
||||
check = false;
|
||||
} else {
|
||||
checkTree(right);
|
||||
}
|
||||
}
|
||||
}
|
||||
checkTree(this.root);
|
||||
return check;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
this.remove = function(value) {
|
||||
if (this.root === null) {
|
||||
return null;
|
||||
}
|
||||
var target;
|
||||
var parent = null;
|
||||
// Find the target value and its parent
|
||||
(function findValue(node = this.root) {
|
||||
if (value == node.value) {
|
||||
target = node;
|
||||
} else if (value < node.value && node.left !== null) {
|
||||
parent = node;
|
||||
return findValue(node.left);
|
||||
} else if (value < node.value && node.left === null) {
|
||||
return null;
|
||||
} else if (value > node.value && node.right !== null) {
|
||||
parent = node;
|
||||
return findValue(node.right);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}.bind(this)());
|
||||
if (target === null) {
|
||||
return null;
|
||||
}
|
||||
// Count the children of the target to delete
|
||||
var children =
|
||||
(target.left !== null ? 1 : 0) + (target.right !== null ? 1 : 0);
|
||||
// Case 1: Target has no children
|
||||
if (children === 0) {
|
||||
if (target == this.root) {
|
||||
this.root = null;
|
||||
} else {
|
||||
if (parent.left == target) {
|
||||
parent.left = null;
|
||||
} else {
|
||||
parent.right = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Case 2: Target has one child
|
||||
else if (children == 1) {
|
||||
var newChild = target.left !== null ? target.left : target.right;
|
||||
if (parent === null) {
|
||||
target.value = newChild.value;
|
||||
target.left = null;
|
||||
target.right = null;
|
||||
} else if (newChild.value < parent.value) {
|
||||
parent.left = newChild;
|
||||
} else {
|
||||
parent.right = newChild;
|
||||
}
|
||||
target = null;
|
||||
}
|
||||
// Case 3: Target has two children
|
||||
// Only change code below this line
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,208 @@
|
||||
---
|
||||
id: 587d825d367417b2b2512c96
|
||||
title: 深さ優先探索
|
||||
challengeType: 1
|
||||
forumTopicId: 301640
|
||||
dashedName: depth-first-search
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
ここでは、<dfn>幅優先探索</dfn>と似ているが別のグラフ走査アルゴリズムである、<dfn>深さ優先探索</dfn>について学びます。
|
||||
|
||||
幅優先探索はソースノードからのエッジの長さを徐々に増やして検索しますが、<dfn>深さ優先探索</dfn>は、最初にエッジの経路のうちの 1 本をできるだけ遠くまで下ります。
|
||||
|
||||
経路の末端に到達すると、検索は訪問されていないエッジ経路を持つ最後のノードに引き返し、検索を続けます。
|
||||
|
||||
下のアニメーションはこのアルゴリズムの仕組みを示しています。 このアルゴリズムは一番上のノードから始まり、番号順にノードを訪問します。
|
||||
|
||||
<img class='img-responsive' src='https://camo.githubusercontent.com/aaad9e39961daf34d967c616edeb50abf3bf1235/68747470733a2f2f75706c6f61642e77696b696d656469612e6f72672f77696b6970656469612f636f6d6d6f6e732f372f37662f44657074682d46697273742d5365617263682e676966' />
|
||||
|
||||
幅優先探索とは異なり、1 つのノードを訪問するたびにすべての隣接ノードを訪れるわけではありません。 代わりに、最初に隣接ノードのいずれかを訪れ、その経路上に未訪問のノードがなくなるまで経路を下り続けます。
|
||||
|
||||
このアルゴリズムを実装するには、スタックを使用すると良いでしょう。 スタックは、最後に追加された要素が最初に削除されるような配列です。 これは、<dfn>後入れ先出し</dfn>のデータ構造とも呼ばれます。 スタックは、深さ優先探索アルゴリズムに役立ちます。なぜなら、スタックに隣接ノードを追加するとき、直近に追加された隣接ノードを最初に訪問してそれをスタックから取り除きたいからです。
|
||||
|
||||
このアルゴリズムの単純な出力は、与えられたノードから到達可能なノードのリストです。 したがって、訪問したノードの追跡も必要でしょう。
|
||||
|
||||
# --instructions--
|
||||
|
||||
無向の隣接行列 `graph` とノードラベル `root` をパラメータとして取る関数、`dfs()` を記述してください。 ノードラベルは単に `0` から `n - 1` の間の数値です (`n` はグラフ内のノードの総数)。
|
||||
|
||||
この関数は、`root` から到達可能なすべてのノードの配列を出力する必要があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
`1` を開始ノードとする入力グラフ `[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]` は、`0`、`1`、`2`、`3` を持つ配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert.sameMembers(
|
||||
(function () {
|
||||
var graph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 1, 0],
|
||||
[0, 1, 0, 1],
|
||||
[0, 0, 1, 0]
|
||||
];
|
||||
return dfs(graph, 1);
|
||||
})(),
|
||||
[0, 1, 2, 3]
|
||||
);
|
||||
```
|
||||
|
||||
`1` を開始ノードとする入力グラフ `[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 1], [0, 0, 1, 0]]` は、4 つの要素を持つ配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var graph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 1, 0],
|
||||
[0, 1, 0, 1],
|
||||
[0, 0, 1, 0]
|
||||
];
|
||||
return dfs(graph, 1);
|
||||
})().length === 4
|
||||
);
|
||||
```
|
||||
|
||||
`3` を開始ノードとする入力グラフ `[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]]` は、`3` を持つ配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert.sameMembers(
|
||||
(function () {
|
||||
var graph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 1, 0],
|
||||
[0, 1, 0, 0],
|
||||
[0, 0, 0, 0]
|
||||
];
|
||||
return dfs(graph, 3);
|
||||
})(),
|
||||
[3]
|
||||
);
|
||||
```
|
||||
|
||||
`3` を開始ノードとする入力グラフ `[[0, 1, 0, 0], [1, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]]` は、1 つの要素を持つ配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var graph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 1, 0],
|
||||
[0, 1, 0, 0],
|
||||
[0, 0, 0, 0]
|
||||
];
|
||||
return dfs(graph, 3);
|
||||
})().length === 1
|
||||
);
|
||||
```
|
||||
|
||||
`3` を開始ノードとする入力グラフ `[[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]`は、`2` と `3` を持つ配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert.sameMembers(
|
||||
(function () {
|
||||
var graph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 0, 0],
|
||||
[0, 0, 0, 1],
|
||||
[0, 0, 1, 0]
|
||||
];
|
||||
return dfs(graph, 3);
|
||||
})(),
|
||||
[2, 3]
|
||||
);
|
||||
```
|
||||
|
||||
`3` を開始ノードとする入力グラフ `[[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]` は、2 つの要素を持つ配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var graph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 0, 0],
|
||||
[0, 0, 0, 1],
|
||||
[0, 0, 1, 0]
|
||||
];
|
||||
return dfs(graph, 3);
|
||||
})().length === 2
|
||||
);
|
||||
```
|
||||
|
||||
`0` を開始ノードとする入力グラフ `[[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]` は、`0` と `1` を持つ配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert.sameMembers(
|
||||
(function () {
|
||||
var graph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 0, 0],
|
||||
[0, 0, 0, 1],
|
||||
[0, 0, 1, 0]
|
||||
];
|
||||
return dfs(graph, 0);
|
||||
})(),
|
||||
[0, 1]
|
||||
);
|
||||
```
|
||||
|
||||
`0` を開始ノードとする入力グラフ `[[0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]` は、2 つの要素を持つ配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var graph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 0, 0],
|
||||
[0, 0, 0, 1],
|
||||
[0, 0, 1, 0]
|
||||
];
|
||||
return dfs(graph, 0);
|
||||
})().length === 2
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function dfs(graph, root) {
|
||||
|
||||
}
|
||||
|
||||
var exDFSGraph = [
|
||||
[0, 1, 0, 0],
|
||||
[1, 0, 1, 0],
|
||||
[0, 1, 0, 1],
|
||||
[0, 0, 1, 0]
|
||||
];
|
||||
console.log(dfs(exDFSGraph, 3));
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function dfs(graph, root) {
|
||||
var stack = [];
|
||||
var tempV;
|
||||
var visited = [];
|
||||
var tempVNeighbors = [];
|
||||
stack.push(root);
|
||||
while (stack.length > 0) {
|
||||
tempV = stack.pop();
|
||||
if (visited.indexOf(tempV) == -1) {
|
||||
visited.push(tempV);
|
||||
tempVNeighbors = graph[tempV];
|
||||
for (var i = 0; i < tempVNeighbors.length; i++) {
|
||||
if (tempVNeighbors[i] == 1) {
|
||||
stack.push(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return visited;
|
||||
}
|
||||
```
|
@ -0,0 +1,346 @@
|
||||
---
|
||||
id: 587d8257367417b2b2512c7d
|
||||
title: 二分探索木の最小と最大の高さを見つける
|
||||
challengeType: 1
|
||||
forumTopicId: 301641
|
||||
dashedName: find-the-minimum-and-maximum-height-of-a-binary-search-tree
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
直前のチャレンジでは、木が不均衡になる (平衡でなくなる) 可能性のあるシナリオを説明しました。 平衡の概念を理解するために、木のもう一つの性質である「高さ」に注目してみましょう。 木の高さは、根ノードから、与えられた葉ノードまでの距離を表します。 分岐の多いツリー構造では経路によって高さが異なる場合がありますが、与えられた木には最小と最大の高さがあります。 平衡木の場合、これらの値の差は最大 1 です。 つまり平衡木では、すべての葉ノードが同じレベル内にあるか、または、同じレベル内でないとしても差は 1 レベル以内です。
|
||||
|
||||
平衡性は、木の操作効率を左右するので木にとって重要なものです。 直前のチャレンジで説明したように、ひどく不均衡な木では最悪ケースの時間計算量になってしまいます。 動的データセットを持つ木でこの問題を考慮するために、平衡木がよく使われます。 その一般的な例としては、AVL 木、赤黒木、B 木などがあります。 これらすべての木には、挿入や削除によって平衡でなくなった木を再び平衡にするための内部ロジックが追加されています。
|
||||
|
||||
**注:**「高さ」と似た性質として「深さ」があります。深さは、与えられたノードが根ノードからどれだけ離れているかを表します。
|
||||
|
||||
# --instructions--
|
||||
|
||||
私たちの二分木に対して 2 つのメソッド、`findMinHeight` と `findMaxHeight` を記述してください。 これらのメソッドは、与えられた二分木の中の最小と最大の高さの整数値をそれぞれ返す必要があります。 ノードが空の場合は、`-1` の高さを割り当てましょう (これは初期条件です)。 最後に、木が平衡であるかどうかに応じて `true` または `false` を返す 3 つ目のメソッド、`isBalanced` を追加してください。 木が平衡かどうかを決定するには、最初の 2 つのメソッドを使用できます。
|
||||
|
||||
# --hints--
|
||||
|
||||
`BinarySearchTree` データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `findMinHeight` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.findMinHeight == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `findMaxHeight` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.findMaxHeight == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `isBalanced` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.isBalanced == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`findMinHeight` メソッドは、木の最小の高さを返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.findMinHeight !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(4);
|
||||
test.add(1);
|
||||
test.add(7);
|
||||
test.add(87);
|
||||
test.add(34);
|
||||
test.add(45);
|
||||
test.add(73);
|
||||
test.add(8);
|
||||
return test.findMinHeight() == 1;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`findMaxHeight` メソッドは、木の最大の高さを返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.findMaxHeight !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(4);
|
||||
test.add(1);
|
||||
test.add(7);
|
||||
test.add(87);
|
||||
test.add(34);
|
||||
test.add(45);
|
||||
test.add(73);
|
||||
test.add(8);
|
||||
return test.findMaxHeight() == 5;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
空の木は `-1` の高さを返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.findMaxHeight !== 'function') {
|
||||
return false;
|
||||
}
|
||||
return test.findMaxHeight() == -1;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`isBalanced` メソッドは、その木が不均衡な二分探索木である場合に `false` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.isBalanced !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(4);
|
||||
test.add(1);
|
||||
test.add(7);
|
||||
test.add(87);
|
||||
test.add(34);
|
||||
test.add(45);
|
||||
test.add(73);
|
||||
test.add(8);
|
||||
return test.isBalanced() === false;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`isBalanced` メソッドは、その木が平衡な二分探索木である場合に `true` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.isBalanced !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(10);
|
||||
test.add(3);
|
||||
test.add(22);
|
||||
test.add(1);
|
||||
test.add(4);
|
||||
test.add(17);
|
||||
test.add(32);
|
||||
return test.isBalanced() === true;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
BinarySearchTree.prototype = Object.assign(
|
||||
BinarySearchTree.prototype,
|
||||
{
|
||||
add: function(value) {
|
||||
function searchTree(node) {
|
||||
if (value < node.value) {
|
||||
if (node.left == null) {
|
||||
node.left = new Node(value);
|
||||
return;
|
||||
} else if (node.left != null) {
|
||||
return searchTree(node.left);
|
||||
}
|
||||
} else if (value > node.value) {
|
||||
if (node.right == null) {
|
||||
node.right = new Node(value);
|
||||
return;
|
||||
} else if (node.right != null) {
|
||||
return searchTree(node.right);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var node = this.root;
|
||||
if (node == null) {
|
||||
this.root = new Node(value);
|
||||
return;
|
||||
} else {
|
||||
return searchTree(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
this.findMinHeight = function(root = this.root) {
|
||||
// empty tree.
|
||||
if (root === null) {
|
||||
return -1;
|
||||
}
|
||||
// leaf node.
|
||||
if (root.left === null && root.right === null) {
|
||||
return 0;
|
||||
}
|
||||
if (root.left === null) {
|
||||
return this.findMinHeight(root.right) + 1;
|
||||
}
|
||||
if (root.right === null) {
|
||||
return this.findMinHeight(root.left) + 1;
|
||||
}
|
||||
const lHeight = this.findMinHeight(root.left);
|
||||
const rHeight = this.findMinHeight(root.right);
|
||||
return Math.min(lHeight, rHeight) + 1;
|
||||
};
|
||||
this.findMaxHeight = function(root = this.root) {
|
||||
// empty tree.
|
||||
if (root === null) {
|
||||
return -1;
|
||||
}
|
||||
// leaf node.
|
||||
if (root.left === null && root.right === null) {
|
||||
return 0;
|
||||
}
|
||||
if (root.left === null) {
|
||||
return this.findMaxHeight(root.right) + 1;
|
||||
}
|
||||
if (root.right === null) {
|
||||
return this.findMaxHeight(root.left) + 1;
|
||||
}
|
||||
const lHeight = this.findMaxHeight(root.left);
|
||||
const rHeight = this.findMaxHeight(root.right);
|
||||
return Math.max(lHeight, rHeight) + 1;
|
||||
};
|
||||
this.isBalanced = function(root = this.root) {
|
||||
if (root === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (root.left === null && root.right === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (root.left === null) {
|
||||
return this.findMaxHeight(root.right) <= 0;
|
||||
}
|
||||
|
||||
if (root.right === null) {
|
||||
return this.findMaxHeight(root.left) <= 0;
|
||||
}
|
||||
|
||||
const lHeight = this.findMaxHeight(root.left);
|
||||
const rHeight = this.findMaxHeight(root.right);
|
||||
if (Math.abs(lHeight - rHeight) > 1) {
|
||||
return false;
|
||||
}
|
||||
return this.isBalanced(root.left) && this.isBalanced(root.right);
|
||||
};
|
||||
}
|
||||
```
|
@ -0,0 +1,369 @@
|
||||
---
|
||||
id: 587d8256367417b2b2512c7a
|
||||
title: 二分探索木の最小値と最大値を見つける
|
||||
challengeType: 1
|
||||
forumTopicId: 301642
|
||||
dashedName: find-the-minimum-and-maximum-value-in-a-binary-search-tree
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
このチャレンジでは、`findMin` と `findMax` の 2 つのメソッドを定義します。 これらのメソッドは、二分探索木の中の最小値と最大値を返す必要があります (今は、木に値を追加することについて考える必要はありません。値を追加するコードが既に用意されています)。 分からなくなったら、二分探索木において必ず真であるべき不変条件を思い出してください。つまり、左部分木はそれぞれがその親以下、右部分木はそれぞれがその親以上でなければなりません。 また、木は整数値のみを格納できるものとしましょう。 木が空の場合、どちらのメソッドも `null` を返す必要があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
`BinarySearchTree` データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `findMin` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.findMin == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `findMax` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.findMax == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`findMin` メソッドは、二分探索木の最小値を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.findMin !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(4);
|
||||
test.add(1);
|
||||
test.add(7);
|
||||
test.add(87);
|
||||
test.add(34);
|
||||
test.add(45);
|
||||
test.add(73);
|
||||
test.add(8);
|
||||
return test.findMin() == 1;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`findMax` メソッドは、二分探索木の最大値を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.findMax !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(4);
|
||||
test.add(1);
|
||||
test.add(7);
|
||||
test.add(87);
|
||||
test.add(34);
|
||||
test.add(45);
|
||||
test.add(73);
|
||||
test.add(8);
|
||||
return test.findMax() == 87;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`findMin` メソッドと `findMax` メソッドは、空の木の場合に `null` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.findMin !== 'function') {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.findMax !== 'function') {
|
||||
return false;
|
||||
}
|
||||
return test.findMin() == null && test.findMax() == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
BinarySearchTree.prototype = Object.assign(
|
||||
BinarySearchTree.prototype,
|
||||
{
|
||||
add: function(value) {
|
||||
function searchTree(node) {
|
||||
if (value < node.value) {
|
||||
if (node.left == null) {
|
||||
node.left = new Node(value);
|
||||
return;
|
||||
} else if (node.left != null) {
|
||||
return searchTree(node.left);
|
||||
}
|
||||
} else if (value > node.value) {
|
||||
if (node.right == null) {
|
||||
node.right = new Node(value);
|
||||
return;
|
||||
} else if (node.right != null) {
|
||||
return searchTree(node.right);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var node = this.root;
|
||||
if (node == null) {
|
||||
this.root = new Node(value);
|
||||
return;
|
||||
} else {
|
||||
return searchTree(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
this.findMin = function() {
|
||||
// Empty tree.
|
||||
if (!this.root) {
|
||||
return null;
|
||||
}
|
||||
let currentNode = this.root;
|
||||
while (currentNode.left) {
|
||||
currentNode = currentNode.left;
|
||||
}
|
||||
return currentNode.value;
|
||||
};
|
||||
this.findMax = function() {
|
||||
// Empty tree.
|
||||
if (!this.root) {
|
||||
return null;
|
||||
}
|
||||
let currentNode = this.root;
|
||||
while (currentNode.right) {
|
||||
currentNode = currentNode.right;
|
||||
}
|
||||
return currentNode.value;
|
||||
};
|
||||
this.add = function(value) {
|
||||
// Empty tree.
|
||||
if (!this.root) {
|
||||
this.root = new Node(value);
|
||||
return undefined;
|
||||
}
|
||||
return this.addNode(this.root, value);
|
||||
};
|
||||
this.addNode = function(node, value) {
|
||||
// Check if value already exists.
|
||||
if (node.value === value) return null;
|
||||
if (value < node.value) {
|
||||
if (node.left) {
|
||||
return this.addNode(node.left, value);
|
||||
} else {
|
||||
node.left = new Node(value);
|
||||
return undefined;
|
||||
}
|
||||
} else {
|
||||
if (node.right) {
|
||||
return this.addNode(node.right, value);
|
||||
} else {
|
||||
node.right = new Node(value);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
};
|
||||
this.isPresent = function(value) {
|
||||
if (!this.root) {
|
||||
return null;
|
||||
}
|
||||
return this.isNodePresent(this.root, value);
|
||||
};
|
||||
this.isNodePresent = function(node, value) {
|
||||
if (node.value === value) return true;
|
||||
if (value < node.value) {
|
||||
return node.left ? this.isNodePresent(node.left, value) : false;
|
||||
} else {
|
||||
return node.right ? this.isNodePresent(node.right, value) : false;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
this.findMinHeight = function() {
|
||||
if (!this.root) {
|
||||
return -1;
|
||||
}
|
||||
let heights = {};
|
||||
let height = 0;
|
||||
this.traverseTree(this.root, height, heights);
|
||||
return Math.min(...Object.keys(heights));
|
||||
};
|
||||
this.findMaxHeight = function() {
|
||||
if (!this.root) {
|
||||
return -1;
|
||||
}
|
||||
let heights = {};
|
||||
let height = 0;
|
||||
this.traverseTree(this.root, height, heights);
|
||||
return Math.max(...Object.keys(heights));
|
||||
};
|
||||
this.traverseTree = function(node, height, heights) {
|
||||
if (node.left === null && node.right === null) {
|
||||
return (heights[height] = true);
|
||||
}
|
||||
if (node.left) {
|
||||
this.traverseTree(node.left, height + 1, heights);
|
||||
}
|
||||
if (node.right) {
|
||||
this.traverseTree(node.right, height + 1, heights);
|
||||
}
|
||||
};
|
||||
this.isBalanced = function() {
|
||||
return this.findMaxHeight() > this.findMinHeight() + 1;
|
||||
};
|
||||
// DFS tree traversal.
|
||||
this.inorder = function() {
|
||||
if (!this.root) return null;
|
||||
let result = [];
|
||||
|
||||
function traverseInOrder(node) {
|
||||
if (node.left) traverseInOrder(node.left);
|
||||
result.push(node.value);
|
||||
if (node.right) traverseInOrder(node.right);
|
||||
}
|
||||
traverseInOrder(this.root);
|
||||
return result;
|
||||
};
|
||||
this.preorder = function() {
|
||||
if (!this.root) return null;
|
||||
let result = [];
|
||||
|
||||
function traverseInOrder(node) {
|
||||
result.push(node.value);
|
||||
if (node.left) traverseInOrder(node.left);
|
||||
if (node.right) traverseInOrder(node.right);
|
||||
}
|
||||
traverseInOrder(this.root);
|
||||
return result;
|
||||
};
|
||||
this.postorder = function() {
|
||||
if (!this.root) return null;
|
||||
let result = [];
|
||||
|
||||
function traverseInOrder(node) {
|
||||
if (node.left) traverseInOrder(node.left);
|
||||
if (node.right) traverseInOrder(node.right);
|
||||
result.push(node.value);
|
||||
}
|
||||
traverseInOrder(this.root);
|
||||
return result;
|
||||
};
|
||||
// BFS tree traversal.
|
||||
this.levelOrder = function() {
|
||||
if (!this.root) return null;
|
||||
let queue = [this.root];
|
||||
let result = [];
|
||||
while (queue.length) {
|
||||
let node = queue.shift();
|
||||
result.push(node.value);
|
||||
if (node.left) queue.push(node.left);
|
||||
if (node.right) queue.push(node.right);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
this.reverseLevelOrder = function() {
|
||||
if (!this.root) return null;
|
||||
let queue = [this.root];
|
||||
let result = [];
|
||||
while (queue.length) {
|
||||
let node = queue.shift();
|
||||
result.push(node.value);
|
||||
if (node.right) queue.push(node.right);
|
||||
if (node.left) queue.push(node.left);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
// Delete a leaf node.
|
||||
}
|
||||
let bst = new BinarySearchTree();
|
||||
```
|
@ -0,0 +1,144 @@
|
||||
---
|
||||
id: 587d825b367417b2b2512c8c
|
||||
title: 最小ヒープでヒープ ソートを実装する
|
||||
challengeType: 1
|
||||
forumTopicId: 301643
|
||||
dashedName: implement-heap-sort-with-a-min-heap
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
要素の追加と削除ができるようになったので、ヒープを使える応用をいくつか見てみましょう。 ヒープは優先度付きキューを実装するためによく使用されます。なぜなら、優先度付きキューは常に、先頭に最大値または最小値の要素を格納するからです。 さらに、ヒープソートと呼ばれるソートアルゴリズムの実装にもヒープが使用されます。 その方法を見ていきましょう。 ヒープソートは、最大ヒープの逆である最小ヒープを使用します。 最小ヒープは常に、最小値である要素を根の位置に格納します。
|
||||
|
||||
ヒープソートの仕組みは、ソートされていない配列を取り、配列内の各要素を最小ヒープに追加し、次に最小ヒープからすべての要素を新しい配列に抽出するというものです。 最小ヒープ構造では、新しい配列に元の要素が必ず最小から最大の順序で格納されます。 これは、平均ケースと最悪ケースのパフォーマンスが O(nlog(n)) である最も効率的なソートアルゴリズムの一つです。
|
||||
|
||||
# --instructions--
|
||||
|
||||
最小ヒープを使ってヒープソートを実装しましょう。 ここでは、自分が書いた最大ヒープのコードを基にしても構いません。 `insert`、`remove`、`sort` の各メソッドを持つオブジェクト `MinHeap` を作成してください。 `sort` メソッドは、最小ヒープ内のすべての要素が最小から最大の順に格納されている配列を返す必要があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
MinHeap データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MinHeap !== 'undefined') {
|
||||
test = new MinHeap();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
MinHeap に insert というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MinHeap !== 'undefined') {
|
||||
test = new MinHeap();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.insert == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
MinHeap に remove というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MinHeap !== 'undefined') {
|
||||
test = new MinHeap();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.remove == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
MinHeap に sort というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MinHeap !== 'undefined') {
|
||||
test = new MinHeap();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.sort == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
sort メソッドは、最小ヒープに追加されたすべての要素がソート順に格納されている配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(() => {
|
||||
if (typeof MinHeap === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const heap = new MinHeap();
|
||||
const arr = createRandomArray(25);
|
||||
|
||||
for (let i of arr) {
|
||||
heap.insert(i);
|
||||
}
|
||||
|
||||
const result = heap.sort();
|
||||
arr.sort((a, b) => a - b);
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
if (arr[i] !== result[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function isSorted(a){
|
||||
for(let i = 0; i < a.length - 1; i++)
|
||||
if(a[i] > a[i + 1])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
// Generate a randomly filled array
|
||||
function createRandomArray(size = 5){
|
||||
let a = new Array(size);
|
||||
for(let i = 0; i < size; i++)
|
||||
a[i] = Math.floor(Math.random() * 100);
|
||||
|
||||
return a;
|
||||
}
|
||||
const array = createRandomArray(25);
|
||||
|
||||
var MinHeap = function() {
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
};
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,110 @@
|
||||
---
|
||||
id: 587d8256367417b2b2512c79
|
||||
title: 接続行列
|
||||
challengeType: 1
|
||||
forumTopicId: 301644
|
||||
dashedName: incidence-matrix
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
グラフを表すもう一つの方法は、 <dfn>接続行列</dfn>に入れることです。
|
||||
|
||||
<dfn>接続行列</dfn> は二次元 (2D) 配列です。 一般に接続行列は、2 つの次元の間で 2 種類のクラスのオブジェクトを関連付けます。 このような行列は隣接行列に似ています。 しかし、行と列の意味がそれとは異なります。
|
||||
|
||||
グラフにはエッジとノードがあります。 この 2 つは、私たちが使う「オブジェクトの 2 種類のクラス」です。 この行列では、行がノード、列がエッジを表します。 したがって、行と列の数が違っていても構いません。
|
||||
|
||||
各列は一意のエッジを表します。 また、各エッジは 2 つのノードを接続します。 2 つのノードの間に 1 本のエッジがあることを示すために、特定の列の 2 行に 1 を入れます。 下に示したのは、ノード 1 とノード 3 の間に 1 本のエッジがある、3 ノードのグラフです。
|
||||
|
||||
<blockquote> 1<br> ---<br>1 | 1<br>2 | 0<br>3 | 1</blockquote>
|
||||
|
||||
4 本のエッジと 4 つのノードを持つ`接続行列`の例を示します。 列はエッジ、行はノード自体であることを思い出してください。
|
||||
|
||||
<blockquote> 1 2 3 4<br> --------<br>1 | 0 1 1 1<br>2 | 1 1 0 0<br>3 | 1 0 0 1<br>4 | 0 0 1 0</blockquote>
|
||||
|
||||
次のコードは、同じことを JavaScript で実装したものです。
|
||||
|
||||
```js
|
||||
var incMat = [
|
||||
[0, 1, 1, 1],
|
||||
[1, 1, 0, 0],
|
||||
[1, 0, 0, 1],
|
||||
[0, 0, 1, 0]
|
||||
];
|
||||
```
|
||||
|
||||
有向グラフを作成するには、特定のノードを離れるエッジに `-1` を使用し、ノードに入るエッジに `1` を使用します。
|
||||
|
||||
```js
|
||||
var incMatDirected = [
|
||||
[ 0, -1, 1, -1],
|
||||
[-1, 1, 0, 0],
|
||||
[ 1, 0, 0, 1],
|
||||
[ 0, 0, -1, 0]
|
||||
];
|
||||
```
|
||||
|
||||
グラフのエッジに <dfn>重み</dfn> を付けることもできます。 これまでに見てきたエッジは、単にエッジの有無が二項 (`0` または `1`) で表された、<dfn>重み付けされていない</dfn>エッジです。 用途によって重みを変えることができます。 異なる重みは 1 より大きい数字として表されます。
|
||||
|
||||
# --instructions--
|
||||
|
||||
5 つのノードと 4 本のエッジを持つ、無向グラフの接続行列を作成してください。 この行列は多次元配列でなければなりません。
|
||||
|
||||
これら 5 つのノードは次のような関係にあります。 1 本目のエッジは 1 番目と 2 番目のノードの間にあります。 2 本目のエッジは 2 番目と 3 番目のノードの間にあります。 3 本目のエッジは 3 番目と 5 番目のノードの間にあります。 4 本目のエッジは 4 番目と 2 番目のノードの間にあります。 すべてのエッジの重みは 1 であり、エッジの順序には意味があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
`incMatUndirected` には 5 つのノードのみが含まれている必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
incMatUndirected.length === 5 &&
|
||||
incMatUndirected
|
||||
.map(function (x) {
|
||||
return x.length === 4;
|
||||
})
|
||||
.reduce(function (a, b) {
|
||||
return a && b;
|
||||
})
|
||||
);
|
||||
```
|
||||
|
||||
1 番目と 2 番目のノードの間には 1 本目のエッジが必要です。
|
||||
|
||||
```js
|
||||
assert(incMatUndirected[0][0] === 1 && incMatUndirected[1][0] === 1);
|
||||
```
|
||||
|
||||
2 番目と 3 番目のノードの間には、2 本目のエッジが必要です。
|
||||
|
||||
```js
|
||||
assert(incMatUndirected[1][1] === 1 && incMatUndirected[2][1] === 1);
|
||||
```
|
||||
|
||||
3 番目と 5 番目のノードの間には、3 本目のエッジが必要です。
|
||||
|
||||
```js
|
||||
assert(incMatUndirected[2][2] === 1 && incMatUndirected[4][2] === 1);
|
||||
```
|
||||
|
||||
2 番目と 4 番目のノードの間には、4 本目のエッジが必要です。
|
||||
|
||||
```js
|
||||
assert(incMatUndirected[1][3] === 1 && incMatUndirected[3][3] === 1);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var incMatUndirected = [
|
||||
|
||||
];
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var incMatUndirected = [[1, 0, 0, 0],[1, 1, 0, 1],[0, 1, 1, 0],[0, 0, 0, 1],[0, 0, 1, 0]];
|
||||
```
|
@ -0,0 +1,165 @@
|
||||
---
|
||||
id: 587d825a367417b2b2512c8a
|
||||
title: 要素を最大ヒープに挿入する
|
||||
challengeType: 1
|
||||
forumTopicId: 301703
|
||||
dashedName: insert-an-element-into-a-max-heap
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
次に、別のツリーデータ構造である二分ヒープに進みます。 二分ヒープは、ヒーププロパティを満たす、部分的に順序付きの二分木です。 ヒーププロパティは、親ノードと子ノードの関係を指定します。 最大ヒープ (すべての親ノードがその子ノード以上であるようなヒープ)、または最小ヒープ (その逆であるヒープ) を持つことができます。 二分ヒープは完全な二分木でもあります。 つまり、木のすべてのレベルが完全に埋まっています。最後のレベルが部分的に埋まっている場合には、左から右に埋まります。
|
||||
|
||||
二分ヒープは、左右の参照を含むノードを持つツリー構造として実装できますが、ヒーププロパティに従って部分的に順序付けすれば、配列を使ってヒープを表現することができます。 ここでは親子関係に注目します。あらゆる親ノードの子と、あらゆる子ノードの親を、簡単な算術で計算することができます。
|
||||
|
||||
例えば、二分最小ヒープを次のような配列で表現することを考えてみましょう。
|
||||
|
||||
```js
|
||||
[ 6, 22, 30, 37, 63, 48, 42, 76 ]
|
||||
```
|
||||
|
||||
根ノードは最初の要素、`6` です。 根ノードの子は `22` と `30` です。 これらの値の配列インデックス間の関係を見てみると、`i` の子要素は `2 * i + 1` および `2 * i + 2` です。 同様に、インデックス `0` にある要素は、インデックス `1` と `2` にある 2 つの子の親です。 より一般的には、`Math.floor(i - 1) / 2)` を使用すれば、任意のインデックスにあるノードの親を見つけることができます。 二分木がどれほど大きくなってもこれらのパターンが当てはまります。 最後に、配列内の最初の要素をスキップするというわずかな調整で、この演算をさらに簡単にできます。 これを行うと、与えられたインデックス `i` にある任意の要素に対して次のような関係が作られます。
|
||||
|
||||
配列表現の例:
|
||||
|
||||
```js
|
||||
[ null, 6, 22, 30, 37, 63, 48, 42, 76 ]
|
||||
```
|
||||
|
||||
要素の左の子: `i * 2`
|
||||
|
||||
要素の右の子: `i * 2 + 1`
|
||||
|
||||
要素の親: `Math.floor(i / 2)`
|
||||
|
||||
この計算を理解してしまえば、配列表現を使うことは非常に便利です。なぜなら、子ノードへの参照を維持する必要がないので、この演算でノード位置が素早く決まり、メモリ使用量が減少するからです。
|
||||
|
||||
# --instructions--
|
||||
|
||||
手順: ここでは最大ヒープを作成してください。 まず、ヒープに要素を追加する `insert` メソッドを作成します。 挿入中は、ヒーププロパティを常に維持することが重要です。 つまり最大ヒープの場合、根要素は常に木の中で最大値を持ち、すべての親ノードは子ノードより大きくなければなりません。 ヒープの配列実装では、通常、これは次の 3 つのステップで実行されます。
|
||||
|
||||
<ol>
|
||||
<li>配列の末尾に新しい要素を追加します。</li>
|
||||
<li>要素が親より大きい場合は、それらを交換します。</li>
|
||||
<li>新しい要素が親より小さくなるまで、または木の根に到達するまで、交換を続けます。</li>
|
||||
</ol>
|
||||
|
||||
最後に、ヒープに追加されたすべての要素の配列を返す `print` メソッドを追加します。
|
||||
|
||||
# --hints--
|
||||
|
||||
MaxHeap データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MaxHeap !== 'undefined') {
|
||||
test = new MaxHeap();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
MaxHeap に insert というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MaxHeap !== 'undefined') {
|
||||
test = new MaxHeap();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.insert == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
MaxHeap に print というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MaxHeap !== 'undefined') {
|
||||
test = new MaxHeap();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.print == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
insert メソッドは最大ヒーププロパティに従って要素を追加する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MaxHeap !== 'undefined') {
|
||||
test = new MaxHeap();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
test.insert(50);
|
||||
test.insert(100);
|
||||
test.insert(700);
|
||||
test.insert(32);
|
||||
test.insert(51);
|
||||
test.insert(800);
|
||||
const result = test.print();
|
||||
const solution = JSON.stringify([null,800,51,700,32,50,100]);
|
||||
const solutionWithoutNull = JSON.stringify([800,51,700,32,50,100]);
|
||||
|
||||
return (result.length == 6) ? (JSON.stringify(result) == solutionWithoutNull) : (JSON.stringify(result) == solution);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var MaxHeap = function() {
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
};
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var MaxHeap = function() {
|
||||
// Only change code below this line
|
||||
this.heap = [];
|
||||
this.parent = index => {
|
||||
return Math.floor((index - 1) / 2);
|
||||
}
|
||||
this.insert = element => {
|
||||
this.heap.push(element);
|
||||
this.heapifyUp(this.heap.length - 1);
|
||||
}
|
||||
this.heapifyUp = index => {
|
||||
let currentIndex = index,
|
||||
parentIndex = this.parent(currentIndex);
|
||||
while (currentIndex > 0 && this.heap[currentIndex] > this.heap[parentIndex]) {
|
||||
this.swap(currentIndex, parentIndex);
|
||||
currentIndex = parentIndex;
|
||||
parentIndex = this.parent(parentIndex);
|
||||
}
|
||||
}
|
||||
this.swap = (index1, index2) => {
|
||||
[this.heap[index1], this.heap[index2]] = [this.heap[index2], this.heap[index1]];
|
||||
}
|
||||
this.print = () => {
|
||||
return this.heap;
|
||||
}
|
||||
// Only change code above this line
|
||||
};
|
||||
```
|
@ -0,0 +1,192 @@
|
||||
---
|
||||
id: 587d8259367417b2b2512c83
|
||||
title: 二分木を反転させる
|
||||
challengeType: 1
|
||||
forumTopicId: 301704
|
||||
dashedName: invert-a-binary-tree
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
ここでは、二分木を反転させる関数を作成します。 与えられた二分木の左右を逆にして新しい木を作りましょう。 反転した木で通りがけ順走査を実行すると、元の木の通りがけ順走査とは逆の順にノードが探索されます。 これを行うための `invert` と呼ばれるメソッドを二分木に対して記述してください。 このメソッドを呼び出すことで現在のツリー構造が反転する必要があります。 線形時間計算量でこれをそのまま行えるのが理想です。 つまり、各ノードを 1 回訪れ、追加のメモリを使用せずに、走査しながら既存のツリー構造を変更します。 頑張ってください!
|
||||
|
||||
# --hints--
|
||||
|
||||
`BinarySearchTree` データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `invert` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.invert == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`invert` メソッドはツリー構造を正しく反転させる必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.invert !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(4);
|
||||
test.add(1);
|
||||
test.add(7);
|
||||
test.add(87);
|
||||
test.add(34);
|
||||
test.add(45);
|
||||
test.add(73);
|
||||
test.add(8);
|
||||
test.invert();
|
||||
return test.inorder().join('') == '877345348741';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
空の木を反転させると、`null` が返される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.invert !== 'function') {
|
||||
return false;
|
||||
}
|
||||
return test.invert() == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
BinarySearchTree.prototype = Object.assign(
|
||||
BinarySearchTree.prototype,
|
||||
{
|
||||
add: function(value) {
|
||||
function searchTree(node) {
|
||||
if (value < node.value) {
|
||||
if (node.left == null) {
|
||||
node.left = new Node(value);
|
||||
return;
|
||||
} else if (node.left != null) {
|
||||
return searchTree(node.left)
|
||||
};
|
||||
} else if (value > node.value) {
|
||||
if (node.right == null) {
|
||||
node.right = new Node(value);
|
||||
return;
|
||||
} else if (node.right != null) {
|
||||
return searchTree(node.right);
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
var node = this.root;
|
||||
if (node == null) {
|
||||
this.root = new Node(value);
|
||||
return;
|
||||
} else {
|
||||
return searchTree(node);
|
||||
};
|
||||
},
|
||||
inorder: function() {
|
||||
if (this.root == null) {
|
||||
return null;
|
||||
} else {
|
||||
var result = new Array();
|
||||
function traverseInOrder(node) {
|
||||
if (node.left != null) {
|
||||
traverseInOrder(node.left);
|
||||
};
|
||||
result.push(node.value);
|
||||
if (node.right != null) {
|
||||
traverseInOrder(node.right);
|
||||
};
|
||||
}
|
||||
traverseInOrder(this.root);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var displayTree = (tree) => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
// Only change code below this line
|
||||
this.invert = function(node = this.root) {
|
||||
if (node) {
|
||||
const temp = node.left;
|
||||
node.left = node.right;
|
||||
node.right = temp;
|
||||
this.invert(node.left);
|
||||
this.invert(node.right);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
@ -0,0 +1,71 @@
|
||||
---
|
||||
id: 587d8250367417b2b2512c5e
|
||||
title: スタックの仕組みを学ぶ
|
||||
challengeType: 1
|
||||
forumTopicId: 301705
|
||||
dashedName: learn-how-a-stack-works
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
机の上に本が積まれていることはよくあるでしょう。 テキストエディタの取り消し機能を使ったことがあるでしょう。 また、携帯電話の「戻る」ボタンを押してアプリを直前の表示に戻すことに慣れているでしょう。
|
||||
|
||||
そのすべてに共通する点は何でしょうか? それらはすべて、後方に走査できるようにデータを格納しています。
|
||||
|
||||
本の山の一番上にある本は、最後に置かれた本でした。 山の一番上からその本を取り除くと、最後の本より先に置かれた本が見え、本を取り除くたびに同じことが起こります。
|
||||
|
||||
そう考えると、上のすべての例で<dfn>後入れ先出し</dfn>タイプのサービスを受けていることになります。 これをコードを使って再現してみましょう。
|
||||
|
||||
このようなデータ保存は<dfn>スタック</dfn>と呼ばれます。 具体的には、JavaScript オブジェクトをスタックの一番上にプッシュする `push()` メソッドと、現在スタックの一番上にある JavaScript オブジェクトを削除する `pop()` メソッドを実装する必要があります。
|
||||
|
||||
# --instructions--
|
||||
|
||||
ここでは、配列で表現された宿題のスタックがあります。`"BIO12"` (生物 12) はスタックの一番下、`"PSY44"` (物理 44) は一番上です。
|
||||
|
||||
与えられた配列を変更し、上述の JavaScript メソッドを使用してそれを `stack` のように扱ってください。 一番上の要素 `"PSY44"` をスタックから削除します。 次に、スタックの新しい一番上の要素として `"CS50"` (コンピュータサイエンス 50) を追加します。
|
||||
|
||||
# --hints--
|
||||
|
||||
`homeworkStack` には 4 つの要素のみが含まれている必要があります。
|
||||
|
||||
```js
|
||||
assert(homeworkStack.length === 4);
|
||||
```
|
||||
|
||||
`homeworkStack` の最後の要素は `"CS50"` でなければなりません。
|
||||
|
||||
```js
|
||||
assert(homeworkStack[3] === 'CS50');
|
||||
```
|
||||
|
||||
`homeworkStack` に `"PSY44"` を含めることはできません。
|
||||
|
||||
```js
|
||||
assert(homeworkStack.indexOf('PSY44') === -1);
|
||||
```
|
||||
|
||||
`homeworkStack` の最初の宣言は変更しないでください。
|
||||
|
||||
```js
|
||||
assert(
|
||||
code.match(/=/g).length === 1 &&
|
||||
/homeworkStack\s*=\s*\["BIO12"\s*,\s*"HIS80"\s*,\s*"MAT122"\s*,\s*"PSY44"\]/.test(
|
||||
code
|
||||
)
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var homeworkStack = ["BIO12","HIS80","MAT122","PSY44"];
|
||||
// Only change code below this line
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,219 @@
|
||||
---
|
||||
id: 587d8254367417b2b2512c6e
|
||||
title: 2 つのデータセットの差集合を求める
|
||||
challengeType: 1
|
||||
forumTopicId: 301706
|
||||
dashedName: perform-a-difference-on-two-sets-of-data
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
この課題では、2 つのデータセットの差集合を求めます。 `difference` と呼ばれる メソッドを `Set` データ構造に作成します。 2 つのセットの差集合を求めるには、2 つのセットを比較して、最初のセットにはあるが 2 番目のセットにはない要素を返す必要があります。 このメソッドは、別の `Set` を引数として取り、2 つのセットの `difference` を返す必要があります。
|
||||
|
||||
例えば、`setA = ['a','b','c']` かつ `setB = ['a','b','d','e']` の場合、setA と setB の差集合は `setA.difference(setB) = ['c']` です。
|
||||
|
||||
# --hints--
|
||||
|
||||
`Set` クラスに `difference` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
return typeof test.difference === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`difference` メソッドは適切なコレクションを返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var setA = new Set();
|
||||
var setB = new Set();
|
||||
setA.add('a');
|
||||
setA.add('b');
|
||||
setA.add('c');
|
||||
setB.add('c');
|
||||
setB.add('d');
|
||||
var differenceSetAB = setA.difference(setB);
|
||||
return (
|
||||
differenceSetAB.size() === 2 &&
|
||||
DeepEqual(differenceSetAB.values(), ['a', 'b'])
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
class Set {
|
||||
constructor() {
|
||||
// This will hold the set
|
||||
this.dictionary = {};
|
||||
this.length = 0;
|
||||
}
|
||||
// This method will check for the presence of an element and return true or false
|
||||
has(element) {
|
||||
return this.dictionary[element] !== undefined;
|
||||
}
|
||||
// This method will return all the values in the set
|
||||
values() {
|
||||
return Object.keys(this.dictionary);
|
||||
}
|
||||
// This method will add an element to the set
|
||||
add(element) {
|
||||
if (!this.has(element)) {
|
||||
this.dictionary[element] = true;
|
||||
this.length++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// This method will remove an element from a set
|
||||
remove(element) {
|
||||
if (this.has(element)) {
|
||||
delete this.dictionary[element];
|
||||
this.length--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// This method will return the size of the set
|
||||
size() {
|
||||
return this.length;
|
||||
}
|
||||
// This is our union method
|
||||
union(set) {
|
||||
const newSet = new Set();
|
||||
this.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
set.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
// This is our intersection method
|
||||
intersection(set) {
|
||||
const newSet = new Set();
|
||||
|
||||
let largeSet;
|
||||
let smallSet;
|
||||
if (this.dictionary.length > set.length) {
|
||||
largeSet = this;
|
||||
smallSet = set;
|
||||
} else {
|
||||
largeSet = set;
|
||||
smallSet = this;
|
||||
}
|
||||
|
||||
smallSet.values().forEach(value => {
|
||||
if (largeSet.dictionary[value]) {
|
||||
newSet.add(value);
|
||||
}
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
class Set {
|
||||
constructor() {
|
||||
this.dictionary = {};
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
has(element) {
|
||||
return this.dictionary[element] !== undefined;
|
||||
}
|
||||
|
||||
values() {
|
||||
return Object.keys(this.dictionary);
|
||||
}
|
||||
|
||||
add(element) {
|
||||
if (!this.has(element)) {
|
||||
this.dictionary[element] = true;
|
||||
this.length++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
remove(element) {
|
||||
if (this.has(element)) {
|
||||
delete this.dictionary[element];
|
||||
this.length--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size() {
|
||||
return this.length;
|
||||
}
|
||||
|
||||
union(set) {
|
||||
const newSet = new Set();
|
||||
this.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
set.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
|
||||
intersection(set) {
|
||||
const newSet = new Set();
|
||||
|
||||
let largeSet;
|
||||
let smallSet;
|
||||
if (this.dictionary.length > set.length) {
|
||||
largeSet = this;
|
||||
smallSet = set;
|
||||
} else {
|
||||
largeSet = set;
|
||||
smallSet = this;
|
||||
}
|
||||
|
||||
smallSet.values().forEach(value => {
|
||||
if (largeSet.dictionary[value]) {
|
||||
newSet.add(value);
|
||||
}
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
|
||||
difference(set) {
|
||||
const newSet = new Set();
|
||||
|
||||
this.values().forEach(value => {
|
||||
if (!set.dictionary[value]) {
|
||||
newSet.add(value);
|
||||
}
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,302 @@
|
||||
---
|
||||
id: 587d8254367417b2b2512c6f
|
||||
title: 2 つのデータセットに対してサブセットチェックを実行する
|
||||
challengeType: 1
|
||||
forumTopicId: 301707
|
||||
dashedName: perform-a-subset-check-on-two-sets-of-data
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
この課題では、2 つのデータセットに対してサブセット (部分集合) テ ストを実行します。 `isSubsetOf` と呼ばれるメソッドを `Set` データ構造に作成します。 これは最初のセットを 2 番目のセットと比較し、最初のセットがすべて 2 番目のセットに含まれている場合に `true` を返します。
|
||||
|
||||
例えば、`setA = ['a','b']` かつ `setB = ['a','b','c','d']` の場合、 `setA` は `setB` のサブセットなので、`setA.isSubsetOf(setB)` は `true` を返す必要があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
`Set` クラスに `isSubsetOf` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
return typeof test.isSubsetOf === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
最初の Set() が 2 番目の Set に含まれている必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var setA = new Set();
|
||||
var setB = new Set();
|
||||
setA.add('a');
|
||||
setB.add('b');
|
||||
setB.add('c');
|
||||
setB.add('a');
|
||||
setB.add('d');
|
||||
var aIsSubsetOfB = setA.isSubsetOf(setB);
|
||||
return aIsSubsetOfB === true;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`['a', 'b'].isSubsetOf(['a', 'b', 'c', 'd'])` は `true` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var setA = new Set();
|
||||
var setB = new Set();
|
||||
setA.add('a');
|
||||
setA.add('b');
|
||||
setB.add('a');
|
||||
setB.add('b');
|
||||
setB.add('c');
|
||||
setB.add('d');
|
||||
var aIsSubsetOfB = setA.isSubsetOf(setB);
|
||||
return aIsSubsetOfB === true;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`['a', 'b', 'c'].isSubsetOf(['a', 'b'])` は `false` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var setA = new Set();
|
||||
var setB = new Set();
|
||||
setA.add('a');
|
||||
setA.add('b');
|
||||
setA.add('c');
|
||||
setB.add('a');
|
||||
setB.add('b');
|
||||
var aIsSubsetOfB = setA.isSubsetOf(setB);
|
||||
return aIsSubsetOfB === false;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`[].isSubsetOf([])` は `true` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var setA = new Set();
|
||||
var setB = new Set();
|
||||
var aIsSubsetOfB = setA.isSubsetOf(setB);
|
||||
return aIsSubsetOfB === true;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`['a', 'b'].isSubsetOf(['c', 'd'])` は `false` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var setA = new Set();
|
||||
var setB = new Set();
|
||||
setA.add('a');
|
||||
setA.add('b');
|
||||
setB.add('c');
|
||||
setB.add('d');
|
||||
var aIsSubsetOfB = setA.isSubsetOf(setB);
|
||||
return aIsSubsetOfB === false;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
class Set {
|
||||
constructor() {
|
||||
// This will hold the set
|
||||
this.dictionary = {};
|
||||
this.length = 0;
|
||||
}
|
||||
// This method will check for the presence of an element and return true or false
|
||||
has(element) {
|
||||
return this.dictionary[element] !== undefined;
|
||||
}
|
||||
// This method will return all the values in the set
|
||||
values() {
|
||||
return Object.keys(this.dictionary);
|
||||
}
|
||||
// This method will add an element to the set
|
||||
add(element) {
|
||||
if (!this.has(element)) {
|
||||
this.dictionary[element] = true;
|
||||
this.length++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// This method will remove an element from a set
|
||||
remove(element) {
|
||||
if (this.has(element)) {
|
||||
delete this.dictionary[element];
|
||||
this.length--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// This method will return the size of the set
|
||||
size() {
|
||||
return this.length;
|
||||
}
|
||||
// This is our union method
|
||||
union(set) {
|
||||
const newSet = new Set();
|
||||
this.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
set.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
// This is our intersection method
|
||||
intersection(set) {
|
||||
const newSet = new Set();
|
||||
|
||||
let largeSet;
|
||||
let smallSet;
|
||||
if (this.dictionary.length > set.length) {
|
||||
largeSet = this;
|
||||
smallSet = set;
|
||||
} else {
|
||||
largeSet = set;
|
||||
smallSet = this;
|
||||
}
|
||||
|
||||
smallSet.values().forEach(value => {
|
||||
if (largeSet.dictionary[value]) {
|
||||
newSet.add(value);
|
||||
}
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
|
||||
difference(set) {
|
||||
const newSet = new Set();
|
||||
|
||||
this.values().forEach(value => {
|
||||
if (!set.dictionary[value]) {
|
||||
newSet.add(value);
|
||||
}
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
class Set {
|
||||
constructor() {
|
||||
this.dictionary = {};
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
has(element) {
|
||||
return this.dictionary[element] !== undefined;
|
||||
}
|
||||
|
||||
values() {
|
||||
return Object.keys(this.dictionary);
|
||||
}
|
||||
|
||||
add(element) {
|
||||
if (!this.has(element)) {
|
||||
this.dictionary[element] = true;
|
||||
this.length++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
remove(element) {
|
||||
if (this.has(element)) {
|
||||
delete this.dictionary[element];
|
||||
this.length--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size() {
|
||||
return this.length;
|
||||
}
|
||||
|
||||
union(set) {
|
||||
const newSet = new Set();
|
||||
this.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
set.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
|
||||
intersection(set) {
|
||||
const newSet = new Set();
|
||||
|
||||
let largeSet;
|
||||
let smallSet;
|
||||
if (this.dictionary.length > set.length) {
|
||||
largeSet = this;
|
||||
smallSet = set;
|
||||
} else {
|
||||
largeSet = set;
|
||||
smallSet = this;
|
||||
}
|
||||
|
||||
smallSet.values().forEach(value => {
|
||||
if (largeSet.dictionary[value]) {
|
||||
newSet.add(value);
|
||||
}
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
|
||||
difference(set) {
|
||||
const newSet = new Set();
|
||||
|
||||
this.values().forEach(value => {
|
||||
if (!set.dictionary[value]) {
|
||||
newSet.add(value);
|
||||
}
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
|
||||
isSubsetOf(set) {
|
||||
for(const value of this.values()){
|
||||
if(!set.dictionary[value]) return false;
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,155 @@
|
||||
---
|
||||
id: 587d8253367417b2b2512c6c
|
||||
title: 2 つのセットの和集合を求める
|
||||
challengeType: 1
|
||||
forumTopicId: 301708
|
||||
dashedName: perform-a-union-on-two-sets
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
この課題では、2 つのデータセットの和集合を求めます。 `union` と呼ばれるメソッドを `Set` データ構造に作成します。 このメソッドは、別の `Set` を引数として取り、重複する値を除外して、2 つのセットの `union` を返す必要があります。
|
||||
|
||||
例えば、`setA = ['a','b','c']` かつ `setB = ['a','b','d','e']` の場合、setA と setB の和集合は `setA.union(setB) = ['a', 'b', 'c', 'd', 'e']` です。
|
||||
|
||||
# --hints--
|
||||
|
||||
`Set` クラスに `union` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
return typeof test.union === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
The union of a Set containing values ["a", "b", "c"] and a Set containing values ["c", "d"] should return a new Set containing values ["a", "b", "c", "d"].
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var setA = new Set();
|
||||
var setB = new Set();
|
||||
setA.add('a');
|
||||
setA.add('b');
|
||||
setA.add('c');
|
||||
setB.add('c');
|
||||
setB.add('d');
|
||||
var unionSetAB = setA.union(setB);
|
||||
var final = unionSetAB.values();
|
||||
return (
|
||||
final.indexOf('a') !== -1 &&
|
||||
final.indexOf('b') !== -1 &&
|
||||
final.indexOf('c') !== -1 &&
|
||||
final.indexOf('d') !== -1 &&
|
||||
final.length === 4
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
class Set {
|
||||
constructor() {
|
||||
// This will hold the set
|
||||
this.dictionary = {};
|
||||
this.length = 0;
|
||||
}
|
||||
// This method will check for the presence of an element and return true or false
|
||||
has(element) {
|
||||
return this.dictionary[element] !== undefined;
|
||||
}
|
||||
// This method will return all the values in the set
|
||||
values() {
|
||||
return Object.values(this.dictionary);
|
||||
}
|
||||
// This method will add an element to the set
|
||||
add(element) {
|
||||
if (!this.has(element)) {
|
||||
this.dictionary[element] = element;
|
||||
this.length++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// This method will remove an element from a set
|
||||
remove(element) {
|
||||
if (this.has(element)) {
|
||||
delete this.dictionary[element];
|
||||
this.length--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// This method will return the size of the set
|
||||
size() {
|
||||
return this.length;
|
||||
}
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
class Set {
|
||||
constructor() {
|
||||
this.dictionary = {};
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
has(element) {
|
||||
return this.dictionary[element] !== undefined;
|
||||
}
|
||||
|
||||
values() {
|
||||
return Object.values(this.dictionary);
|
||||
}
|
||||
|
||||
add(element) {
|
||||
if (!this.has(element)) {
|
||||
this.dictionary[element] = element;
|
||||
this.length++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
remove(element) {
|
||||
if (this.has(element)) {
|
||||
delete this.dictionary[element];
|
||||
this.length--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size() {
|
||||
return this.length;
|
||||
}
|
||||
|
||||
union(set) {
|
||||
const newSet = new Set();
|
||||
this.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
set.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,184 @@
|
||||
---
|
||||
id: 587d8253367417b2b2512c6d
|
||||
title: 2 つのデータセットの積集合を求める
|
||||
challengeType: 1
|
||||
forumTopicId: 301709
|
||||
dashedName: perform-an-intersection-on-two-sets-of-data
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
この課題では、2 つのデータセットの積集合を求めます。 `intersection` と呼ばれるメソッドを `Set` データ構造に作成します。 セットの積集合とは、2 つ以上のセットに共通するすべての値のことです。 このメソッドは、別の `Set` を引数として取り、2 つのセットの `intersection` を返す必要があります。
|
||||
|
||||
例えば、`setA = ['a','b','c']` かつ `setB = ['a','b','d','e']` の場合、setA と setB の積集合は `setA.intersection(setB) = ['a', 'b']` です。
|
||||
|
||||
# --hints--
|
||||
|
||||
`Set` クラスに `intersection` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new Set();
|
||||
return typeof test.intersection === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
適切なコレクションが返される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var setA = new Set();
|
||||
var setB = new Set();
|
||||
setA.add('a');
|
||||
setA.add('b');
|
||||
setA.add('c');
|
||||
setB.add('c');
|
||||
setB.add('d');
|
||||
var intersectionSetAB = setA.intersection(setB);
|
||||
return (
|
||||
intersectionSetAB.size() === 1 && intersectionSetAB.values()[0] === 'c'
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
class Set {
|
||||
constructor() {
|
||||
// This will hold the set
|
||||
this.dictionary = {};
|
||||
this.length = 0;
|
||||
}
|
||||
// This method will check for the presence of an element and return true or false
|
||||
has(element) {
|
||||
return this.dictionary[element] !== undefined;
|
||||
}
|
||||
// This method will return all the values in the set
|
||||
values() {
|
||||
return Object.keys(this.dictionary);
|
||||
}
|
||||
// This method will add an element to the set
|
||||
add(element) {
|
||||
if (!this.has(element)) {
|
||||
this.dictionary[element] = true;
|
||||
this.length++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// This method will remove an element from a set
|
||||
remove(element) {
|
||||
if (this.has(element)) {
|
||||
delete this.dictionary[element];
|
||||
this.length--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
// This method will return the size of the set
|
||||
size() {
|
||||
return this.length;
|
||||
}
|
||||
// This is our union method
|
||||
union(set) {
|
||||
const newSet = new Set();
|
||||
this.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
set.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
class Set {
|
||||
constructor() {
|
||||
this.dictionary = {};
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
has(element) {
|
||||
return this.dictionary[element] !== undefined;
|
||||
}
|
||||
|
||||
values() {
|
||||
return Object.keys(this.dictionary);
|
||||
}
|
||||
|
||||
add(element) {
|
||||
if (!this.has(element)) {
|
||||
this.dictionary[element] = true;
|
||||
this.length++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
remove(element) {
|
||||
if (this.has(element)) {
|
||||
delete this.dictionary[element];
|
||||
this.length--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size() {
|
||||
return this.length;
|
||||
}
|
||||
|
||||
union(set) {
|
||||
const newSet = new Set();
|
||||
this.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
set.values().forEach(value => {
|
||||
newSet.add(value);
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
|
||||
intersection(set) {
|
||||
const newSet = new Set();
|
||||
|
||||
let largeSet;
|
||||
let smallSet;
|
||||
if (this.dictionary.length > set.length) {
|
||||
largeSet = this;
|
||||
smallSet = set;
|
||||
} else {
|
||||
largeSet = set;
|
||||
smallSet = this;
|
||||
}
|
||||
|
||||
smallSet.values().forEach(value => {
|
||||
if (largeSet.dictionary[value]) {
|
||||
newSet.add(value);
|
||||
}
|
||||
})
|
||||
|
||||
return newSet;
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,151 @@
|
||||
---
|
||||
id: 587d825b367417b2b2512c8b
|
||||
title: 最大ヒープから要素を削除する
|
||||
challengeType: 1
|
||||
forumTopicId: 301710
|
||||
dashedName: remove-an-element-from-a-max-heap
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
ヒープに要素を追加できるようになったので、要素を削除する方法を学びましょう。 要素の削除と挿入は、どちらも似たようなロジックが必要です。 最大ヒープでは一般に最大値を削除したいので、単に木の根からそれを抽出すれば良いのです。 これによって木のヒーププロパティが壊れるので、何らかの方法でそれを作り直す必要があります。 通常、最大ヒープの場合は次の方法でそれを行います。
|
||||
|
||||
<ol>
|
||||
<li>ヒープ内の最後の要素を根の位置に移動します。</li>
|
||||
<li>根の子のいずれかが根より大きい場合は、根を、より大きい値の子と交換します。</li>
|
||||
<li>親が両方の子よりも大きくなるまで、または操作が木の最後のレベルに達するまで、交換を続けます。</li>
|
||||
</ol>
|
||||
|
||||
# --instructions--
|
||||
|
||||
手順: `remove` と呼ばれるメソッドを最大ヒープに追加してください。 このメソッドは、最大ヒープに追加された最大値を返し、ヒープから削除する必要があります。 また、ヒーププロパティが維持されるようにヒープの順序を変更する必要があります。 要素を削除した後、ヒープに残っている次の最大の要素が根になる必要があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
MaxHeap データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MaxHeap !== 'undefined') {
|
||||
test = new MaxHeap();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
MaxHeap に print というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MaxHeap !== 'undefined') {
|
||||
test = new MaxHeap();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.print == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
MaxHeap に insert というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MaxHeap !== 'undefined') {
|
||||
test = new MaxHeap();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.insert == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
MaxHeap に remove というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MaxHeap !== 'undefined') {
|
||||
test = new MaxHeap();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.remove == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
remove メソッドは max heap プロパティを維持しながら最大ヒープから最大要素を削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof MaxHeap !== 'undefined') {
|
||||
test = new MaxHeap();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
test.insert(30);
|
||||
test.insert(300);
|
||||
test.insert(500);
|
||||
test.insert(10);
|
||||
let result = [];
|
||||
result.push(test.remove());
|
||||
result.push(test.remove());
|
||||
result.push(test.remove());
|
||||
result.push(test.remove());
|
||||
return result.join('') == '5003003010';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var MaxHeap = function () {
|
||||
this.heap = [];
|
||||
this.parent = index => {
|
||||
return Math.floor((index - 1) / 2);
|
||||
}
|
||||
this.insert = element => {
|
||||
this.heap.push(element);
|
||||
this.heapifyUp(this.heap.length - 1);
|
||||
}
|
||||
this.heapifyUp = index => {
|
||||
let currentIndex = index,
|
||||
parentIndex = this.parent(currentIndex);
|
||||
while (currentIndex > 0 && this.heap[currentIndex] > this.heap[parentIndex]) {
|
||||
this.swap(currentIndex, parentIndex);
|
||||
currentIndex = parentIndex;
|
||||
parentIndex = this.parent(parentIndex);
|
||||
}
|
||||
}
|
||||
this.swap = (index1, index2) => {
|
||||
[this.heap[index1], this.heap[index2]] = [this.heap[index2], this.heap[index1]];
|
||||
}
|
||||
this.print = () => {
|
||||
return this.heap;
|
||||
}
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
};
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
@ -0,0 +1,242 @@
|
||||
---
|
||||
id: 587d8251367417b2b2512c65
|
||||
title: インデックスによってリンクリストから要素を削除する
|
||||
challengeType: 1
|
||||
forumTopicId: 301711
|
||||
dashedName: remove-elements-from-a-linked-list-by-index
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
別のデータ構造の話に移る前に、リンクリストを使って最後の練習をいくつか行いましょう。
|
||||
|
||||
与えられた `index` に位置している `element` を削除する `removeAt` メソッドを書きましょう。 メソッドは `removeAt(index)` と呼ばれる必要があります。 特定の `index` にある `element` を削除するには、リンクリストに沿って移動しながら各ノードの実行数を数え続ける必要があります。
|
||||
|
||||
リンクリストの要素に対して操作を繰り返すための一般的なテクニックは、比較対象ノードを「指し示す」ための <dfn>'runner'</dfn>、すなわち番兵を使用することです。 今回のケースでは、リストの `head` が出発点です。`0` で始まる `currentIndex` 変数で操作を開始します。 `currentIndex` は、ノードが 1 つ渡されるたびに 1 ずつ増加する必要があります。
|
||||
|
||||
[前回のレッスン](/learn/coding-interview-prep/data-structures/remove-elements-from-a-linked-list)で取り上げた `remove(element)` メソッドと同じように、`removeAt(index)` メソッドでノードを削除する際には、リストの残りの部分が孤立しないように注意する必要があります。 削除されたノードへの参照を持つノードに、次のノードへの参照を必ず持たせることにより、ノードの連続性を保ちます。
|
||||
|
||||
# --instructions--
|
||||
|
||||
与えられた `index` に位置しているノードを削除して返す、`removeAt(index)` メソッドを記述してください。 与えられた `index` が負の数であるか、リンクリストの `length` 以上である場合、このメソッドは `null` を返す必要があります。
|
||||
|
||||
**注:** `currentIndex` を数え続けることを忘れないでください。
|
||||
|
||||
# --hints--
|
||||
|
||||
`LinkedList` クラスに `removeAt` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
return typeof test.removeAt === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`removeAt` メソッドは、リンクリストの `length` を 1 減らす必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('kitten');
|
||||
test.removeAt(1);
|
||||
return test.size() === 2;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`removeAt` メソッドは、指定されたインデックスにある要素をリンクリストから削除する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('kitten');
|
||||
test.add('bird');
|
||||
test.removeAt(1);
|
||||
return (
|
||||
JSON.stringify(test.head()) ===
|
||||
'{"element":"cat","next":{"element":"kitten","next":{"element":"bird","next":null}}}'
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
リンクリストに要素が 1 つしかない場合、`removeAt` メソッドは、指定されたインデックスにある要素を削除して返し、リンクリストの長さを減らす必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
var removedItem = test.removeAt(0);
|
||||
return test.head() === null && test.size() === 0 && removedItem === 'cat';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`removeAt` メソッドは、削除されたノードの要素を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('kitten');
|
||||
return test.removeAt(1) === 'dog';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
与えられたインデックスが `0` より小さい場合、`removeAt` メソッドは `null` を返す必要があり、リンクリストを変更してはいけません。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('kitten');
|
||||
var removedItem = test.removeAt(-1);
|
||||
return (
|
||||
removedItem === null &&
|
||||
JSON.stringify(test.head()) ===
|
||||
'{"element":"cat","next":{"element":"dog","next":{"element":"kitten","next":null}}}'
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
与えられたインデックスがリストの `length` 以上である場合、`removeAt` メソッドは `null` を返す必要があり、リンクリストを変更してはいけません。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('kitten');
|
||||
var removedItem = test.removeAt(3);
|
||||
return (
|
||||
removedItem === null &&
|
||||
JSON.stringify(test.head()) ===
|
||||
'{"element":"cat","next":{"element":"dog","next":{"element":"kitten","next":null}}}'
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function LinkedList() {
|
||||
var length = 0;
|
||||
var head = null;
|
||||
|
||||
var Node = function(element){
|
||||
this.element = element;
|
||||
this.next = null;
|
||||
};
|
||||
|
||||
this.size = function(){
|
||||
return length;
|
||||
};
|
||||
|
||||
this.head = function(){
|
||||
return head;
|
||||
};
|
||||
|
||||
this.add = function(element){
|
||||
var node = new Node(element);
|
||||
if(head === null){
|
||||
head = node;
|
||||
} else {
|
||||
var currentNode = head;
|
||||
|
||||
while(currentNode.next){
|
||||
currentNode = currentNode.next;
|
||||
}
|
||||
|
||||
currentNode.next = node;
|
||||
}
|
||||
|
||||
length++;
|
||||
};
|
||||
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function LinkedList() {
|
||||
var length = 0;
|
||||
var head = null;
|
||||
|
||||
var Node = function (element) {
|
||||
this.element = element;
|
||||
this.next = null;
|
||||
};
|
||||
|
||||
this.size = function () {
|
||||
return length;
|
||||
};
|
||||
|
||||
this.head = function () {
|
||||
return head;
|
||||
};
|
||||
|
||||
this.add = function (element) {
|
||||
var node = new Node(element);
|
||||
if (head === null) {
|
||||
head = node;
|
||||
} else {
|
||||
var currentNode = head;
|
||||
|
||||
while (currentNode.next) {
|
||||
currentNode = currentNode.next;
|
||||
}
|
||||
|
||||
currentNode.next = node;
|
||||
}
|
||||
|
||||
length++;
|
||||
};
|
||||
|
||||
this.removeAt = function (index) {
|
||||
var currentNode = head;
|
||||
var previous = head;
|
||||
var count = 0;
|
||||
if (index >= length || index < 0) {
|
||||
return null;
|
||||
}
|
||||
if (index === 0) {
|
||||
var removed = head.element;
|
||||
head = currentNode.next;
|
||||
} else {
|
||||
while (count < index) {
|
||||
previous = currentNode;
|
||||
currentNode = currentNode.next;
|
||||
count++;
|
||||
}
|
||||
var removed = previous.next.element;
|
||||
previous.next = currentNode.next;
|
||||
}
|
||||
length--;
|
||||
return removed;
|
||||
};
|
||||
}
|
||||
```
|
@ -0,0 +1,210 @@
|
||||
---
|
||||
id: 587d8251367417b2b2512c63
|
||||
title: リンクリストから要素を削除する
|
||||
challengeType: 1
|
||||
forumTopicId: 301712
|
||||
dashedName: remove-elements-from-a-linked-list
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
リンクリストの実装に不可欠な重要メソッドがもう一つあります。それは `remove` メソッドです。 このメソッドは、削除したい要素を引数として取り、リストを検索して、その要素が含まれているノードを見つけて削除します。
|
||||
|
||||
リンクリストからノードを削除するときは、削除によってそのリストの残りを誤って孤立させることがないように常に注意を払うことが重要です。 すべてのノードの `next` プロパティが、リスト内でそれに続くノードを指すということを思い出してください。 例えば、中央の要素を取り除く場合、その要素の前のノードの `next` プロパティから、その中央の要素の `next` プロパティ (リスト内の次のノード!) への接続を確保しなければなりません。
|
||||
|
||||
これはかなりややこしく聞こえるかもしれないので、分かりやすい概念モデルとしてにコンガラインの例に戻りましょう。 あなたがコンガラインの中にいて、すぐ前の人がラインを離れるところを想像してください。 ラインを離れたその人はもうラインの誰にも手を置いておらず、あなたは離れた人にもう手を置いていません。 あなたは前に進み、次に見える人に手を置きます。
|
||||
|
||||
削除したい要素が `head` 要素である場合、リンクリストの 2 つ目のノードに `head` を割り当てます。
|
||||
|
||||
# --instructions--
|
||||
|
||||
要素を受け取り、それをリンクリストから削除する `remove` メソッドを記述してください。
|
||||
|
||||
**注:** リストの `length` は、リンクリストから要素が削除されるたびに 1 ずつ減少する必要があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
`LinkedList` クラスに `remove` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
return typeof test.remove === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`remove` メソッドは、最初のノードが削除されたときに、`head` を2 つ目のノードに再割り当てする必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.remove('cat');
|
||||
return test.head().element === 'dog';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`remove` メソッドは、ノードが 1 つ削除されるたびにリンクリストの `length` を 1 ずつ減らす必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('hamster');
|
||||
test.remove('cat');
|
||||
test.remove('fish');
|
||||
return test.size() === 2;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`remove` メソッドは、削除されたノードの前のノードの参照を、削除されたノードの `next` 参照に再割り当てする必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('snake');
|
||||
test.add('kitten');
|
||||
test.remove('snake');
|
||||
return test.head().next.next.element === 'kitten';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`remove` メソッドは、リンクリストに要素が存在しない場合にリンクリストを変更してはいけません。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('kitten');
|
||||
test.remove('elephant');
|
||||
return (
|
||||
JSON.stringify(test.head()) ===
|
||||
'{"element":"cat","next":{"element":"dog","next":{"element":"kitten","next":null}}}'
|
||||
);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function LinkedList() {
|
||||
var length = 0;
|
||||
var head = null;
|
||||
|
||||
var Node = function(element){
|
||||
this.element = element;
|
||||
this.next = null;
|
||||
};
|
||||
|
||||
this.size = function(){
|
||||
return length;
|
||||
};
|
||||
|
||||
this.head = function(){
|
||||
return head;
|
||||
};
|
||||
|
||||
this.add = function(element){
|
||||
var node = new Node(element);
|
||||
if(head === null){
|
||||
head = node;
|
||||
} else {
|
||||
var currentNode = head;
|
||||
|
||||
while(currentNode.next){
|
||||
currentNode = currentNode.next;
|
||||
}
|
||||
|
||||
currentNode.next = node;
|
||||
}
|
||||
|
||||
length++;
|
||||
};
|
||||
|
||||
this.remove = function(element){
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function LinkedList() {
|
||||
var length = 0;
|
||||
var head = null;
|
||||
|
||||
var Node = function(element){
|
||||
this.element = element;
|
||||
this.next = null;
|
||||
};
|
||||
|
||||
this.size = function(){
|
||||
return length;
|
||||
};
|
||||
|
||||
this.head = function(){
|
||||
return head;
|
||||
};
|
||||
|
||||
this.add = function(element){
|
||||
var node = new Node(element);
|
||||
if(head === null){
|
||||
head = node;
|
||||
} else {
|
||||
var currentNode = head;
|
||||
|
||||
while(currentNode.next){
|
||||
currentNode = currentNode.next;
|
||||
}
|
||||
|
||||
currentNode.next = node;
|
||||
}
|
||||
|
||||
length++;
|
||||
};
|
||||
|
||||
this.remove = function(element){
|
||||
if (head === null) {
|
||||
return;
|
||||
}
|
||||
var previous;
|
||||
var currentNode = head;
|
||||
|
||||
while (currentNode.next !== null && currentNode.element !== element) {
|
||||
previous = currentNode;
|
||||
currentNode = currentNode.next;
|
||||
}
|
||||
|
||||
if (currentNode.next === null && currentNode.element !== element) {
|
||||
return;
|
||||
}
|
||||
else if (previous) {
|
||||
previous.next = currentNode.next;
|
||||
} else {
|
||||
head = currentNode.next;
|
||||
}
|
||||
|
||||
length--;
|
||||
};
|
||||
}
|
||||
```
|
@ -0,0 +1,67 @@
|
||||
---
|
||||
id: 587d8254367417b2b2512c71
|
||||
title: ES6 でセットから要素を削除する
|
||||
challengeType: 1
|
||||
forumTopicId: 301713
|
||||
dashedName: remove-items-from-a-set-in-es6
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
`delete` メソッドを使って ES6 のセットから要素を削除する方法を練習しましょう。
|
||||
|
||||
まず、ES6のセットを作成します。
|
||||
|
||||
```js
|
||||
var set = new Set([1,2,3]);
|
||||
```
|
||||
|
||||
次に、`delete` メソッドを使用してセットから要素を削除します。
|
||||
|
||||
```js
|
||||
set.delete(1);
|
||||
console.log([...set]) // should return [ 2, 3 ]
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
整数 1、2、3、4、5 を使ってセットを作成してください。
|
||||
|
||||
値 2 と 5 を削除してから、セットを返します。
|
||||
|
||||
# --hints--
|
||||
|
||||
セットには、値 1、3、4 が含まれている必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = checkSet();
|
||||
return test.has(1) && test.has(3) && test.has(4) && test.size === 3;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function checkSet(){
|
||||
// Only change code below this line
|
||||
var set = null;
|
||||
|
||||
// Only change code above this line
|
||||
return set;
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function checkSet(){
|
||||
var set = new Set([1,2,3,4,5]);
|
||||
set.delete(2);
|
||||
set.delete(5);
|
||||
return set;}
|
||||
```
|
@ -0,0 +1,205 @@
|
||||
---
|
||||
id: 587d825a367417b2b2512c88
|
||||
title: 二重リンクリストを逆順にする
|
||||
challengeType: 1
|
||||
forumTopicId: 301714
|
||||
dashedName: reverse-a-doubly-linked-list
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
二重リンクリストに対して、通りがけ順にリストを逆にする reverse というメソッドを作りましょう。 このメソッドが実行されると、ヘッドは以前のテールを指し、テールは以前のヘッドを指します。 こうすると、ヘッドからテールまでリストを走査したときに、元のリストとは逆の順序でノードを訪問することになります。 空のリストを逆順にしようとすると、null が返される必要があります。
|
||||
|
||||
# --hints--
|
||||
|
||||
DoublyLinkedList データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
DoublyLinkedList に reverse というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
if (test.reverse == undefined) {
|
||||
return false;
|
||||
}
|
||||
return typeof test.reverse == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
空のリストを逆順にすると、null が返される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
return test.reverse() == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
reverse メソッドはリストを逆順にする必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
test.add(58);
|
||||
test.add(61);
|
||||
test.add(32);
|
||||
test.add(95);
|
||||
test.add(41);
|
||||
test.reverse();
|
||||
return test.print().join('') == '4195326158';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
リストが逆順になったとき、次の参照と前の参照が正しく維持される必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof DoublyLinkedList !== 'undefined') {
|
||||
test = new DoublyLinkedList();
|
||||
}
|
||||
test.add(11);
|
||||
test.add(22);
|
||||
test.add(33);
|
||||
test.add(44);
|
||||
test.add(55);
|
||||
test.reverse();
|
||||
return test.printReverse().join('') == '1122334455';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
DoublyLinkedList.prototype = Object.assign(
|
||||
DoublyLinkedList.prototype,
|
||||
{
|
||||
add(data) {
|
||||
if (this.head == null) {
|
||||
this.head = new Node(data, null);
|
||||
this.tail = this.head;
|
||||
} else {
|
||||
var node = this.head;
|
||||
var prev = null;
|
||||
while (node.next != null) {
|
||||
prev = node;
|
||||
node = node.next;
|
||||
};
|
||||
var newNode = new Node(data, node);
|
||||
node.next = newNode;
|
||||
this.tail = newNode;
|
||||
};
|
||||
},
|
||||
print() {
|
||||
if (this.head == null) {
|
||||
return null;
|
||||
} else {
|
||||
var result = new Array();
|
||||
var node = this.head;
|
||||
while (node.next != null) {
|
||||
result.push(node.data);
|
||||
node = node.next;
|
||||
};
|
||||
result.push(node.data);
|
||||
return result;
|
||||
};
|
||||
},
|
||||
printReverse() {
|
||||
if (this.tail == null) {
|
||||
return null;
|
||||
} else {
|
||||
var result = new Array();
|
||||
var node = this.tail;
|
||||
while (node.prev != null) {
|
||||
result.push(node.data);
|
||||
node = node.prev;
|
||||
};
|
||||
result.push(node.data);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var Node = function(data, prev) {
|
||||
this.data = data;
|
||||
this.prev = prev;
|
||||
this.next = null;
|
||||
};
|
||||
var DoublyLinkedList = function() {
|
||||
this.head = null;
|
||||
this.tail = null;
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
};
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var Node = function(data, prev) {
|
||||
this.data = data;
|
||||
this.prev = prev;
|
||||
this.next = null;
|
||||
};
|
||||
var DoublyLinkedList = function() {
|
||||
this.head = null;
|
||||
this.tail = null;
|
||||
|
||||
this.reverse = function() {
|
||||
if (!this.head || !this.head.next) {
|
||||
return this.head
|
||||
}
|
||||
|
||||
let tail;
|
||||
let temp;
|
||||
let current = this.head;
|
||||
while(current !== null) {
|
||||
if(!tail) tail = current;
|
||||
temp = current.prev;
|
||||
current.prev = current.next;
|
||||
current.next = temp;
|
||||
current = current.prev;
|
||||
}
|
||||
|
||||
this.head = temp.prev;
|
||||
this.tail = tail
|
||||
}
|
||||
};
|
||||
```
|
@ -0,0 +1,293 @@
|
||||
---
|
||||
id: 587d8251367417b2b2512c64
|
||||
title: リンクリスト内で検索する
|
||||
challengeType: 1
|
||||
forumTopicId: 301715
|
||||
dashedName: search-within-a-linked-list
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
作成したリンクリストクラスに、便利なメソッドをもう少し追加しましょう。 `Stack` クラスや `Queue` クラスと同じように、リストが空かどうかを知ることができたら便利ではありませんか?
|
||||
|
||||
リンクリスト内の特定の要素を見つけることもできるはずです。 データ構造の走査はたくさん練習しなければなりません! `element` を引数として取り、リンクリスト内におけるその要素の `index` を返す、`indexOf` メソッドを作成しましょう。 リンクリスト内にその要素が見つからない場合は、`-1` を返してください。
|
||||
|
||||
また、逆のことをする `elementAt` メソッドも実装しましょう。このメソッドは `index` を引数として取り、与えられた `index` にある `element` を返します。 `element` が見つからない場合は `undefined` を返します。
|
||||
|
||||
# --instructions--
|
||||
|
||||
リンクリストが空かどうかを調べる `isEmpty` メソッド、与えられた要素の `index` を返す `indexOf` メソッド、および、与えられた `index` にある `element` を返す `elementAt` メソッドを記述してください。
|
||||
|
||||
# --hints--
|
||||
|
||||
`LinkedList` クラスに `isEmpty` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
return typeof test.isEmpty === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
リンクリストに 1 つ以上の要素がある場合、`isEmpty` メソッドは `false` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('kitten');
|
||||
return test.isEmpty() === false;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
リンクリストに要素がない場合、`isEmpty` メソッドは `true` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
return test.isEmpty() === true;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`LinkedList` クラスに `indexOf` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
return typeof test.indexOf === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`indexOf` メソッドは、リンクリスト内で見つかった、与えられた要素のインデックスを返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('kitten');
|
||||
return test.indexOf('cat') === 0;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
与えられた要素がリンクリスト内に見つからない場合、`indexOf` メソッドは `-1` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('kitten');
|
||||
return test.indexOf('pony') === -1;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`LinkedList` クラスに `elementAt` メソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
return typeof test.elementAt === 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`elementAt` メソッドは、リンクリスト内の与えられたインデックスで見つかった要素を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('kitten');
|
||||
return test.elementAt(1) === 'dog';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`elementAt` メソッドは、リンクリスト内の与えられたインデックスに、与えられた要素が見つからない場合、`undefined` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = new LinkedList();
|
||||
test.add('cat');
|
||||
test.add('dog');
|
||||
test.add('kitten');
|
||||
return test.elementAt(5) === undefined;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function LinkedList() {
|
||||
var length = 0;
|
||||
var head = null;
|
||||
|
||||
var Node = function(element){
|
||||
this.element = element;
|
||||
this.next = null;
|
||||
};
|
||||
|
||||
this.size = function() {
|
||||
return length;
|
||||
};
|
||||
|
||||
this.head = function(){
|
||||
return head;
|
||||
};
|
||||
|
||||
this.add = function(element){
|
||||
var node = new Node(element);
|
||||
if(head === null){
|
||||
head = node;
|
||||
} else {
|
||||
var currentNode = head;
|
||||
|
||||
while(currentNode.next){
|
||||
currentNode = currentNode.next;
|
||||
}
|
||||
|
||||
currentNode.next = node;
|
||||
}
|
||||
|
||||
length++;
|
||||
};
|
||||
|
||||
this.remove = function(element){
|
||||
var currentNode = head;
|
||||
var previousNode;
|
||||
if(currentNode.element === element){
|
||||
head = currentNode.next;
|
||||
} else {
|
||||
while(currentNode.element !== element) {
|
||||
previousNode = currentNode;
|
||||
currentNode = currentNode.next;
|
||||
}
|
||||
|
||||
previousNode.next = currentNode.next;
|
||||
}
|
||||
|
||||
length --;
|
||||
};
|
||||
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function LinkedList() {
|
||||
var length = 0;
|
||||
var head = null;
|
||||
|
||||
var Node = function(element){
|
||||
this.element = element;
|
||||
this.next = null;
|
||||
};
|
||||
|
||||
this.size = function() {
|
||||
return length;
|
||||
};
|
||||
|
||||
this.head = function(){
|
||||
return head;
|
||||
};
|
||||
|
||||
this.add = function(element){
|
||||
var node = new Node(element);
|
||||
if(head === null){
|
||||
head = node;
|
||||
} else {
|
||||
var currentNode = head;
|
||||
|
||||
while(currentNode.next){
|
||||
currentNode = currentNode.next;
|
||||
}
|
||||
|
||||
currentNode.next = node;
|
||||
}
|
||||
|
||||
length++;
|
||||
};
|
||||
|
||||
this.remove = function(element){
|
||||
var currentNode = head;
|
||||
var previousNode;
|
||||
if(currentNode.element === element){
|
||||
head = currentNode.next;
|
||||
} else {
|
||||
while(currentNode.element !== element) {
|
||||
previousNode = currentNode;
|
||||
currentNode = currentNode.next;
|
||||
}
|
||||
|
||||
previousNode.next = currentNode.next;
|
||||
}
|
||||
|
||||
length --;
|
||||
};
|
||||
|
||||
this.indexOf = function(element) {
|
||||
if (head === null) return -1
|
||||
|
||||
let current = head;
|
||||
let index = 0;
|
||||
|
||||
while (current.element !== element && current.next !== null) {
|
||||
current = current.next;
|
||||
index++
|
||||
}
|
||||
|
||||
if (current.element !== element && current.next === null) {
|
||||
return -1
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
this.elementAt = function(index) {
|
||||
if (head === null) return undefined;
|
||||
|
||||
let current = head;
|
||||
let currentIndex = 0;
|
||||
|
||||
while (currentIndex !== index && current.next !== null) {
|
||||
current = current.next;
|
||||
currentIndex++
|
||||
}
|
||||
|
||||
if (currentIndex !== index && current.next === null) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return current.element;
|
||||
}
|
||||
|
||||
this.isEmpty = function() {
|
||||
return length === 0;
|
||||
}
|
||||
}
|
||||
```
|
@ -0,0 +1,94 @@
|
||||
---
|
||||
id: 587d8253367417b2b2512c6a
|
||||
title: 型付き配列
|
||||
challengeType: 1
|
||||
forumTopicId: 301716
|
||||
dashedName: typed-arrays
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
配列は、さまざまな要素を大量に保持できる JavaScript オブジェクトです。
|
||||
|
||||
```js
|
||||
var complexArr = [1, 5, "2", "Word", {"name": "James"}];
|
||||
```
|
||||
|
||||
バックグラウンドで行われることは、基本的に、ブラウザがその配列に対して適切なメモリ空間を自動的に与えることです。 データの追加や削除を行ったときも、必要に応じてメモリ空間が変化します。
|
||||
|
||||
しかし、高いパフォーマンスと多様な要素型が求められる世界では、配列に与えるメモリの量をより具体的に指定しなければならない場合があります。
|
||||
|
||||
それを可能にするのが<dfn>型付き配列</dfn> です。 これで、配列に与えるメモリの量を指定できるようになります。 利用可能な配列型の基本概要と、その配列に含まれる各要素のサイズ (バイト数) は次の通りです。
|
||||
|
||||
<table class='table table-striped'><tbody><tr><th>型</th><th>各要素のサイズ (バイト数)</th></tr><tr><td><code>Int8Array</code></td><td>1</td></tr><tr><td><code>Uint8Array</code></td><td>1</td></tr><tr><td><code>Uint8ClampedArray</code></td><td>1</td></tr><tr><td><code>Int16Array</code></td><td>2</td></tr><tr><td><code>Uint16Array</code></td><td>2</td></tr><tr><td><code>Int32Array</code></td><td>4</td></tr><tr><td><code>Uint32Array</code></td><td>4</td></tr><tr><td><code>Float32Array</code></td><td>4</td></tr><tr><td><code>Float64Array</code></td><td>8</td></tr></tbody></table>
|
||||
|
||||
これらのような配列を作る方法は 2 つあります。 方法の一つは、配列を直接作成することです。 長さ 3 の `Int16Array` を作成するには、次のようにします。
|
||||
|
||||
```js
|
||||
var i8 = new Int16Array(3);
|
||||
console.log(i8);
|
||||
// Returns [0, 0, 0]
|
||||
```
|
||||
|
||||
また、<dfn>バッファ</dfn>を作成して、配列が受け取るデータ量 (バイト数) を割り当てることもできます。 **注**
|
||||
バッファを使って型付き配列を作成するには、割り当てるバイト数を、上に示したバイト数の倍数にする必要があります。
|
||||
|
||||
```js
|
||||
// Create same Int16Array array differently
|
||||
var byteSize = 6; // Needs to be multiple of 2
|
||||
var buffer = new ArrayBuffer(byteSize);
|
||||
var i8View = new Int16Array(buffer);
|
||||
buffer.byteLength; // Returns 6
|
||||
i8View.byteLength; // Returns 6
|
||||
console.log(i8View); // Returns [0, 0, 0]
|
||||
```
|
||||
|
||||
<dfn>バッファ</dfn>は、データを保持するだけの汎用オブジェクトです。 通常、バッファにアクセスすることはできません。 アクセスするには、先に<dfn>ビュー</dfn>を作成する必要があります。
|
||||
|
||||
```js
|
||||
i8View[0] = 42;
|
||||
console.log(i8View); // Returns [42, 0, 0]
|
||||
```
|
||||
|
||||
**注**
|
||||
型付き配列には、普通の配列が持つメソッドの一部、例えば `.pop()` や `.push()` がありません。 また、型付き配列では、対象物が配列であるかを調べる `Array.isArray()` が失敗します。 この配列は比較的単純ですが、そのことは、旧来の JavaScript エンジンに実装する際の長所になり得ます。
|
||||
|
||||
# --instructions--
|
||||
|
||||
最初に 64 バイトの `buffer` を作成してください。 次に、`i32View` と呼ばれるビューを持つ `Int32Array` 型の配列を作成してください。
|
||||
|
||||
# --hints--
|
||||
|
||||
`buffer` のサイズを 64 バイトにする必要があります。
|
||||
|
||||
```js
|
||||
assert(buffer.byteLength === 64);
|
||||
```
|
||||
|
||||
バッファの `i32View` ビューのサイズを 64 バイトにする必要があります。
|
||||
|
||||
```js
|
||||
assert(i32View.byteLength === 64);
|
||||
```
|
||||
|
||||
バッファの `i32View` ビューの長さを 16 要素にする必要があります。
|
||||
|
||||
```js
|
||||
assert(i32View.length === 16);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var buffer;
|
||||
var i32View;
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var buffer = new ArrayBuffer(64);
|
||||
var i32View = new Int32Array(buffer);
|
||||
```
|
@ -0,0 +1,73 @@
|
||||
---
|
||||
id: 587d8255367417b2b2512c72
|
||||
title: ES6 Set に .has と .size を使用する
|
||||
challengeType: 1
|
||||
forumTopicId: 301717
|
||||
dashedName: use--has-and--size-on-an-es6-set
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
ES6 Set オブジェクトで利用できる .has メソッドと .size メソッドを見てみましょう。
|
||||
|
||||
まず、ES6 Set を作成します。
|
||||
|
||||
```js
|
||||
var set = new Set([1,2,3]);
|
||||
```
|
||||
|
||||
.has メソッドは、その値がセットに含まれているかどうかを調べます。
|
||||
|
||||
```js
|
||||
var hasTwo = set.has(2);
|
||||
```
|
||||
|
||||
.size メソッドは、セットのサイズを表す整数を返します。
|
||||
|
||||
```js
|
||||
var howBig = set.size;
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
この課題では、checkSet() 関数に配列と値を渡します。 この関数は配列引数から ES6 Set を作成します。 値の引数がセットに含まれているかどうかを調べてください。 セットのサイズを求めてください。 そして、配列内のこれら 2 つの値を返してください。
|
||||
|
||||
# --hints--
|
||||
|
||||
`checkSet([4, 5, 6], 3)` は [false, 3 ] を返す必要があります
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = checkSet([4, 5, 6], 3);
|
||||
return DeepEqual(test, [false, 3]);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function checkSet(arrToBeSet, checkValue){
|
||||
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function checkSet(arrToBeSet, checkValue){
|
||||
var set = new Set(arrToBeSet);
|
||||
var result = [
|
||||
set.has(checkValue),
|
||||
set.size
|
||||
];
|
||||
return result;
|
||||
}
|
||||
```
|
@ -0,0 +1,261 @@
|
||||
---
|
||||
id: 587d8258367417b2b2512c7f
|
||||
title: 二分探索木に幅優先探索を使用する
|
||||
challengeType: 1
|
||||
forumTopicId: 301718
|
||||
dashedName: use-breadth-first-search-in-a-binary-search-tree
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
ここでは、木を走査するもう一つの方法である幅優先探索について説明します。 直前のチャレンジで学んだ深さ優先探索とは対照的に、幅優先探索は、次のレベルに進む前に、木の中において与えられたレベルに位置するノードをすべて探索します。 一般に、幅優先探索アルゴリズムの設計において、ヘルパーデータ構造としてキューが利用されます。
|
||||
|
||||
このメソッドでは、まず、キューに根ノードを追加します。 次に、キューの先頭要素をキューから取り出す操作のループを開始し、それを新しい配列に追加し、次に、その要素の子部分木を両方とも調べます。 子が null でない場合、それぞれがキューに追加されます。 このプロセスはキューが空になるまで続きます。
|
||||
|
||||
# --instructions--
|
||||
|
||||
`levelOrder` という名前の木に幅優先探索メソッドを作成しましょう。 このメソッドは、幅優先方式で探索された、すべての木ノードの値が含まれている配列を返す必要があります。 ノード自体ではなく、配列の値を返すようにしてください。 各レベルは左から右へ走査される必要があります。 次に、これに似た `reverseLevelOrder` と呼ばれるメソッドを書きましょう。このメソッドは同じ探索を行いますが、各レベルでの方向が逆 (右から左) になります。
|
||||
|
||||
# --hints--
|
||||
|
||||
`BinarySearchTree` データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `levelOrder` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.levelOrder == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `reverseLevelOrder` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.reverseLevelOrder == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`levelOrder` メソッドは、レベル順に探索された木ノード値の配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.levelOrder !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(7);
|
||||
test.add(1);
|
||||
test.add(9);
|
||||
test.add(0);
|
||||
test.add(3);
|
||||
test.add(8);
|
||||
test.add(10);
|
||||
test.add(2);
|
||||
test.add(5);
|
||||
test.add(4);
|
||||
test.add(6);
|
||||
return test.levelOrder().join('') == '719038102546';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`reverseLevelOrder` メソッドは、レベル順の逆順に探索された木ノード値の配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.reverseLevelOrder !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(7);
|
||||
test.add(1);
|
||||
test.add(9);
|
||||
test.add(0);
|
||||
test.add(3);
|
||||
test.add(8);
|
||||
test.add(10);
|
||||
test.add(2);
|
||||
test.add(5);
|
||||
test.add(4);
|
||||
test.add(6);
|
||||
return test.reverseLevelOrder().join('') == '791108305264';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`levelOrder` メソッドは、空の木の場合に `null` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.levelOrder !== 'function') {
|
||||
return false;
|
||||
}
|
||||
return test.levelOrder() == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`reverseLevelOrder` メソッドは、空の木の場合に `null` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.reverseLevelOrder !== 'function') {
|
||||
return false;
|
||||
}
|
||||
return test.reverseLevelOrder() == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
BinarySearchTree.prototype = Object.assign(
|
||||
BinarySearchTree.prototype,
|
||||
{
|
||||
add: function(value) {
|
||||
function searchTree(node) {
|
||||
if (value < node.value) {
|
||||
if (node.left == null) {
|
||||
node.left = new Node(value);
|
||||
return;
|
||||
} else if (node.left != null) {
|
||||
return searchTree(node.left);
|
||||
}
|
||||
} else if (value > node.value) {
|
||||
if (node.right == null) {
|
||||
node.right = new Node(value);
|
||||
return;
|
||||
} else if (node.right != null) {
|
||||
return searchTree(node.right);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
var node = this.root;
|
||||
if (node == null) {
|
||||
this.root = new Node(value);
|
||||
return;
|
||||
} else {
|
||||
return searchTree(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
// Only change code below this line
|
||||
this.levelOrder = (root = this.root) => {
|
||||
if(!root) return null;
|
||||
let queue = [root];
|
||||
let results = [];
|
||||
while(queue.length > 0) {
|
||||
let node = queue.shift();
|
||||
results.push(node.value);
|
||||
if(node.left) queue.push(node.left);
|
||||
if(node.right) queue.push(node.right);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
this.reverseLevelOrder = (root = this.root) => {
|
||||
if(!root) return null;
|
||||
let queue = [root];
|
||||
let results = [] ;
|
||||
while ( queue.length > 0) {
|
||||
let node = queue.shift();
|
||||
results.push(node.value);
|
||||
if(node.right) queue.push(node.right);
|
||||
if(node.left ) queue.push(node.left);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
@ -0,0 +1,328 @@
|
||||
---
|
||||
id: 587d8257367417b2b2512c7e
|
||||
title: 二分探索木で深さ優先探索を使用する
|
||||
challengeType: 1
|
||||
forumTopicId: 301719
|
||||
dashedName: use-depth-first-search-in-a-binary-search-tree
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
二分探索木で特定の値を検索する方法は既に学びました。 しかし、木全体を探索したい場合はどうすれば良いでしょうか? あるいは、順序付きの木がないときに、単に値を検索したい場合はどうでしょうか? ここでは、ツリーデータ構造を探索するために木を走査する方法をいくつか紹介します。 1 つ目は深さ優先探索です。 深さ優先探索は、探索が別の部分木に移る前に、与えられた部分木をできるだけ深く探索します。 これを行うには次の 3 つの方法があります。通りがけ順: 左端のノードで探索を開始し、右端のノードで終了します。 行きがけ順: 葉より先にすべての根を探索します。 帰りがけ順: 根より先にすべての葉を探索します。 お察しの通り、木がどのような種類のデータを格納しているか、そして何を探したいかに応じて、異なる検索方法を選択できます。 二分探索木の場合、通りがけ順走査は、ソートされた順序でノードを返します。
|
||||
|
||||
# --instructions--
|
||||
|
||||
ここでは、二分探索木に対してこれら 3 つの探索方法を作成します。 深さ優先探索は、子ノードが存在する限りさらに部分木の探索を続けるという、本質的に再帰性を持つ操作です。 この基本概念を理解したら、ノードと部分木の探索順序を変えるだけで上述の 3 つの探索をすべて作成できます。 例えば帰りがけ順の探索では、ノード自体を返し始める前に、葉ノードまでの全体を再帰的に探索します。一方、行きがけ順の探索では、最初にノードを返してから、木の下の方へ再帰的に探索し続けます。 この木に `inorder`、`preorder`、`postorder` の各メソッドを定義してください。 これらの各メソッドは、木の走査を表す要素の配列を返す必要があります。 ノード自体ではなく、配列内の各ノードの整数値を返すようにしてください。 最後に、木が空の場合は `null` を返してください。
|
||||
|
||||
# --hints--
|
||||
|
||||
`BinarySearchTree` データ構造が存在する必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
}
|
||||
return typeof test == 'object';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `inorder` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.inorder == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `preorder` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.preorder == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
二分探索木に `postorder` というメソッドが必要です。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return typeof test.postorder == 'function';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`inorder` メソッドは、通りがけ順走査によって得たノード値の配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.inorder !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(7);
|
||||
test.add(1);
|
||||
test.add(9);
|
||||
test.add(0);
|
||||
test.add(3);
|
||||
test.add(8);
|
||||
test.add(10);
|
||||
test.add(2);
|
||||
test.add(5);
|
||||
test.add(4);
|
||||
test.add(6);
|
||||
return test.inorder().join('') == '012345678910';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`preorder` メソッドは、行きがけ順走査によって得たノード値の配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.preorder !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(7);
|
||||
test.add(1);
|
||||
test.add(9);
|
||||
test.add(0);
|
||||
test.add(3);
|
||||
test.add(8);
|
||||
test.add(10);
|
||||
test.add(2);
|
||||
test.add(5);
|
||||
test.add(4);
|
||||
test.add(6);
|
||||
return test.preorder().join('') == '710325469810';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`postorder` メソッドは、帰りがけ順走査によって得たノード値の配列を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.postorder !== 'function') {
|
||||
return false;
|
||||
}
|
||||
test.add(7);
|
||||
test.add(1);
|
||||
test.add(9);
|
||||
test.add(0);
|
||||
test.add(3);
|
||||
test.add(8);
|
||||
test.add(10);
|
||||
test.add(2);
|
||||
test.add(5);
|
||||
test.add(4);
|
||||
test.add(6);
|
||||
return test.postorder().join('') == '024653181097';
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`inorder` メソッドは、空の木の場合に `null` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.inorder !== 'function') {
|
||||
return false;
|
||||
}
|
||||
return test.inorder() == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`preorder` メソッドは、空の木の場合に `null` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.preorder !== 'function') {
|
||||
return false;
|
||||
}
|
||||
return test.preorder() == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
`postorder` メソッドは、空の木の場合に `null` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = false;
|
||||
if (typeof BinarySearchTree !== 'undefined') {
|
||||
test = new BinarySearchTree();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (typeof test.postorder !== 'function') {
|
||||
return false;
|
||||
}
|
||||
return test.postorder() == null;
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --after-user-code--
|
||||
|
||||
```js
|
||||
BinarySearchTree.prototype = Object.assign(
|
||||
BinarySearchTree.prototype,
|
||||
{
|
||||
add: function(value) {
|
||||
function searchTree(node) {
|
||||
if (value < node.value) {
|
||||
if (node.left == null) {
|
||||
node.left = new Node(value);
|
||||
return;
|
||||
} else if (node.left != null) {
|
||||
return searchTree(node.left);
|
||||
}
|
||||
} else if (value > node.value) {
|
||||
if (node.right == null) {
|
||||
node.right = new Node(value);
|
||||
return;
|
||||
} else if (node.right != null) {
|
||||
return searchTree(node.right);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var node = this.root;
|
||||
if (node == null) {
|
||||
this.root = new Node(value);
|
||||
return;
|
||||
} else {
|
||||
return searchTree(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
var displayTree = tree => console.log(JSON.stringify(tree, null, 2));
|
||||
function Node(value) {
|
||||
this.value = value;
|
||||
this.left = null;
|
||||
this.right = null;
|
||||
}
|
||||
function BinarySearchTree() {
|
||||
this.root = null;
|
||||
this.result = [];
|
||||
|
||||
this.inorder = function(node) {
|
||||
if (!node) node = this.root;
|
||||
if (!node) return null;
|
||||
|
||||
if (node.left) this.inorder(node.left);
|
||||
this.result.push(node.value);
|
||||
if (node.right) this.inorder(node.right);
|
||||
return this.result;
|
||||
};
|
||||
this.preorder = function(node) {
|
||||
if (!node) node = this.root;
|
||||
if (!node) return null;
|
||||
|
||||
this.result.push(node.value);
|
||||
if (node.left) this.preorder(node.left);
|
||||
if (node.right) this.preorder(node.right);
|
||||
return this.result;
|
||||
};
|
||||
this.postorder = function(node) {
|
||||
if (!node) node = this.root;
|
||||
if (!node) return null;
|
||||
|
||||
if (node.left) this.postorder(node.left);
|
||||
if (node.right) this.postorder(node.right);
|
||||
this.result.push(node.value);
|
||||
|
||||
return this.result;
|
||||
};
|
||||
}
|
||||
```
|
@ -0,0 +1,59 @@
|
||||
---
|
||||
id: 587d8255367417b2b2512c73
|
||||
title: ES5 Set() 統合にスプレッドとノートを使用する
|
||||
challengeType: 1
|
||||
forumTopicId: 301720
|
||||
dashedName: use-spread-and-notes-for-es5-set-integration
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
ES6 スプレッド演算子 "`...`" を覚えていますか?
|
||||
|
||||
"`...`" は、ES6 の反復可能なオブジェクトを配列に変換することができます。
|
||||
|
||||
Set を作成し、スプレッド機能を使ってみましょう。
|
||||
|
||||
```js
|
||||
var set = new Set([1,2,3]);
|
||||
var setToArr = [...set]
|
||||
console.log(setToArr) // returns [ 1, 2, 3 ]
|
||||
```
|
||||
|
||||
# --instructions--
|
||||
|
||||
この課題では、Set オブジェクトを `checkSet` 関数に渡します。 この関数は、Set の値が含まれている配列を返す必要があります。
|
||||
|
||||
これで、ES6 `Set()` オブジェクトの使い方を正しく学びました。よくできました!
|
||||
|
||||
# --hints--
|
||||
|
||||
`checkSet(new Set([1,2,3,4,5,6,7])` は `[1, 2, 3, 4, 5, 6, 7]` を返す必要があります。
|
||||
|
||||
```js
|
||||
assert(
|
||||
(function () {
|
||||
var test = checkSet(new Set([1, 2, 3, 4, 5, 6, 7]));
|
||||
return DeepEqual(test, [1, 2, 3, 4, 5, 6, 7]);
|
||||
})()
|
||||
);
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
function checkSet(set){
|
||||
// Only change code below this line
|
||||
|
||||
// Only change code above this line
|
||||
}
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
function checkSet(set){
|
||||
return [...set];}
|
||||
```
|
@ -0,0 +1,55 @@
|
||||
---
|
||||
id: 587d8251367417b2b2512c61
|
||||
title: リンクリスト内のノードを操作する
|
||||
challengeType: 1
|
||||
forumTopicId: 301721
|
||||
dashedName: work-with-nodes-in-a-linked-list
|
||||
---
|
||||
|
||||
# --description--
|
||||
|
||||
コンピュータサイエンスの世界でよく目にするもう一つのデータ構造は、<dfn>リンクリスト</dfn>です。 リンクリストは「ノード」と呼ばれるデータ要素の線形コレクションであり、それぞれが次の要素を指しています。 Each <dfn>node</dfn> in a linked list contains two key pieces of information: the `element` itself, and a reference to the next `node`.
|
||||
|
||||
あなたがコンガラインの中にいるのを想像してみてください。 あなたはラインの中で自分のすぐ前の人に手を置き、後ろの人はあなたに手を置いています。 前の人はあなたの正面にいますが、その人が視界を遮るため、もっと前にいる人たちがあなたからは見えません。 ノードはコンガラインの人と同じようなものです。自分のことを知っていて、目の前にいる人だけを見ています。その人の前や自分の後ろにいる、他の人たちの存在には気付きません。
|
||||
|
||||
# --instructions--
|
||||
|
||||
コードエディターに、`Kitten` と `Puppy` という 2 つのノードが既に作成され、`Kitten` ノードが `Puppy` ノードに手動で接続されています。
|
||||
|
||||
`Cat` と `Dog` ノードを作成し、それらを手動でラインに追加してください。
|
||||
|
||||
# --hints--
|
||||
|
||||
`Puppy` ノードは `Cat` ノードへの参照を持つ必要があります。
|
||||
|
||||
```js
|
||||
assert(Puppy.next.element === 'Cat');
|
||||
```
|
||||
|
||||
`Cat` ノードは `Dog` ノードへの参照を持つ必要があります。
|
||||
|
||||
```js
|
||||
assert(Cat.next.element === 'Dog');
|
||||
```
|
||||
|
||||
# --seed--
|
||||
|
||||
## --seed-contents--
|
||||
|
||||
```js
|
||||
var Node = function(element) {
|
||||
this.element = element;
|
||||
this.next = null;
|
||||
};
|
||||
var Kitten = new Node('Kitten');
|
||||
var Puppy = new Node('Puppy');
|
||||
|
||||
Kitten.next = Puppy;
|
||||
// Only change code below this line
|
||||
```
|
||||
|
||||
# --solutions--
|
||||
|
||||
```js
|
||||
// solution required
|
||||
```
|
Reference in New Issue
Block a user