【问题标题】:strategies to reverse a linked list in JavaScript在 JavaScript 中反转链表的策略
【发布时间】:2014-06-10 06:38:15
【问题描述】:

我刚刚通过一个简单的面试问题:请反转一个单链表。

虽然我未能及时提供有效的答案来挽救面试,但后来我能够想出一个解决方案。

我的解决方案正确吗?你会如何用 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 中找到了one example。我想知道我的代码是否可行(没有temp 变量)。谢谢。

【问题讨论】:

    标签: javascript linked-list singly-linked-list


    【解决方案1】:

    您的代码存在一些问题。这应该说清楚。

    // 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);
    

    【讨论】:

      【解决方案2】:

      正如ckersch 所提到的,您可以在 O(n) 时间内递归地解决这个问题。问题是,你需要知道递归是内存密集型的,因为函数在调用堆栈中累积,直到它们达到停止条件并开始返回实际的东西。

      我解决这个问题的方法是:

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

      当 reverse() 到达链表的末尾时,它会抓取最后一个节点作为新的头,并向后引用每个节点。

      【讨论】:

        【解决方案3】:

        这将是 O(n) 时间,因为您在每个节点上执行恒定数量的操作。从概念上讲,没有更有效的做事方式(就大 O 表示法而言,可以进行一些代码优化。)

        你不能超过 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);
        

        当然,这是递归的,所以在空间方面效率低下,但我喜欢递归代码:)

        这也不会返回反向链接列表,但如果这很重要,我们可以相当容易地修改它。

        【讨论】:

        • 感谢您的回答和对 Big-O 的分析,非常感谢。
        【解决方案4】:

        反转单链表: 输入:1->2->3->4->5->NULL 输出:5->4->3->2->1->NULL

        要了解解决方案,我们必须跟踪前一个头和下一个变量 例如在上面的输入 Head = 1 ; next = 2 我们没有 previous 所以假设 previous = null 循环列表直到 head 不为空。反转头部的连接(上一个和下一个)。 下面是代码

        var reverseList = function(head) {
            let previous = null;
            while(head !== null){
                let next = head.next;
                head.next = previous;
                previous= head
                head = next;
            }
            return previous;
            
        };

        【讨论】:

          【解决方案5】:

          ES6 解决方案: 只需跟踪反向列表并继续将其添加到 tmp。

          const reverseLinkedList = (head) => {
            let reversed = null;
            while(head) {
              const tmp = head;
              head = head.next;
              tmp.next = reversed;
              reversed = tmp;
            }
          
            return reversed;
          };
          
          console.log(JSON.stringify(reverseLinkedList({
            data: 1,
            next: {
              data: 2,
              next: {
                data: 3,
                next: {
                  data: 4,
                  next: {
                    data: 5,
                    next: {
                      data: 5,
                      next: {
                        data: 6
                      }
                    }
                  }
                }
              }
            }
          })));
          

          【讨论】:

            【解决方案6】:

            //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))

            【讨论】:

              【解决方案7】:
              class LinkedList {
                  constructor () {
                      this.head = this.tail = null
                  }
              
                  // add to the end of the list
                  append (value) {
                      if (!this.tail) {
                          this.head = this.tail = new Node(value)
                      } else {
                          let oldTail = this.head
                          this.head = new Node(value)
                          this.head.next = oldhead
                      }
                  }
              
                  reverseList() {
                      //your code here
                      let currentNode = this.head
                      this.head = null
                      while(currentNode) {
                          if (!this.head) {
                              this.head = new Node(currenthead.data)
                          } else {
                              let oldhead = this.head
                              this.head = new Node(currentNode.data)
                              this.head.next = oldhead
                          }
                          currentNode = currentNode.next
                      }
                  }
              }
              
              class Node {
                  constructor (value, next) {
                      this.data = value
                      this.next = next || null
                  }
              }
              
              const list = new LinkedList()
              list.append(1)
              list.append(2)
              list.reverseList()
              

              【讨论】:

              • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
              【解决方案8】:

              由于在链表的开头插入数据会将其他第一个节点推到最后,并且因为它是O(1) 过程。 然后我创建了以下函数reverse() 它基本上在开头插入节点元素,基本上会在最后得到一个反向列表。

              下面是一个演示:

              class Node {
                  constructor(data, next = null) {
                      this.data = data;
                      this.next = next;
                  }
              }
              
              class LinkedList {
                  constructor() {
                      this.head = null;
                      this.size = 0;
                  }
                  
                  insertFirst(data = null) {
                      // make new head point to the previous head
                      this.head = new Node(data, this.head);
                      this.size ++;
                  }
                  
                  insertLast(data = null) { // insert last in the beginning will be the first in the linked list
                      const node = new Node(data);
                      // If empty, insert first
                      if (!this.head) this.insertFirst(data);
                      else {
                          let current = this.head;
                          // while next is not null, continue
                          while (current.next) 
                              current = current.next;
                          // eventually next is null, we want to set next here to the node we want to add
                          current.next = node;
                      }
                      this.size ++;
                  }
                  
                  // print linked list
                  print() {
                      let current = this.head;
                      let output = "";
                      while (current) { // while current is not null, eventually it will be null
                          output += current.data + " => ";
                          current = current.next; // current jumping to the next node
                      }
                      output += "| NULL"; // ending
                      console.log(output);
                      return output;
                  }
                  
                  reverse() {
                      if (!this.head) return; // if no head, do nothing
                      let current = this.head;
                      const linkedList = new LinkedList(); // create a new linked list
                      // don't worry, it will be garbage collected once this function ends since it's not a global variable
                      while (current) { 
                          linkedList.insertFirst(current.data); // insert first at the beginning will be the end of the linked list at the end
                          current = current.next;
                      }
                      // assign current head to the reversed linked list head
                      this.head = linkedList.head;
                  }
              }
              
              const linkedList = new LinkedList();
              // fill data as 100 -> 200 -> 300 -> 400
              linkedList.insertLast(100);
              linkedList.insertLast(200);
              linkedList.insertLast(300);
              linkedList.insertLast(400);
              
              // To view results
              const bodyElement = document.getElementsByTagName("body")[0];
              bodyElement.innerHTML = `<p>Original Linked List: <b>${linkedList.print()}</b></p>`; // 100 200 300 400
              linkedList.reverse();
              bodyElement.innerHTML += `<p>Reversed Linked List: <b>${linkedList.print()}</b></p>`; // 400 300 200 100
              b {
                color: green;
              }
              &lt;body&gt;&lt;/body&gt;

              总的来说,这个reverse()函数的整个过程就是O(n)

              希望这对你来说听起来很清楚,如果我错了,请纠正我。

              【讨论】:

                猜你喜欢
                • 2020-08-31
                • 2019-07-27
                • 1970-01-01
                • 2014-02-27
                • 1970-01-01
                • 2012-06-05
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多