JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

算法:反转链表(Java版) 反转链表递归怎么理解

wys521 2024-11-02 14:57:25 精选教程 22 ℃ 0 评论

反转链表是算法中的一个经典问题,它要求我们改变链表中节点的指向,使得原本指向后一个节点的指针现在指向前一个节点。下面,我会详细解释如何使用双指针和递归的方法来解决这个问题,并提供相应的Java代码。

双指针解法

思路

  1. 使用两个指针,一个prev指向前一个节点,初始为null;一个curr指向当前节点,初始为头节点。
  2. 遍历链表,每次迭代做如下操作:
  3. currnext指向prev
  4. prevcurr都向前移动一步。
  5. currnull时,遍历结束,此时prev就是新的头节点。

Java代码

public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public ListNode reverseList(ListNode head) {
    ListNode prev = null;
    ListNode curr = head;
    while (curr != null) {
        ListNode nextTemp = curr.next; // 保存下一个节点
        curr.next = prev; // 反转当前节点的指向
        prev = curr; // prev前进一步
        curr = nextTemp; // curr前进一步
    }
    return prev; // prev现在是新的头节点
}

时间复杂度:O(n),其中n是链表的长度,需要遍历整个链表一次。

空间复杂度:O(1),只使用了常数级别的额外空间。

递归解法

思路

  1. 使用两个参数——currnewHead——允许我们在递归过程中同时处理这两个方面。curr 表示当前处理的节点,而 newHead 表示反转后的新头节点。
  2. 递归的起始点是链表的头节点,此时新头节点是 null,因为反转前没有头节点。在递归的每一步中,我们执行以下操作:
  • 保存下一个节点:在改变当前节点 curr 的指向之前,我们先保存它的下一个节点 nextNode。这是因为一旦我们改变了 curr 的指向,我们就失去了对原始链表中下一个节点的引用。
  • 反转当前节点的指向:我们将 currnext 指针指向 newHead。这样,我们就实现了当前节点的反转。
  • 递归调用:然后,我们递归调用 reverseListRecursive 方法,传入 nextNode 作为新的当前节点,并将 curr 作为新的头节点传入。这是因为,在递归的下一步中,curr 将成为新链表中的前一个节点。
  • 返回新头节点:递归调用的结果(即新的头节点)会被返回,并继续向上传递到上一层递归调用中。这样,每一层递归都能知道反转后的新头节点是什么,并在适当的时候更新它。

Java代码

public class ListNode {  
    int val;  
    ListNode next;  
    ListNode(int x) { val = x; }  
}  
  
public ListNode reverseList(ListNode head) {  
    return reverseListRecursive(head, null);  
}  
  
private ListNode reverseListRecursive(ListNode curr, ListNode newHead) {  
    if (curr == null) {  
        return newHead; // 递归终止条件:当前节点为空,返回新头节点  
    }  
      
    ListNode nextNode = curr.next; // 保存下一个节点  
    curr.next = newHead; // 反转当前节点的指向  
      
    // 递归调用,处理下一个节点,并更新新头节点  
    return reverseListRecursive(nextNode, curr);  
}

时间复杂度:O(n),其中n是链表的长度,递归需要遍历整个链表一次。

空间复杂度:O(n),递归调用栈的深度取决于链表的长度,最坏情况下需要n层递归调用栈。

总结

反转链表是一个基础的链表操作,可以使用双指针和递归两种方法实现。双指针方法空间复杂度低,但需要手动维护两个指针;递归方法代码简洁,但空间复杂度较高。在实际应用中,可以根据具体需求和场景选择合适的方法。

注:个人觉得解决链表问题的时候,画图可以清晰展示每个节点的指向,帮助解决问题。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表