反转链表

一种解决方案是按原始顺序迭代结点,并将它们逐个移动到列表的头部。似乎很难理解。我们先用一个例子来说明我们的算法。

  • 算法概述

让我们看一个例子:




java反转一个单链表 java 反转链表_结点


请记住,黑色结点 23 是原始的头结点。

1. 首先,我们将黑色结点的下一个结点(即结点 6)移动到列表的头部:


java反转一个单链表 java 反转链表_java 链表反转_02


2. 然后,我们将黑色结点的下一个结点(即结点 15)移动到列表的头部:


java反转一个单链表 java 反转链表_Java_03


3. 黑色结点的下一个结点现在是空。因此,我们停止这一过程并返回新的头结点 15。

在该算法中,每个结点只移动一次。因此,时间复杂度为 O(N),其中 N 是链表的长度。我们只使用常量级的额外空间,所以空间复杂度为 O(1)。

leetCode 206. 反转链表

反转一个单链表。

示例:


输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL


进阶:

你可以迭代或递归地反转链表。你能否用两种方法解决这道题?

Solution1. C:


/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList(struct ListNode* head) {
    if((head==NULL) || (head->next==NULL))
        return head;
    struct ListNode* pOrigHead = head;
    struct ListNode* pNode = head->next;
    struct ListNode* pNext;
    while(pNode)
    {
        pNext = pNode->next;
        pNode->next = head;
        head = pNode;
        pNode = pNext;
    }
    pOrigHead->next = NULL;
    return head;
}


Solution2. C++:


/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    /*method1*/
    /*ListNode* reverseList(ListNode* head) {
        if((head == NULL) || (head->next == NULL))
            return head;
        ListNode* pReverseHead = reverseList(head->next);
        ListNode* pNode = pReverseHead;
        while(pNode->next != NULL)
            pNode = pNode->next;
        pNode->next = head;
        head->next = NULL;
        return pReverseHead;
    }*/
    /*method2*/
    ListNode* reverseList(ListNode* head) {
        if((head == NULL) || (head->next == NULL))
            return head;
        ListNode* pHead = head;
        ListNode* pNode = pHead->next;
        while(pNode != NULL)
        {
            ListNode* pNext = pNode->next;
            pNode->next = pHead;
            pHead = pNode;
            pNode = pNext;
        }
        head->next = NULL;
        return pHead;
    }
};


Solution3. Java:


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null)
            return null;
        ListNode pHead = head;
        ListNode pNode = head.next;
        while(pNode != null)
        {
            ListNode pNext = pNode.next;
            pNode.next = pHead;
            pHead = pNode;
            pNode = pNext;
        }
        head.next = null;
        return pHead;
    }
}


Solution4. Python3:


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if not head:
            return None
        pHead, pNode = head, head.next
        while pNode:
            pNext = pNode.next
            pNode.next = pHead
            pHead = pNode
            pNode = pNext
        head.next = None
        return pHead


leetCode 203. 移除链表元素

删除链表中等于给定值 val 的所有节点。

示例:


输入: 1->2->6->3->4->5->6, val = 6
输出: 1->2->3->4->5


Solution1. C++


/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeElements(struct ListNode* head, int val) {
    struct ListNode* pNode = head;
    if(head == NULL)
        return head;
    while(head != NULL && head->val == val)
        head = head->next;
    while(pNode != NULL && pNode->next != NULL)
    {
        if(pNode->next->val == val)
            pNode->next = pNode->next->next;
        else
            pNode = pNode->next;
    }
    return head;
}


Solution2. Java递归方法


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        if(head == null)
            return head;
        head.next = removeElements(head.next, val);
        head = head.val==val ? head.next : head;
        return head;
    }
}


Solution3. Java


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        while(head != null && head.val == val)
            head = head.next;
        ListNode pNode = head;
        while(pNode!=null && pNode.next!=null)
        {
            if(pNode.next.val == val)
                pNode.next = pNode.next.next;
            else
                pNode = pNode.next;
        }
        return head;
    }
}


Solution4. Python3


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeElements(self, head: ListNode, val: int) -> ListNode:
        while head and head.val==val:
            head = head.next
        pNode = head
        while pNode and pNode.next:
            if pNode.next.val == val:
                pNode.next = pNode.next.next
            else:
                pNode = pNode.next
        return head


leetCode 328. 奇偶链表

给定一个单链表,把所有的奇数节点和偶数节点分别排在一起。请注意,这里的奇数节点和偶数节点指的是节点编号的奇偶性,而不是节点的值的奇偶性。

请尝试使用原地算法完成。你的算法的空间复杂度应为 O(1),时间复杂度应为 O(nodes),nodes 为节点总数。

示例 1:


输入: 1->2->3->4->5->NULL
输出: 1->3->5->2->4->NULL


示例 2:


输入: 2->1->3->5->6->4->7->NULL 
输出: 2->3->6->7->1->5->4->NULL


说明:

  • 应当保持奇数节点和偶数节点的相对顺序。
  • 链表的第一个节点视为奇数节点,第二个节点视为偶数节点,以此类推。

Solution1. C


/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* oddEvenList(struct ListNode* head) {
    if(head==NULL || head->next==NULL || head->next->next==NULL)
        return head;
    struct ListNode *odd = head, *even = head->next;
    struct ListNode *evenHead = even;
    while(even != NULL && even->next != NULL)
    {
        odd->next = odd->next->next;
        even->next = even->next->next;
        odd = odd->next;
        even = even->next;
    }
    odd->next = evenHead;
    return head;
}


Solution2. Java


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode oddEvenList(ListNode head) {
        if(head==null || head.next==null || head.next.next==null)
            return head;
        ListNode odd = head, even = head.next;
        ListNode evenHead = even;
        while(even!=null && even.next!=null)
        {
            odd.next = odd.next.next;
            even.next = even.next.next;
            odd = odd.next;
            even = even.next;
        }
        odd.next = evenHead;
        return head;
    }
}


Solution3. Python3


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def oddEvenList(self, head: ListNode) -> ListNode:
        if head and head.next and head.next.next:
            odd, even, evenHead = head, head.next, head.next
            while even and even.next:
                odd.next = odd.next.next
                even.next = even.next.next
                odd = odd.next
                even = even.next
            odd.next = evenHead
        return head


leetCode 234. 回文链表

请判断一个链表是否为回文链表。

示例 1:


输入: 1->2
输出: false


示例 2:


输入: 1->2->2->1
输出: true


进阶:

你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

Solution1. C++


/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverse(struct ListNode* head)
{
    struct ListNode *prev = NULL;
    while(head)
    {
        struct ListNode* pNext = head->next;
        head->next = prev;
        prev = head;
        head = pNext;
    }
    return prev;
}

bool isPalindrome(struct ListNode* head) {
    if(head==NULL || head->next==NULL)
        return true;
    struct ListNode *fast = head;
    struct ListNode *slow = head;
    while(fast->next!=NULL && fast->next->next!=NULL)
    {
        fast = fast->next->next;
        slow = slow->next;
    }
    slow->next = reverse(slow->next);
    slow = slow->next;
    while(slow != NULL)
    {
        if(head->val != slow->val)
            return false;
        head = head->next;
        slow = slow->next;
    }
    return true;
}


Solution2. Java


/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
        if(head == null || head.next == null)
            return true;
        ListNode fast = head, slow = head;
        while(fast.next!=null && fast.next.next!=null)
        {
            fast = fast.next.next;
            slow = slow.next;
        }
        slow.next = reverse(slow.next);
        slow = slow.next;
        while(slow != null)
        {
            if(head.val != slow.val)
                return false;
            head = head.next;
            slow = slow.next;
        }
        return true;
    }
    
    public ListNode reverse(ListNode head)
    {
        ListNode prev = null;
        while(head != null)
        {
            ListNode next = head.next;
            head.next = prev;
            prev = head;
            head = next;
        }
        return prev;
    }
}


Solution3. Python3


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        if head==None or head.next==None:
            return True
        fast = slow = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
        prev = None
        while slow:
            next = slow.next
            slow.next = prev
            prev = slow
            slow = next
        while prev:
            if prev.val != head.val:
                return False
            prev = prev.next
            head = head.next
        return True


Solution4. Python3


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def isPalindrome(self, head: ListNode) -> bool:
        testList = []
        while head:
            testList.append(head.val)
            head = head.next
        return testList == testList[::-1]


小结 - 链表经典问题

1. 通过一些测试用例可以节省您的时间。
使用链表时不易调试。因此,在编写代码之前,自己尝试几个不同的示例来验证您的算法总是很有用的。2. 你可以同时使用多个指针。
有时,当你为链表问题设计算法时,可能需要同时跟踪多个结点。您应该记住需要跟踪哪些结点,并且可以自由地使用几个不同的结点指针来同时跟踪这些结点。
如果你使用多个指针,最好为它们指定适当的名称,以防将来必须调试或检查代码。3. 在许多情况下,你需要跟踪当前结点的前一个结点。
你无法追溯单链表中的前一个结点。因此,您不仅要存储当前结点,还要存储前一个结点。这在双链表中是不同的。