web-dev-qa-db-ja.com

JavaScriptでリンクリストを逆にする戦略

私は簡単な面接の質問に苦労しました:単一にリンクされたリストを逆にしてください。

面接を保存するのに間に合うように実用的な答えを提供することができませんでしたが、後で解決策を思いつくことができました。

私の解決策は正しいですか? Big-Ohでこれをどのように分析しますか?単一リンクリストを逆にするより効率的な方法はありますか?

// reverse a linked list

var reverseLinkedList = function(linkedlist) {
  var node = linkedlist;
  var previous = null;

  while(node) {
    // reverse pointer
    node.next = previous;
    // increment previous to current node
    previous = node;
    // increment node to next node
    if (node.next){
      node = node.next
    } else {
      node = null;
    }
  }
}

注:同様の投稿を検索したところ、JavaScriptで 1つの例 が見つかりました。私のコードが(temp変数なしで)可能かどうか疑問に思いました。ありがとうございました。

17
user2954463

コードにはいくつか問題があります。これはそれを明らかにするはずです。

// reverse a linked list  
var reverseLinkedList = function(linkedlist) {
  var node = linkedlist;
  var previous = null;

  while(node) {
    // save next or you lose it!!!
    var save = node.next;
    // reverse pointer
    node.next = previous;
    // increment previous to current node
    previous = node;
    // increment node to next node or null at end of list
    node = save;
  }
  return previous;   // Change the list head !!!
}
linkedlist = reverseLinkedList(linkedlist);
30
stark

この問題は、O(n)時間 ckersch が言及しているように)で再帰的に解決できます。重要なのは、関数が蓄積されるため、再帰はメモリを大量に消費することを知っておく必要があるということです。呼び出しは、停止条件に到達して実際のものを返し始めるまでスタックします。

この問題を解決する方法は次のとおりです。

 const reverse = (head) => {
   if (!head || !head.next) {
     return head;
   }
   let temp = reverse(head.next);
   head.next.next = head;
   head.next = undefined;
   return temp;
 }    

Reverse()がリストの最後に到達すると、最後のノードを新しいヘッドとして取得し、各ノードを逆方向に参照します。

8
Rantelo

これは、各ノードで一定数の操作を実行するため、時間的にO(n)になります。概念的には、より効率的な方法はありません。表記法として、実行できるコードの最適化がいくつかあります。)

O(n)を超えることができない理由は、それを行うには、いくつかのノードをスキップする必要があるためです。各ノードを変更する必要があるため、これは超えません。可能である。

その後、効率は一定の要因になります。リスト内の項目ごとに実行できる操作が少ないほど、コードの実行速度は速くなります。

私はこのように実装します:

function reverseLinkedList(list, previous){

  //We need to use the the current setting of
  //list.next before we change it. We could save it in a temp variable,
  //or, we could call reverseLinkedList recursively
  if(list.next !== null){
    reverseLinkedList(list.next, list);
  }

  //Everything after 'list' is now reversed, so we don't need list.next anymore.
  //We passed previous in as an argument, so we can go ahead and set next to that.
  list.next = previous;
}

reverseLinkedList(list, null);

もちろん、これは再帰的であるため、スペースの点では非効率的ですが、再帰的なコードが好きです:)

これも逆リンクリストを返しませんが、それが重要な場合は、そうするようにかなり簡単に変更できます。

4
ckersch
//O(n) | O(1) wherre n is the number of nodes in the linked list

class Node{
  constructor(val){
    this.val = val;
    this.next = null;
  }
}


function reverseLinkedList(head) {

 if(!head) return null;
 
 let p1 = head;
 let p2 = null;
        
        while(p1){
                let temp = p1.next;
                p1.next = p2;
                p2 = p1;
                p1 = temp;
        }
        
        return p2;
}


const a = new Node(1);
a.next = new Node(2);
a.next.next = new Node(3)

console.log("Current Node",a);
console.log("Reversed List",reverseLinkedList(a))
0
ASHISH RANJAN