データ構造とアルゴリズムから最も人気のある質問の1つで、主に電話インタビューで質問されました。
データ構造とアルゴリズムから最も人気のある質問の1つで、主に電話インタビューで質問されました。
回答:
不正行為と並行して2つのパスを同時に行うことによって。しかし、採用担当者がこれを好むかどうかはわかりません。
素敵なトリックを使用して、単一のリンクリストで実行できます。2つのポインターがリスト上を移動し、1つは倍速になります。速い方が終わりに達すると、もう片方は途中です。
二重にリンクされたリストではない場合は、リストをカウントして使用するだけでかまいませんが、最悪の場合はメモリを2倍にする必要があり、リストが大きすぎてメモリに保存できない場合は機能しません。
単純な、ほとんどばかげた解決策は、2つのノードごとに中間ノードを増やすだけです。
function middle(start) {
var middle = start
var nextnode = start
var do_increment = false;
while (nextnode.next != null) {
if (do_increment) {
middle = middle.next;
}
do_increment = !do_increment;
nextnode = nextnode.next;
}
return middle;
}
ヘンドリックの答えを詳しく述べる
二重リンクリストの場合は、両端から繰り返します
function middle(start, end) {
do_advance_start = false;
while(start !== end && start && end) {
if (do_advance_start) {
start = start.next
}
else {
end = end.prev
}
do_advance_start = !do_advance_start
}
return (start === end) ? start : null;
}
与えられた [1, 2, 3] => 2
1, 3
1, 2
2, 2
与えられた [1, 2] => 1
1, 2
1, 1
与えられた [1] => 1
与えられた [] => null
動的配列を作成します。配列の各要素は、リスト内の各ノードへのポインターであり、最初から順に走査されます。1に初期化された整数を作成し、訪問したノードの数を追跡します(新しいノードに行くたびに増加します)。最後に到達すると、リストの大きさがわかり、各ノードへのポインターの配列が整います。最後に、リストのサイズを2で割り(0ベースのインデックス付けの場合は1を減算)、配列のそのインデックスに保持されているポインターをフェッチします。リストのサイズが奇数の場合、返す要素を選択できます(最初の要素を返します)。
ここに、いくつかのJavaコードがあります(動的配列の概念は少し不安定ですが)。C / C ++を提供しますが、その分野では非常に錆びています。
public Node getMiddleNode(List<Node> nodes){
int size = 1;
//add code to dynamically increase size if at capacity after adding
Node[] pointers = new Node[10];
for (int i = 0; i < nodes.size(); i++){
//remember to dynamically allocate more space if needed
pointers[i] = nodes.get(i);
size++;
}
return pointers[(size - 1)/2];
}
再帰は複数のパスと見なされますか?
リストを最後まで走査し、参照により整数カウントを渡します。後で参照できるように、各レベルでその値のローカルコピーを作成し、次の呼び出しで参照カウントを増やします。
最後のノードで、カウントを2で除算し、結果を切り捨てます(2つの要素しかないときに最初のノードを「中間」にしたい場合)または切り上げます(2番目のノードにしたい場合)真ん中")。0または1ベースのインデックスを適切に使用します。
巻き戻し、参照カウントをローカルコピー(ノードの番号)に一致させます。等しい場合、そのノードを返します。それ以外の場合は、再帰呼び出しから返されたノードを返します。
。
これを行う方法は他にもあります。それらのいくつかはそれほど面倒ではないかもしれません(誰かがそれを配列に読み込み、配列の長さを使用して中間の賞賛を決定すると言う人を見たと思った)。しかし、率直に言って、それは愚かなインタビューの質問なので、良い答えはありません。ナンバーワン、まだリンクリストを使用している(支持意見)。2つ目は、真ん中のノードを見つけることは、現実のシナリオでは価値のないacademic意的な学術的課題です。3番目に、真ん中のノードを本当に知る必要がある場合、リンクリストはノードカウントを公開します。中間ノードが必要になるたびにリスト全体を走査する時間を無駄にするよりも、そのプロパティを維持する方が簡単です。そして最後に、4つ、すべてのインタビュアーが異なる答えを好むか拒否します-あるインタビュアーが滑らかだと思うもの、別のインタビュアーはばかげていると呼びます。
私はほとんどの場合、インタビューの質問にさらに質問をします。このような質問を受け取った場合(私は持っていない)、私は尋ねます; (2)私の制約は何ですか?メモリが問題にならない場合(配列の答えなど)は高速化できますが、インタビュアーがメモリの増加が無駄であると思う場合は、うんざりします。(3)どの言語で開発しますか?私が知っているほぼすべての現代言語には、リストの走査を不要にするリンクリストを処理する組み込みクラスがあります。言語の開発者によって効率が向上するように調整されたものを再発明するのはなぜですか。
2つのポインターを使用する。反復ごとに1つずつ増加し、2番目の反復ごとに1ずつ増加します。1番目のポインターがリンクリストの終わりを指している場合、2番目のポインターはリンクリストの中央モードを指します。