算法入门很简单:链表题套路及精选题目(上)

简介: 链表(Linked List):一种线性表数据结构。它使用一组任意的存储单元(可以是连续的,也可以是不连续的),来存储一组具有相同类型的数据。

链表介绍

链表(Linked List):一种线性表数据结构。它使用一组任意的存储单元(可以是连续的,也可以是不连续的),来存储一组具有相同类型的数据。


简单来说,「链表」 是实现线性表的链式存储结构的基础。存储模式如下:


image.png


在链表中,数据元素之间的逻辑关系是通过指针来间接反映的。逻辑上相邻的数据元素在物理地址上可能相邻,可也能不相邻。其在物理地址上的表现是随机的。


我们先来简单介绍一下链表结构的优缺点:


  • 优点:存储空间不必事先分配,在需要存储空间的时候可以临时申请,不会造成空间的浪费;一些操作的时间效率远比数组高(插入、移动、删除元素等)。
  • 缺点:不仅数据元素本身的数据信息要占用存储空间,指针也需要占用存储空间,链表结构比数组结构的空间开销大。

套路总结

链表操作套路:链表不仅仅是穿针引线,还有双指针,虚拟节点,迭代和递归。

精选题目

1. 反转链表

Python 版本:

def reverseList(self, head):
    cur, prev = head, None
    while cur:
        cur.next, prev, cur = prev, cur, cur.next
    return prev


Go 语言版本:

func reverseList(head *ListNode) *ListNode {
    if head == nil {
        return nil
    }
    cur := head
    var pre *ListNode
    for cur != nil {
        tmp := cur.Next
        cur.Next = pre
        pre = cur
        cur = tmp
    }
    return pre
}

2. 反转链表 2

https://leetcode-cn.com/problems/reverse-linked-list-ii/

思路 1:迭代

  1. 使用两个指针 curpre 进行迭代。pre 指向 cur 前一个节点位置。初始时,pre 指向 Nonecur 指向 head
  2. precur 的前后指针进行交换,指针更替顺序为:
    使用 next 指针保存当前节点 cur 的后一个节点,即 next = cur.next
    断开当前节点 cur 的后一节点链接,将 curnext 指针指向前一节点 pre,即 cur.next = pre
    pre 向前移动一步,移动到 cur 位置,即 pre = cur
    cur 向前移动一步,移动到之前 next 指针保存的位置,即 cur = next
  3. 继续执行第 2 步中的 1、2、3、4。
  4. 最后等到 cur 遍历到链表末尾,即 cur == None,时,pre 所在位置就是反转后链表的头节点,返回新的头节点 pre
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre = None
        cur = head
        while cur != None:
            next = cur.next
            cur.next = pre
            pre = cur
            cur = next
        return pre

思路 2:递归

具体做法如下:

  • 首先定义递归函数含义为:将链表反转,并返回反转后的头节点。
  • 然后从 head.next 的位置开始调用递归函数,即将 head.next 为头节点的链表进行反转,并返回该链表的头节点。
  • 递归到链表的最后一个节点,将其作为最终的头节点,即为 new_head
  • 在每次递归函数返回的过程中,改变 headhead.next 的指向关系。也就是将 head.nextnext 指针先指向当前节点 head,即 head.next.next = head
  • 然后让当前节点 headnext 指针指向 None,从而实现从链表尾部开始的局部反转。
  • 当递归从末尾开始顺着递归栈的退出,从而将整个链表进行反转。
  • 最后返回反转后的链表头节点 new_head
class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if head == None or head.next == None:
            return head
        new_head = self.reverseList(head.next)
        head.next.next = head
        head.next = None
        return new_head

3. 两数相加

def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
    dummy = tail = ListNode(None)
    sum = 0
    while l1 or l2 or sum:
        sum += (l1.val if l1 else 0) + (l2.val if l2 else 0)
        tail.next = ListNode(sum % 10)
        tail = tail.next
        sum // 10
        l1 = l1.next if l1 else None
        l2 = l2.next if l2 else None
    return dummy.next

4. 两两交换链表中的节点

def swapPairs(self, head: ListNode) -> ListNode:
    # 申请一个虚节点头
    pre, pre.next = self, head
    # 空 或者 只剩下一个节点
    while pre.next and pre.next.next:
        a = pre.next
        b = a.next
        pre.next, b.next, a.next = b, a, b.next
        pre = a
    return pre.next
func swapPairs(head *ListNode) *ListNode {
    if head == nil {
        return nil
    }
    if head.Next == nil {
        return head
    }
    var (
        dummy *ListNode = &ListNode{0, head}
        temp = dummy
        cur = dummy.Next
    )
    for cur != nil && cur.Next != nil {
        temp.Next = cur.Next
        cur.Next = cur.Next.Next
        temp.Next.Next = cur
        temp = cur
        cur = cur.Next
    }
    return dummy.Next
}
相关文章
|
2月前
|
存储 算法
算法入门:专题二---滑动窗口(长度最小的子数组)类型题目攻克!
给定一个正整数数组和目标值target,找出总和大于等于target的最短连续子数组长度。利用滑动窗口(双指针)优化,维护窗口内元素和,通过单调性避免重复枚举,时间复杂度O(n)。当窗口和满足条件时收缩左边界,更新最小长度,最终返回结果。
|
2月前
|
存储 算法
算法入门:专题一:双指针(有效三角形的个数)
给定一个数组,找出能组成三角形的三元组个数。利用“两边之和大于第三边”的性质,先排序,再用双指针优化。固定最大边,左右指针从区间两端向内移动,若两短边之和大于最长边,则中间所有组合均有效,时间复杂度由暴力的O(n³)降至O(n²)。
|
2月前
|
存储 算法 编译器
算法入门:剑指offer改编题目:查找总价格为目标值的两个商品
给定递增数组和目标值target,找出两数之和等于target的两个数字。利用双指针法,left从头、right从尾向中间逼近,根据和与target的大小关系调整指针,时间复杂度O(n),空间复杂度O(1)。找不到时返回{-1,-1}。
|
5月前
|
机器学习/深度学习 数据采集 算法
你天天听“数据挖掘”,可它到底在“挖”啥?——数据挖掘算法入门扫盲篇
你天天听“数据挖掘”,可它到底在“挖”啥?——数据挖掘算法入门扫盲篇
111 0
|
9月前
|
机器学习/深度学习 算法 机器人
强化学习:时间差分(TD)(SARSA算法和Q-Learning算法)(看不懂算我输专栏)——手把手教你入门强化学习(六)
本文介绍了时间差分法(TD)中的两种经典算法:SARSA和Q-Learning。二者均为无模型强化学习方法,通过与环境交互估算动作价值函数。SARSA是On-Policy算法,采用ε-greedy策略进行动作选择和评估;而Q-Learning为Off-Policy算法,评估时选取下一状态中估值最大的动作。相比动态规划和蒙特卡洛方法,TD算法结合了自举更新与样本更新的优势,实现边行动边学习。文章通过生动的例子解释了两者的差异,并提供了伪代码帮助理解。
674 2
|
8月前
|
存储 算法 物联网
解析局域网内控制电脑机制:基于 Go 语言链表算法的隐秘通信技术探究
数字化办公与物联网蓬勃发展的时代背景下,局域网内计算机控制已成为提升工作效率、达成设备协同管理的重要途径。无论是企业远程办公时的设备统一调度,还是智能家居系统中多设备间的联动控制,高效的数据传输与管理机制均构成实现局域网内计算机控制功能的核心要素。本文将深入探究 Go 语言中的链表数据结构,剖析其在局域网内计算机控制过程中,如何达成数据的有序存储与高效传输,并通过完整的 Go 语言代码示例展示其应用流程。
145 0
|
9月前
|
存储 监控 算法
员工电脑监控系统中的 C# 链表算法剖析-如何监控员工的电脑
当代企业管理体系中,员工电脑监控已成为一个具有重要研究价值与实践意义的关键议题。随着数字化办公模式的广泛普及,企业亟需确保员工对公司资源的合理利用,维护网络安全环境,并提升整体工作效率。有效的电脑监控手段对于企业实现这些目标具有不可忽视的作用,而这一过程离不开精妙的数据结构与算法作为技术支撑。本文旨在深入探究链表(Linked List)这一经典数据结构在员工电脑监控场景中的具体应用,并通过 C# 编程语言给出详尽的代码实现与解析。
187 5
|
10月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
380 30
|
10月前
|
存储 监控 算法
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
203 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
|
2月前
|
机器学习/深度学习 算法 机器人
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
218 0