螺旋矩阵 II:从理论到实践的五种算法解析

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: 螺旋矩阵 II:从理论到实践的五种算法解析

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。

会一些的技术:数据分析、算法、SQL、大数据相关、python

欢迎加入社区:码上找工作

作者专栏每日更新:

LeetCode解锁1000题: 打怪升级之旅

python数据分析可视化:企业实战案例

备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级

题目描述

给定一个链表,旋转链表,将链表每个节点向右移动 k 个位置,其中 k 是非负数。

输入格式
  • head:链表的头节点。
  • k:一个整数,表示旋转的位置数。
输出格式
  • 返回旋转后的链表的头节点。

示例

示例 1
输入: 1->2->3->4->5->NULL, k = 2
输出: 4->5->1->2->3->NULL
解释:
向右旋转 1 步: 5->1->2->3->4->NULL
向右旋转 2 步: 4->5->1->2->3->NULL
示例 2
输入: 0->1->2->NULL, k = 4
输出: 2->0->1->NULL
解释:
向右旋转 1 步: 2->0->1->NULL
向右旋转 2 步: 1->2->0->NULL
向右旋转 3 步: 0->1->2->NULL
向右旋转 4 步: 2->0->1->NULL

方法一:闭合为环

解题步骤
  1. 链表长度:首先遍历整个链表得到链表长度 n 和最后一个节点。
  2. 闭合成环:将链表的尾节点连接到头节点,形成环。
  3. 计算新头位置:根据 k % n 计算新的头节点的位置。
  4. 重置头节点:找到新的头节点和尾节点,断开环。
完整的规范代码
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
def rotateRight(head, k):
    """
    使用闭合环的方法进行链表旋转
    :param head: ListNode, 链表的头节点
    :param k: int, 旋转的位置数
    :return: ListNode, 旋转后的链表头节点
    """
    if not head or not head.next or k == 0:
        return head
    
    # 计算链表长度并形成环
    lastElement = head
    length = 1
    while lastElement.next:
        lastElement = lastElement.next
        length += 1
    lastElement.next = head
    
    # 找到新的尾部:(长度 - k % 长度 - 1)的位置
    k = k % length
    steps_to_new_tail = length - k
    new_tail = head
    for i in range(steps_to_new_tail - 1):
        new_tail = new_tail.next
    
    new_head = new_tail.next
    
    # 断开环
    new_tail.next = None
    
    return new_head
# 示例代码用于创建链表和打印链表
def create_list(lst):
    head = current = ListNode(lst[0])
    for number in lst[1:]:
        current.next = ListNode(number)
        current = current.next
    return head
def print_list(node):
    while node:
        print(node.val, end=" -> ")
        node = node.next
    print("NULL")
# 示例调用
lst = create_list([1, 2, 3, 4, 5])
rotated_lst = rotateRight(lst, 2)
print_list(rotated_lst)  # 输出: 4 -> 5 -> 1 -> 2 -> 3 -> NULL
算法分析
  • 时间复杂度:(O(n)),主要时间开销来自于链表遍历和旋转计算。
  • 空间复杂度:(O(1)),除了给定的链表结构,只使用常数额外空间。

方法二:数组模拟

解题步骤
  1. 转换为数组:遍历链表,存储每个节点的值到数组中。
  2. 数组旋转:对数组进行旋转操作。
  3. 重建链表:根据旋转后的数组重建链表。
完整的规范代码
def rotateRight(head, k):
    """
    使用数组模拟链表旋转
    :param head: ListNode, 链表的头节点
    :param k: int, 旋转的位置数
    :return: ListNode, 旋转后的链表头节点
    """
    if not head or not head.next or k == 0:
        return head
    
    # 转换链表到数组
    nodes = []
    current = head
    while current:
        nodes.append(current.val)
        current = current.next
    
    # 数组旋转
    k = k % len(nodes)
    nodes = nodes[-k:] + nodes[:-k]
    
    # 重建链表
    new_head = current = ListNode(nodes[0])
    for val in nodes[1:]:
        current.next = ListNode(val)
        current = current.next
    
    return new_head
# 示例调用
lst = create_list([1, 2, 3, 4, 5])
rotated_lst = rotateRight(lst, 2)
print_list(rotated_lst)  # 输出: 4 -> 5 -> 1 -> 2 -> 3 -> NULL
算法分析
  • 时间复杂度:(O(n)),包括链表到数组的转换和数组的旋转。
  • 空间复杂度:(O(n)),需要额外空间来存储链表元素的数组。

方法三:直接旋转

解题步骤
  1. 链表遍历:计算链表长度并连接成环。
  2. 计算新尾部:根据旋转次数确定新的尾部位置。
  3. 重建链表:在新的尾部断开环,形成新的链表。
完整的规范代码
def rotateRight(head, k):
    """
    直接通过链表旋转实现
    :param head: ListNode, 链表的头节点
    :param k: int, 旋转的位置数
    :return: ListNode, 旋转后的链表头节点
    """
    if not head or not head.next or k == 0:
        return head
    
    # 计算长度并形成环
    old_tail = head
    length = 1
    while old_tail.next:
        old_tail = old_tail.next
        length += 1
    old_tail.next = head
    
    # 计算新尾部位置
    k = k % length
    new_tail = head
    for i in range(length - k - 1):
        new_tail = new_tail.next
    
    new_head = new_tail.next
    new_tail.next = None
    
    return new_head
# 示例调用
lst = create_list([1, 2, 3, 4, 5])
rotated_lst = rotateRight(lst, 2)
print_list(rotated_lst)  # 输出: 4 -> 5 -> 1 -> 2 -> 3 -> NULL
算法分析
  • 时间复杂度:(O(n)),需要遍历链表两次。
  • 空间复杂度:(O(1)),仅使用常数额外空间。

方法四:改进的数组模拟

解题步骤
  1. 转换为数组:将链表节点转换为数组,方便随机访问。
  2. 数组旋转:对数组进行旋转操作。
  3. 重建链表:根据旋转后的数组重建链表。
完整的规范代码
def rotateRight(head, k):
    """
    使用改进的数组模拟方法旋转链表
    :param head: ListNode, 链表的头节点
    :param k: int, 旋转的位置数
    :return: ListNode, 旋转后的链表头节点
    """
    if not head:
        return None
    
    # 转换链表到数组
    nodes = []
    while head:
        nodes.append(head)
        head = head.next
    
    k = k % len(nodes)
    nodes = nodes[-k:] + nodes[:-k]
    
    # 重建链表
    for i in range(len(nodes) - 1):
        nodes[i].next = nodes[i + 1]
    nodes[-1].next = None
    
    return nodes[0]
# 示例调用
lst = create_list([1, 2, 3, 4, 5])
rotated_lst = rotateRight(lst, 2)
print_list(rotated_lst)  # 输出: 4 -> 5 -> 1 -> 2 -> 3 -> NULL
算法分析
  • 时间复杂度:(O(n)),链表到数组的转换和数组旋转各需要 (O(n))。
  • 空间复杂度:(O(n)),需要额外空间来存储节点指针的数组。

方法五:反向索引旋转

解题步骤
  1. 链表遍历:一次遍历计算链表长度并形成尾部连接。
  2. 反向计算头部:使用长度减去 (k % \text{长度}) 计算新头部和尾部位置。
  3. 断开连接:在新尾部断开链表,形成新的链表结构。
完整的规范代码
def rotateRight(head, k):
    """
    使用反向索引旋转链表
    :param head: ListNode, 链表的头节点
    :param k: int, 旋转的位置数
    :return: ListNode, 旋转后的链表头节点
    """
    if not head or not head.next or k == 0:
        return head
    
    # 完成一次完整遍历以确定长度并形成环
    last = head
    length = 1
    while last.next:
        last = last.next
        length += 1
    last.next = head
    
    # 确定新的头部和尾部
    k = k % length
    if k:
        for _ in range(length - k):
            last = last.next
    head = last.next
    last.next = None
    
    return head
# 示例调用
lst = create_list([1, 2, 3, 4, 5])
rotated_lst = rotateRight(lst, 2)
print_list(rotated_lst)  # 输出: 4 -> 5 -> 1 -> 2 -> 3 -> NULL
算法分析
  • 时间复杂度:(O(n)),可能需要遍历链表两次(计算长度和调整位置)。
  • 空间复杂度:(O(1)),不需要额外的存储空间,除了输入的链表。

不同算法的优劣势对比

特征 方法一: 闭环 方法二: 数组模拟 方法三: 直接旋转 方法四: 改进数组模拟 方法五: 反向索引旋转
时间复杂度 (O(n)) (O(n)) (O(n)) (O(n)) (O(n))
空间复杂度 (O(1)) (O(n)) (O(1)) (O(n)) (O(1))
优势 直观简单,实现快速 方便理解和实现,便于调试 减少了中间转换步骤,提高效率 易于理解和操作,灵活处理 计算头尾连接,避免额外空间,快速
劣势 需要特别处理新的头尾 需要额外空间存储数组,增加空间复杂度 需要准确计算长度和剩余部分 需要额外空间且稍复杂 需要两次遍历,稍增时间开销

应用示例

游戏开发中的角色队列管理

在多人在线游戏中,经常需要管理玩家的队列,例如在战场游戏中旋转玩家的出场顺序。使用旋转链表的算法可以有效地管理这种动态变化的玩家队列,确保每个玩家都能公平地参与游戏,同时也支持快速的动态调整。

欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
9月前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
10月前
|
机器学习/深度学习 人工智能 搜索推荐
从零构建短视频推荐系统:双塔算法架构解析与代码实现
短视频推荐看似“读心”,实则依赖双塔推荐系统:用户塔与物品塔分别将行为与内容编码为向量,通过相似度匹配实现精准推送。本文解析其架构原理、技术实现与工程挑战,揭秘抖音等平台如何用AI抓住你的注意力。
2515 7
从零构建短视频推荐系统:双塔算法架构解析与代码实现
|
10月前
|
机器学习/深度学习 存储 算法
动态规划算法深度解析:0-1背包问题
0-1背包问题是经典的组合优化问题,目标是在给定物品重量和价值及背包容量限制下,选取物品使得总价值最大化且每个物品仅能被选一次。该问题通常采用动态规划方法解决,通过构建二维状态表dp[i][j]记录前i个物品在容量j时的最大价值,利用状态转移方程避免重复计算子问题,从而高效求解最优解。
959 1
|
10月前
|
算法 搜索推荐 Java
贪心算法:部分背包问题深度解析
该Java代码基于贪心算法求解分数背包问题,通过按单位价值降序排序,优先装入高价值物品,并支持部分装入。核心包括冒泡排序优化、分阶段装入策略及精度控制,体现贪心选择性质,适用于可分割资源的最优化场景。
508 1
贪心算法:部分背包问题深度解析
|
10月前
|
机器学习/深度学习 边缘计算 人工智能
粒子群算法模型深度解析与实战应用
蒋星熠Jaxonic是一位深耕智能优化算法领域多年的技术探索者,专注于粒子群优化(PSO)算法的研究与应用。他深入剖析了PSO的数学模型、核心公式及实现方法,并通过大量实践验证了其在神经网络优化、工程设计等复杂问题上的卓越性能。本文全面展示了PSO的理论基础、改进策略与前沿发展方向,为读者提供了一份详尽的技术指南。
粒子群算法模型深度解析与实战应用
|
10月前
|
机器学习/深度学习 资源调度 算法
遗传算法模型深度解析与实战应用
摘要 遗传算法(GA)作为一种受生物进化启发的优化算法,在复杂问题求解中展现出独特优势。本文系统介绍了GA的核心理论、实现细节和应用经验。算法通过模拟自然选择机制,利用选择、交叉、变异三大操作在解空间中进行全局搜索。与梯度下降等传统方法相比,GA不依赖目标函数的连续性或可微性,特别适合处理离散优化、多目标优化等复杂问题。文中详细阐述了染色体编码、适应度函数设计、遗传操作实现等关键技术,并提供了Python代码实现示例。实践表明,GA的成功应用关键在于平衡探索与开发,通过精心调参维持种群多样性同时确保收敛效率
机器学习/深度学习 算法 自动驾驶
1483 0
|
10月前
|
机器学习/深度学习 人工智能 资源调度
大语言模型的核心算法——简要解析
大语言模型的核心算法基于Transformer架构,以自注意力机制为核心,通过Q、K、V矩阵动态捕捉序列内部关系。多头注意力增强模型表达能力,位置编码(如RoPE)解决顺序信息问题。Flash Attention优化计算效率,GQA平衡性能与资源消耗。训练上,DPO替代RLHF提升效率,MoE架构实现参数扩展,Constitutional AI实现自监督对齐。整体技术推动模型在长序列、低资源下的性能突破。
1143 8
|
10月前
|
算法 API 数据安全/隐私保护
深度解析京东图片搜索API:从图像识别到商品匹配的算法实践
京东图片搜索API基于图像识别技术,支持通过上传图片或图片URL搜索相似商品,提供智能匹配、结果筛选、分页查询等功能。适用于比价、竞品分析、推荐系统等场景。支持Python等开发语言,提供详细请求示例与文档。
|
12月前
|
机器学习/深度学习 人工智能 编解码
AI视觉新突破:多角度理解3D世界的算法原理全解析
多视角条件扩散算法通过多张图片输入生成高质量3D模型,克服了单图建模背面细节缺失的问题。该技术模拟人类多角度观察方式,结合跨视图注意力机制与一致性损失优化,大幅提升几何精度与纹理保真度,成为AI 3D生成的重要突破。
1496 0

推荐镜像

更多
  • DNS