链表数据结构的描述_Python描述数据结构之链表实战篇

前言

刷题,尤其是像我这种刚开始刷题的新手,最重要的是要先有个能够执行的算法,能出个结果,即使这个算法很笨,结果很差,也没事,然后再在其基础之上进行改进算法,去做优化,先易后难,一定要思考,画画图,がんばれ(ง •̀_•́)ง!!!

为了方便调试自己的代码,使其能直接运行在LeetCode上,所以,我根据前面几篇博客重新定义了以下函数:

函数名功能CreateSingleLinkList(list)传入一个数组,将数组转换成无头结点的单链表TraverseList(linklist)传入一个单链表,将其节点的值打印出来

class ListNode(object):
    def __init__(self, val=None, next=None):
        self.val = val
        self.next = next


class LeetCodeSingleLinkList(object):
    def __init__(self):
        self.__head = ListNode(None)

    def CreateSingleLinkList(self, val_list):
        prehead = self.__head
        for val in val_list:
            new_node = ListNode(val)
            prehead.next = new_node
            prehead = prehead.next
        # 第一个节点是头结点, 所以要返回链表的下一个节点
        # 即与LeetCode的保持一致
        return self.__head.next


def TraverseList(result):
    # result是不含头结点的
    while result:
        print(result.val, end=' ')
        result = result.next
    print('')


if __name__ == '__main__':
    l1 = LeetCodeSingleLinkList().CreateSingleLinkList([1, 2, 4])
    TraverseList(l1)
这里是LeetCode中有关链表的题库。另外还需要注意,val的数据类型,我这里统一定义为了None。

1. LeetCode21: 合并两个有序链表

LeetCode的第21题:合并两个有序链表。
看到这个题,很大可能想到的就是遍历两个链表,然后进行比较,所以就有了一个遍历的条件,即链表L1和链表L2都不为空。
这里我们采用带头结点的单链表比较方便,我们可以定义一个指针prev,不断地去比较链表L1和链表L2对应的值,如果L1的值小,就将指针prev指向L1,然后L1后移,继续用其第二个结点的值与L2的第一个结点的值比较,每比较完一次,prev都要后移,指向新的结点,就这样遍历一遍。如果链表L1和链表L2的长度不一致,那么指针prev最后将指向较长的那个链表。
实现代码如下:

def mergeTwoLists(l1, l2):
    prevhead = ListNode(None)
    prev = prevhead
    while l1 and l2:
        if l1.val <= l2.val:
            prev.next = l1
            l1 = l1.next
        else:
            prev.next = l2
            l2 = l2.next
        prev = prev.next
    prev.next = l1 if l1 else l2
    # 返回不带头结点的链表
    return prevhead.next

运行结果,emmmm:

82f251582fdbaecd89533be28cf2e3d2.png

2. LeetCode237: 删除链表中的节点

LeetCode的第237题:删除链表中的节点。
这个题给我的感觉就是比较坑,看到这个就先想到了双链表找前驱结点,或者用单链表带两个指针(一前一后)也可以找到,然后就不加思索的实现了,具体代码详见下面的3.3 剑指 Offer 18: 删除链表的节点。
然后提交的时候发现,函数没有传入链表,只传入了需要被删除的结点,而且还不要返回结果,莫名其妙(•́へ•́╬)懵圈。然后看了官方题解,才理解。。。。。。就是直接把要被删除节点的值被其下一个节点的值给覆盖掉,简单粗暴!!!∑(゚Д゚ノ)ノ就是没想到,看来还是涉世未深呐(这是我LeetCode简单系列的第二题(︶.̮︶✽))。
代码如下:

def deleteNode(node):
    # 简单粗暴
    # 237. 删除链表中的节点
    node.val = node.next.val
    node.next = node.next.next

代码如下:

17374a580c7367784814e220ef7ef673.png


只击败了18%的用户,看来还有很大的提升空间呐!

3. 剑指 Offer 18: 删除链表的节点

剑指 Offer的第18题:删除链表中的节点。
这个题才比较正常嘛,注意要看看题目的说明以及官方给的函数参数,单链表实现代码如下:

def deleteNode(head, val):
    # 给链表加上一个头结点
    fakehead = ListNode(None)
    fakehead.next = head
    prehead = fakehead
    while prehead.next:
        result = prehead
        prehead = prehead.next
        if prehead.val == val:
            if prehead.next is None:
                result.next = None
            else:
                result.next = prehead.next
            return fakehead.next
    return fakehead.next

运行如下:

f846ffaaa256ece2abadc7024e1d0655.png

4. LeetCode234: 回文链表

LeetCode第234题:回文链表。
官方给的依旧是单链表,另外,题目中只是判断是否为回文链表,即结果返回是布尔值True或False,enmmm,既然这样,那完全可以用数组实现,哈哈哈哈哈哈,前面博客也说了,在Python中,数组和字典是基本的数据结构,我们可以基于这两种结构构造其他的数据结构。
大致就是将单链表每个节点的值放在数组里,因为回文链表是个对称的结构,回文数组也是,只需判断原数组与翻转后的数组是否一样即可。
代码如下:

def isPalindrome(head):
    prehead = head
    fake_list = []
    while prehead:
        fake_list.append(prehead.val)
        prehead = prehead.next
    return fake_list == fake_list[::-1]

运行结果如下:

67833ea75d5e25855c55c865d4153466.png

5. 面试题 02.02: 返回倒数第 k 个节点

面试题 02.02:返回倒数第 k 个节点。
可以做成两个指针front和rear,两个指针的间距为kkk,当后面那个指针rear走到最后时,前面的front指针就来到了倒数第kkk个节点。

def kthToLast(head, k):
    front = head
    rear = head
    for i in range(k):
        rear = rear.next
    while rear:
        front = front.next
        rear = rear.next
    return front.val

运行结果如下:

9c5bbd16cb84a6e0ae8d0a2ec62c6d0a.png

6. LeetCode83:删除排序链表中的重复元素

LeetCode第83题:删除排序链表中的重复元素。

一失足成千古恨呐,本来是想执行一下代码,结果点成提交了(’∇’)シ┳━┳,少了一个条件。这个题还是很简单的(本来练习的就是简单题),题目中也说了是一个排序链表,如此就直接判断当前结点的值与其后继节点的值是否一样,不一样的话指针后移;若值一样,则将当前结点的next指向其后继结点的后继结点,最后返回处理后的链表。

def deleteDuplicates(head):
    prehead = head
    while prehead and prehead.next:
        if prehead.val == prehead.next.val:
            prehead.next = prehead.next.next
        else:
            prehead = prehead.next
    return head

运行结果如下:

f7ed6d9113b5bbba9cb2591c2ac21478.png

7. LeetCode1290:二进制链表转整数

LeetCode第1290题:二进制链表转整数。
这个题目就是个二进制转十进制,不同的是这次我们不是从最低位开始,而是要从最高位,这也很容易。在学习C语言时就晓得十进制转二进制,就是不断除2,然后余数最下面的就是最高位,就像下面这样子:

852f8b9c28b3a8aa141a25b36b0651fe.png


13的二进制就是1101,如果从最高位开始将其转换为十进制就是:2×0+1=1−−>2×1+1=3−−>2×3+0=6−−>2×6+1=132times0+1=1-->2times1+1=3-->2times3+0=6-->2times6+1=132×0+1=1−−>2×1+1=3−−>2×3+0=6−−>2×6+1=13,代码实现如下:

def getDecimalValue(head):
    prehead = head
    result = 0
    while prehead:
        result = 2 * result + prehead.val
        prehead = prehead.next
    return result

运行结果如下:

283596d7af053cd855f61121ce01e7da.png


当然,在Python可以直接将二进制转换成十进制,用int()函数就可以,代码如下:

def getDecimalValue(head):
    prehead = head
    result = '0b'
    while prehead:
        result += str(prehead.val)
        prehead = prehead.next
    return int(result, 2)

运行结果如下:

0e4e6254cc4a8c79418f16c01147c98c.png

结束语

虽然以前学过数据结构,但平时没有刷过题,这也是第一次刷题,哈哈哈惭愧惭愧,所以就从LeetCode的简单题目入手,然后慢慢加深加大难度。做了这几个题,我觉得对于我这种新手来说,还是要画画图,需要的话在调试一下,哈哈哈哈,加油(ง •̀_•́)ง

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值