反转链表
一种解决方案是按原始顺序迭代结点
,并将它们逐个移动到列表的头部
。似乎很难理解。我们先用一个例子来说明我们的算法。
- 算法概述
让我们看一个例子:
请记住,黑色结点 23 是原始的头结点。
1. 首先,我们将黑色结点的下一个结点(即结点 6)移动到列表的头部:
2. 然后,我们将黑色结点的下一个结点(即结点 15)移动到列表的头部:
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. 在许多情况下,你需要跟踪当前结点的前一个结点。
你无法追溯单链表中的前一个结点。因此,您不仅要存储当前结点,还要存储前一个结点。这在双链表中是不同的。