算法面试(一) 链表

1,114 阅读5分钟

系列文章导图:

查看所有系列文章: xiaozhuanlan.com/leetcode_tc

算法面试(三) 优先队列

Linked List

1. 知识点

1.1 概念

链表想必大家都不陌生,链表是一种递归的数据结构,它或者为空(null),或者是指向一个结点(node)的引用,该节点还有一个元素和一个指向另一条链表的引用。

链表有单向链表(Single Linked List)和双向链表(Doubly Linked List)

1.2 链表常见操作

1.2.1 插入

有个New Node节点需要插入到链表中的时候,找到插入的位置,将新节点的Next指针指向要插入位置元素的前面,然后把前面一个节点的Next指针指向新节点。

1.2.2 删除

删除操作,把要删除节点的前一个节点的Next指针指向删除节点的后一个节点,即跨过需要删除的节点,然后再将删除节点从内存中释放。

1.3 双向链表

简单介绍一个双向链表,与上面单链表不同的是,双向链表既有前置节点,也有后置节点。

1.4 时间复杂度

操作 时间复杂度 说明
prepend O(1) 头部增加元素
append O(1) 尾部增加元素
lookup O(N) 查找
insert O(1) 插入
delete O(1) 删除

上表中总结,只有查找的时间复杂度是O(N),因为查找需要从头节点依次往下找。其余操作都是O(1),上面也简单介绍插入和删除,只需要动2次Next指针,即O(1)的时间复杂度。

2. 面试题

算法代码实现使用python实现,如果不了解python,则使用自己喜欢的语言实现即可, 完整代码地址github.com/CrystalSkyZ…,完整代码里可以自己进行用例调试。

2.1 206. Reverse Linked List

leetcode link 206 leetcode第206题,反转一个单链表。 题目要求: Reverse a singly linked list.

Example: Input: 1->2->3->4->5->NULL Output: 5->4->3->2->1->NULL

题目要求是反转一个单链表,思路的相对简单,即将每一个指针的Next指向它的前驱节点即可。这类链表题目在面试过程之中主要考察的是代码实现能力,思维相对简单,所以在面试之前一定要有所准备,这样才能紧张的面试过程中快速精炼的写出代码。

python实现:

class Solution:
    def reverseList(self, head)
    """
    :type head: ListNode
    :rtype: ListNode
    """
    cur, prev = head, None
    while cur:
         cur.next, prev, cur = prev, cur, cur.next
    return prev      

要实现每一个指针指向前置节点,则需要2个节点,一个是当前节点(cur),一个是前置节点(prev),然后一直循环cur节点,再就是对前置节点和当前节点进行赋值操作。

2.2 24. Swap Nodes in Pairs

leetcode link 24 leetcode第24题,反转相邻节点。 题目要求: Given a linked list, swap every two adjacent nodes and return its head.

Example: Given 1->2->3->4, you should return the list as 2->1->4->3.

题目是要求反转相邻节点,思路是循环整个链表,将相邻节点进行反转。思路简单,但是怎么让代码显得很精炼了。

python实现:

class Solution:
    def swapPairs(self, head):
    """
    :type head: ListNode
    :rtype: ListNode
    """
    prev, prev.next = self, head
    while prev.next and prev.next.next:
        a = prev.next
        b = a.next
        prev.next, b.next, a.next = b, a, b.next
        prev = a
    return self.next

首先需要有三个节点,2个相邻节点和后一个节点。第一行代码如果不熟悉python的可能看不懂,其实是将类Solution对象自己赋值prev, prev.next则表示next是类Solution的一个属性,prev.next才是表示head节点。

需要提醒的是链表长度是偶数的话,是刚好全部2个相邻节点反转,如果是奇数则最后一个节点保持不变。

python多变量赋值有时候确实是晦涩难懂,它是一次性赋值,即先算好等号右边的所有值,然后一次性赋给左边。我们可以先简单枚举一下 1->2->3->4,如果需要反转1和2,则它的下一个状态是什么。先算好右边的值: b=2 a=1 b.next=3, 赋值给左边,则: prev.next=2 b.next=1 a.next=3 赋值之后: b=2 a=1 b.next=1 a.next=3。变成了 2->1->3->4, 可以简单理解为赋值之后,prev.next 就是 b, b.next=1=a=1, a.next=3 串起来就是 2->1->3->4

下面给出1->2->3->4->5具体一次while循环的打印,方便大家更加理解,详细请看完整代码地址https://github.com/CrystalSkyZ/leetcode_tc:

print(a.val, a.next.val, b.val, b.next.val, pre.next.val, pre.next.next.val)
# (1, 2, 2, 3, 1, 2)

# 进行赋值: 
pre.next, b.next, a.next = b, a, b.next

print(a.val, a.next.val, b.val, b.next.val, pre.next.val, pre.next.next.val)
# (1, 3, 2, 1, 2, 1)
print(linear.printLiner(self.next)) # 遍历整个链表
# [2, 1, 3, 4, 5]

pre = a
print(pre.val, a.val, self.next.val, self.next.next.val)
# (1, 1, 2, 1)

2.3 141. Linked List Cycle

leetcode link 141 题目要求: Given a linked list, determine if it has a cycle in it.

Example:

题目要求判断一个链表是否有环,通常有几种思路解法:

  1. 暴力解法, 一直遍历循环看下一个节点是否为null, 如果是环的话则会一直死循环,可以判断一个时间,比如1s或0.5s,则结束。这种解法只是一种思路,实际面试中肯定不是一种好的解法。

  2. Set判重,思路跟思路一一样,一直遍历循环,区别就是每一次遍历,在当前节点留下记号,用set存储起来,如果下一个节点在set里则证明有环,否则无环。时间复杂度是O(N),但是空间复杂度由于用了set,则是O(N)。

  3. 龟兔赛跑,则有一个快指针和一个慢指针,快指针每次走2步,慢指针每次走1步,如果有环的情况下,则2者肯定会相遇,即判断有环。这种思路方式如果没有事先去刷过这个题,是比较难想到的。

代码实现:

  1. Set判重:
class Solution(object):
    def hasCycle(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        exist = set()
        while head:
            if head in exist:
                return True
            exist.add(head)
            head = head.next
        return False
  1. 龟兔赛跑:
class Solution(object):
    def hasCycle(self, head):
        """
        :type head: ListNode
        :rtype: bool
        """
        fast = slow = head
        while slow and fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow is fast:
                return True
        return False

3. 思考题

leetcode上还有几题跟上面讲的类似,可以先去做一下,下一篇再一起交流解法和代码实例:

  1. 142题 地址: leetcode.com/problems/li…
  2. 25题 地址: leetcode.com/problems/re…

如果是国内地址的话,则把路由换成https://leetcode-cn.com/

更多精彩文章请关注公众号 天澄的技术笔记 (ChengTian_Tech)