链表反转
这是一个简单的链表操作问题,在leetcode上面有52.7%的通过率,难度是简单。但是还是想在这里基于python做一下总结,顺便总结一下链表的各种操作。
首先先看一下leetcode上面的题目:
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
进阶:
你可以迭代或递归地反转链表。你能否用两种方法解决这道题?
看完了题目,很直白,就是转过来。我们尝试对这道题进行解决。这道题用python至少会有三种解决方案。
首先是链表的数据结构定义:
# Definition for singly-linked list.
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
- 将链表遍历进list中,然后利用切片反转list,再将list填充到链表中即可。这是最简单的一种思考逻辑,但是也比较消耗性能。时间和空间复杂度都为O(n)。
def loop(head):
temp = []
while head is not None:
temp.append(head)
head = head.next
temp = temp[::-1]
for i, n in enumerate(temp):
if i + 1 < len(temp):
n.next = temp[i + 1]
else:
n.next = None
return temp[0] if temp else None
- 另一种迭代算法,是一种纯粹交换的迭代,笔者这里截取了leetcode速度最快的一种。
def reverseList(head):
"""
:type head: ListNode
:rtype: ListNode
"""
if not head:
return None
it = head; jt = head.next
it.next = None
while jt:
tmp = it
it = jt
jt = jt.next
it.next = tmp
return it
这一波交换操作,我们可以画个示意图就知道他的交换是一种怎么样的交换。
从图中可以看出,循环的作用就是将反向指针进行保存。同时令将指针转向的功能。
- 最后一种方案是采用递归的方式进行链表反转。这种方式也需要一定的理解。我们先展示一下代码。
def reverseList(head):
"""
:type head: ListNode
:rtype: ListNode
"""
if head is None or head.next is None:
return head
end = reverseList(head.next)
head.next.next = head
head.next = None
return end
这种解法其实理解起来只有两部分内容,传递反向指针和进行指针反向拼接。我们先来理解一下指针反向拼接这个操作。
1 -> 2 -> 3 -> 4 -> None
依次:
3(head) -> 4(head.next) -> 3(head.next.next)
3 -> None
如此循环即可将链表反转过来。但是还有个关键就是将最后一个指针传递出来。我们可以看到之前的代码中,end传出来后是一直没有做任何操作的。不停的return出最后一个指针。所以就将最后一个指针传递了出来。
以上就是链表反转的3中方法。除此之外还想写一些链表的简单操作。
快慢指针
何为快慢指针,即对链表进行两个不同步频的指针标记遍历。最经典的是慢指针走一步,快指针走两步。
快慢指针有很多的应用,比如说:
def hasCycle(head):
"""
:type head: ListNode
:rtype: bool
"""
if head is None or head.next is None:
return False
fast, slow = head.next.next, head.next
while fast is not slow:
if fast is None or fast.next is None:
return False
fast = fast.next.next
slow = slow.next
return True
两个指针并排走,如果有环的话快指针最终会指向慢指针的位置。没有环的话,快指针会指向None后退出。
当然这道题的解法不止这一样,还可以利用set进行判断。
- 输出链表中的倒数第K个节点
这道题利用快慢指针的思路是这样的。定义两个指针,第一个指针向前走k-1步;第2个指针保持不动;到第k步时第2个指针也开始移动。由于两个指针始终保持着k-1的距离,所以当快指针到达末尾时,慢指针刚好指向倒数第k个。
def count_back(head, k):
if head is None:
return head
fast, slow = head, head
for i in range(k - 1):
fast = fast.next
if fast is None:
return None
while fast is not None:
fast = fast.next
slow = slow.next
return slow
这是关于链表的两种比较简单的操作,反转和快慢指针。挺常见的面试题,在这里做一些记录分享。