【经典算法】LeetCode25:K 个一组翻转链表(Java/C/Python3,Hard)

#算法

目录

  • 题目描述
  • 思路及实现
    • 方式一:递归
      • 思路
      • 代码实现
        • Java 版本
        • C 语言版本
        • Python3 版本
      • 复杂度分析
    • 方式二:迭代和原地反转
      • 思路
      • 代码实现
        • Java 版本
        • C 语言版本
        • Python3 版本
      • 复杂度分析
  • 总结
  • 相似题目

  • 标签:链表、递归

题目描述

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例 1:

输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
示例 2:

输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]
提示:
链表中的节点数目为 n
1 <= k <= n <= 5000
0 <= Node.val <= 1000
进阶:你可以设计一个只用 O(1) 额外内存空间的算法解决此问题吗?

原题:LeetCode 25

思路及实现

方式一:递归

思路

其大致过程可以分解为

  1. 找到待翻转的k个节点(注意:若剩余数量小于 k 的话,则不需要反转,因此直接返回待翻转部分的头结点即可)。
  2. 对其进行翻转。并返回翻转后的头结点(注意:翻转为左闭又开区间,所以本轮操作的尾结点其实就是下一轮操作的头结点)。
  3. 对下一轮 k 个节点也进行翻转操作。
  4. 将上一轮翻转后的尾结点指向下一轮翻转后的头节点,即将每一轮翻转的k的节点连接起来。

示意图

代码实现

Java 版本
/*** Definition for singly-linked list.* public class ListNode {*     int val;*     ListNode next;*     ListNode() {}*     ListNode(int val) { this.val = val; }*     ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/
class Solution {/*** 反转链表中每个大小为 k 的连续节点的子链表* @param head 当前子链表的头节点* @param k 指定的连续节点个数* @return 反转后的链表的头节点*/public ListNode reverseKGroup(ListNode head, int k) {if (head == null || head.next == null) {return head;}ListNode tail = head;for (int i = 0; i < k; i++) {// 如果剩余数量小于 k,则不需要反转。if (tail == null) {return head;}tail = tail.next;}// 反转前 k 个元素ListNode newHead = reverse(head, tail);// 下一轮的开始的地方就是 tailhead.next = reverseKGroup(tail, k);return newHead;}/*** 反转链表中左闭右开区间的节点* @param head 左闭区间的头节点* @param tail 右开区间的尾节点* @return 反转后的链表的头节点*/private ListNode reverse(ListNode head, ListNode tail) {ListNode pre = null;ListNode next = null;while (head != tail) {next = head.next;head.next = pre;pre = head;head = next;}return pre;}
}

说明:
reverseKGroup() 方法用于将链表每个大小为 k 的子列表进行反转。
如果输入的头节点 head 或其下一个节点为空,则无需翻转,直接返回头节点。
使用 tail 指针找到当前子列表的结束节点(即当前子列表的下一组的开始节点)。
如果剩余节点数量不足 k,则无需进行翻转,直接返回头节点。
调用 reverse() 方法反转当前子列表,并得到翻转后的新的头节点 newHead。
通过递归调用 reverseKGroup() 方法,将下一轮的开始位置 tail 作为参数传入。
将当前子列表的头节点 head 的 next 指针指向下一轮的结果,连接翻转后的下一组子列表。
返回翻转后的新的头节点 newHead。

C 语言版本
struct ListNode {int val;struct ListNode *next;
};/*** 反转以头节点head开始,尾节点为tail前一个节点的链表* 返回反转后的链表的头节点*/
struct ListNode* reverse(struct ListNode* head, struct ListNode* tail) {struct ListNode* prev = NULL;struct ListNode* curr = head;struct ListNode* next = NULL;while (curr != tail) {next = curr->next;curr->next = prev;prev = curr;curr = next;}return prev;
}/*** 反转每个大小为k的连续节点子链表* 返回修改后的链表的头节点*/
struct ListNode* reverseKGroup(struct ListNode* head, int k) {if (head == NULL || head->next == NULL) {return head;}struct ListNode* tail = head;for (int i = 0; i < k; i++) {// 如果剩余节点数不足k个,无需反转,直接返回头节点if (tail == NULL) {return head;}tail = tail->next;}// 反转前k个节点struct ListNode* newHead = reverse(head, tail);// 递归调用反转后续的子链表,并将结果连接到当前子链表的末尾head->next = reverseKGroup(tail, k);return newHead;
}

说明:
结构体 ListNode 定义了链表节点的结构,包含一个整型变量 val 和一个指向下一个节点的指针 next。
reverse() 函数用于反转以 head 节点为开始,以 tail 节点为前一个节点的子链表,并返回反转后的链表的头节点。
在 reverse() 函数中,使用三个指针 prev、curr 和 next 分别表示前一个节点、当前节点和下一个节点。
在 while 循环中,将当前节点 curr 的 next 指针指向前一个节点 prev,实现反转。
通过更新指针的位置,进行下一次的节点遍历。
返回反转后的链表的头节点 prev。
reverseKGroup() 函数用于反转每个大小为 k 的连续节点的子链表,并返回修改后的链表的头节点。
在 reverseKGroup() 函数中,如果输入的头节点 head 或其下一个节点为空,则无需反转,直接返回头节点。
使用指针 tail 找到当前子链表的结束节点(即当前子链表的下一组的开始节点)。
如果剩余节点数量不足 k,则无需反转,直接返回头节点。
调用 reverse() 函数反转当前子链表,并得到反转后的新头节点 newHead。
递归调用 reverseKGroup() 函数,对剩余的子链表进行反转,并将结果连接到当前子链表的末尾。
返回反转后的新头节点 newHead。

Python3 版本

class ListNode:def __init__(self, val=0, next=None):self.val = valself.next = nextdef reverse(head: ListNode, tail: ListNode) -> ListNode:"""反转以head为头节点、tail为尾节点的子链表并返回反转后的链表的头节点"""prev = Nonecurr = headwhile curr != tail:next = curr.nextcurr.next = prevprev = currcurr = nextreturn prevdef reverseKGroup(head: ListNode, k: int) -> ListNode:"""反转每个大小为k的连续子链表并返回修改后的链表的头节点"""if not head or not head.next:return headtail = head# 找到子链表的尾节点for _ in range(k):if not tail:return headtail = tail.next# 反转子链表,并获取反转后的新的头节点new_head = reverse(head, tail)# 递归调用,将下一组子链表的头节点连接到当前子链表的末尾head.next = reverseKGroup(tail, k)return new_head

代码说明:
ListNode 类定义了链表节点的结构,包含一个整数类型变量 val 和一个指向下一个节点的指针 next。
reverse() 函数用于反转以 head 节点为开始,以 tail 节点为前一个节点的子链表,并返回反转后的链表的头节点。
在 reverse() 函数中,使用三个指针 prev、curr 和 next 分别表示前一个节点、当前节点和下一个节点。
在 while 循环中,将当前节点 curr 的 next 指针指向前一个节点 prev,实现反转。
通过更新指针的位置,进行下一次的节点遍历。
返回反转后的链表的头节点 prev。
reverseKGroup() 函数用于反转每个大小为 k 的连续节点的子链表,并返回修改后的链表的头节点。
在 reverseKGroup() 函数中,如果输入的头节点 head 或其下一个节点为空,则无需反转,直接返回头节点。
使用指针 tail 找到当前子链表的结束节点(即当前子链表的下一组的开始节点)。
如果剩余节点数量不足 k,则无需反转,直接返回头节点。
调用 reverse() 函数反转当前子链表,并得到反转后的新头节点 new_head。
递归调用 reverseKGroup() 函数,对剩余的子链表进行反转,并将结果连接到当前子链表的末尾。
返回反转后的新头节点 new_head。

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的长度。每个节点都被遍历一次,每次遍历反转 k 个节点。

  • 空间复杂度:O(n/k),递归调用栈的深度

方式二:迭代和原地反转

思路

迭代和原地反转的方法是通过遍历链表,对每个子链表进行原地反转,然后将反转后的子链表拼接到最终结果中。

代码实现

Java 版本
class Solution {/*** 反转以 head 为头节点的链表中的前 k 个节点* 返回反转后的头节点以及反转后的尾节点*/private ListNode reverseK(ListNode head, int k) {ListNode prev = null;ListNode curr = head;for (int i = 0; i < k; i++) {ListNode next = curr.next;curr.next = prev;prev = curr;curr = next;}return new ListNode[]{prev, head};}public ListNode reverseKGroup(ListNode head, int k) {ListNode dummy = new ListNode(0); // 创建一个虚拟头节点dummy.next = head;ListNode prev = dummy; // prev 始终指向每个子链表的反转前的最后一个节点ListNode curr = head; // curr 用于遍历链表while (curr != null) {ListNode tail = curr; // tail 保存每个子链表的最后一个节点int count = 0; // count 记录当前子链表的长度while (curr != null && count < k) {curr = curr.next;count++;}if (count < k) {// 如果剩余节点数不足 k,则不需要反转,直接跳出循环break;}ListNode[] result = reverseK(tail, k); // 反转当前子链表的前 k 个节点ListNode reversedHead = result[0]; // 反转后的头节点ListNode reversedTail = result[1]; // 反转后的尾节点// 将反转后的子链表接入链表prev.next = reversedHead;reversedTail.next = curr;prev = reversedTail; // 更新 prev 指针}return dummy.next;}
}

说明:
reverseK 方法用于反转以 head 为头节点的链表中的前 k 个节点。返回反转后的头节点和尾节点(这里使用了一个数组来返回多个节点)。
reverseKGroup 方法实现以 k 个一组翻转链表的功能。
创建一个虚拟头节点 dummy 来简化链表操作。
prev 指针始终指向每个子链表的反转前的最后一个节点。
curr 指针用于遍历链表。
使用循环遍历链表,直至 curr 为 null,这样可以处理剩余不足 k 个节点的情况。
在循环中,先找到当前子链表的最后一个节点 tail。
然后,再遍历 k 个节点,通过调用 reverseK 方法来反转这个子链表的前 k 个节点。
获取反转后的头节点 reversedHead 和尾节点 reversedTail。
将反转后的子链表接入链表中,即将 prev 的 next 指向 reversedHead,reversedTail 的 next 指向 curr。
更新 prev 指针,使其指向反转后的尾节点。

C 语言版本

struct ListNode {int val;struct ListNode *next;
};/*** 反转以 head 为头节点、tail 为尾节点的子链表* 并返回反转后的链表的头节点*/
struct ListNode* reverseLinkedList(struct ListNode* head, struct ListNode* tail) {struct ListNode* prev = NULL;struct ListNode* curr = head;while (curr != tail) {struct ListNode* next = curr->next;curr->next = prev;prev = curr;curr = next;}return prev;
}/*** 按照 k 个一组翻转链表* 并返回修改后的链表的头节点*/
struct ListNode* reverseKGroup(struct ListNode* head, int k) {struct ListNode* dummy = malloc(sizeof(struct ListNode)); // 创建一个虚拟头节点dummy->val = 0;dummy->next = head;struct ListNode* prev = dummy; // prev 始终指向每个子链表的反转前的最后一个节点struct ListNode* curr = head; // curr 用于遍历链表while (curr != NULL) {struct ListNode* tail = curr; // tail 保存每个子链表的最后一个节点int count = 0; // count 记录当前子链表的长度while (curr != NULL && count < k) {curr = curr->next;count++;}if (count < k) {break; // 如果剩余节点数不足 k,则不需要反转,直接跳出循环}struct ListNode* reversedHead = reverseLinkedList(tail, curr); // 反转当前子链表struct ListNode* reversedTail = tail;// 将反转后的子链表接入链表prev->next = reversedHead;reversedTail->next = curr;prev = reversedTail; // 更新 prev 指针}struct ListNode* newHead = dummy->next;free(dummy); // 释放虚拟头节点的内存return newHead;
}

说明:
reverseLinkedList 函数用于反转以 head 为头节点,以 tail 为前一个节点的子链表,并返回反转后的链表的头节点。
在 reverseLinkedList 函数中,使用两个指针 prev 和 curr 分别表示前一个节点和当前节点。
在 while 循环中,将当前节点 curr 的 next 指针指向前一个节点 prev,实现反转。
通过更新指针的位置,进行下一次的节点遍历。
返回反转后的链表的头节点 prev。
reverseKGroup 函数实现按照 k 个一组翻转链表的功能。
创建一个虚拟头节点 dummy 并将其指向链表的头部,以便于处理头节点的情况。
使用两个指针 prev 和 curr 分别指向当前子链表的最后一个节点和遍历节点。
在循环中,首先找到当前子链表的末尾节点 tail,然后再遍历 k 个节点。
如果剩余的节点数量不足 k 个,则不需要反转,直接退出循环。
调用 reverseLinkedList 函数反转当前子链表,并获取反转后的头节点 reversedHead 和尾节点 reversedTail。
将反转后的子链表接入链表中,即将 prev 的 next 指针指向 reversedHead,reversedTail 的 next 指针指向 curr。
更新 prev 指针,向后移动到反转后的子链表的尾节点。
返回虚拟头节点 dummy 的 next 指针,即为反转后的链表的头结点。

Python3 版本
class ListNode:def __init__(self, val=0, next=None):self.val = valself.next = nextdef reverseLinkedList(head: ListNode, tail: ListNode) -> ListNode:prev = Nonecurr = headwhile curr != tail:next_node = curr.nextcurr.next = prevprev = currcurr = next_nodereturn prevdef reverseKGroup(head: ListNode, k: int) -> ListNode:dummy = ListNode(0)  # 创建一个虚拟头节点dummy.next = headprev = dummy  # prev 始终指向每个子链表的反转前的最后一个节点curr = head  # curr 用于遍历链表while curr:tail = curr  # tail 保存每个子链表的最后一个节点count = 0  # count 记录当前子链表的长度while curr and count < k:curr = curr.nextcount += 1if count < k:break  # 如果剩余节点数不足 k,则不需要反转,直接跳出循环reversed_head = reverseLinkedList(tail, curr)  # 反转当前子链表reversed_tail = tail# 将反转后的子链表接入链表prev.next = reversed_headreversed_tail.next = currprev = reversed_tail  # 更新 prev 指针return dummy.next

说明:
reverseLinkedList 函数用于反转以 head 为头节点、tail 为尾节点的子链表,并返回反转后的链表的头节点。

在 reverseLinkedList 函数中,使用两个指针 prev 和 curr 分别表示前一个节点和当前节点。

在 while 循环中,将当前节点 curr 的 next 指针指向前一个节点 prev,实现反转。

通过更新指针的位置,进行下一次的节点遍历。

返回反转后的链表的头节点 prev。

reverseKGroup 函数用于按照 k 个一组翻转链表。

创建一个虚拟头节点 dummy 并将其指向链表的头部,以便于处理头节点的情况。

使用两个指针 prev 和 curr 分别指向当前子链表的最后一个节点和遍历节点。

在循环中,首先找到当前子链表的末尾节点 tail,然后再遍历 k 个节点。

如果剩余的节点数量不足 k 个,则不需要反转,直接退出循环。

调用 reverseLinkedList 函数反转子链表,并获取反转后的头节点和尾节点。

将反转后的子链表接入链表中,即将 prev 的 next 指针指向反转后的头节点,尾节点的 next 指针指向下一个子链表的头节点。

更新 prev 指针,向后移动到反转后的子链表的尾节点。

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的长度。每个节点恰好被访问两次:一次是遍历整个链表,一次是进行反转操作。
  • 空间复杂度:O(1)。只使用了常数级别的额外空间来进行指针操作,没有使用额外的数据结构。

总结

递归法迭代+原地反转方法
思路将链表划分为大小为k的子链表,递归处理使用循环迭代遍历链表,并在每次迭代中原地反转子链表
时间复杂度O(n),每个节点被遍历一次O(n),每个节点被遍历一次
空间复杂度O(n/k),递归调用栈的深度O(1),原地修改链表
(如果递归栈的深度达到n/k,则创建了O(n/k)个递归调用栈帧)(不需要额外的空间,仅使用常数级别的指针变量和变量存储空间)
优点实现简单,逻辑清晰不需要额外的递归调用栈,适用于大规模链表
代码可读性好原地修改链表,不需要额外空间
缺点递归调用栈可能溢出实现相对复杂,需要处理指针的连接
额外的空间复杂度需要对子链表进行循环遍历和反转
特点可以处理较小规模的链表适用于大规模链表处理和优化空间复杂度
可读性好,思考和实现过程接近问题描述可读性相对较差,实现相对复杂

相似题目

相似题目力扣链接
反转链表 II力扣92
反转链表力扣206
K个一组翻转链表力扣25

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/796747.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

金融企业区域集中库的设计构想和测试验证

导读 本文探讨了金融企业区域集中库的设计构想和测试验证&#xff0c;包括架构设想、数据库整合场景测试及优势和使用设想。作者提出利用 TiDB 数据库产品集中建设区域集中库&#xff0c;解决 MySQL 存量节点的整合问题&#xff0c;实现部署的标准化、按需扩展和统一运维管理。…

阿里云4核8G服务器ECS通用算力型u1实例优惠价格

阿里云4核8G服务器优惠价格955元一年&#xff0c;配置为ECS通用算力型u1实例&#xff08;ecs.u1-c1m2.xlarge&#xff09;4核8G配置、1M到3M带宽可选、ESSD Entry系统盘20G到40G可选&#xff0c;CPU采用Intel(R) Xeon(R) Platinum处理器&#xff0c;阿里云活动链接 aliyunfuwuq…

11 flink-sql 中基于 mysql-cdc 连接 mysql-pxc 集群无法获取增量数据问题

前言 问题是来自于 群友, 2024.03.29, 也是花了一些时间 来排查这个问题 大致的问题是用 mysql-cdc 连接了一个 mysql-pxc 集群, 然后创建了一个 test_user 表 使用 "select * from test_user" 获取数据表的数据, 可以拿到 查询时的快照, 但是 无法获取到后续对…

拾光坞N3 ARM 虚拟主机 i茅台项目

拾光坞N3 在Dcoker部署i茅台案例 OS&#xff1a;Ubuntu 22.04.1 LTS aarch64 cpu&#xff1a;RK3566 ram&#xff1a;2G 部署流程——》mysql——》java8——》redis——》nginx mysql # 依赖 apt update apt install -y net-tools apt install -y libaio* # 下载mysql wg…

CSS设置字体样式

目录 前言&#xff1a; 1.font-family&#xff1a; 2.font-style&#xff1a; 3.font-weight&#xff1a; 4.font-size&#xff1a; 5.font-variant&#xff1a; 6.font&#xff1a; 前言&#xff1a; 在网页中字体是重要的组成部分&#xff0c;使用好字体可以让网页更…

[AIGC] Spring Interceptor 拦截器详解

文章目录 什么是Spring Interceptor如何使用Spring InterceptorSpring Interceptor的影响 什么是Spring Interceptor Interceptor&#xff08;拦截器&#xff09;是Spring MVC框架中的一种特性&#xff0c;类似于Servlet开发中的Filter&#xff08;过滤器&#xff09;&#xf…

Java常用函数接口

Java常用函数接口 Java 8 中引入的常用函数式接口&#xff0c;也就是 java.util.function 包中的接口。这些接口提供了一种简洁的方式来定义函数&#xff0c;常用于 Lambda 表达式和方法引用。下面是一些常用的接口&#xff1a; 一、Predicate&#xff08;断言&#xff09; …

前端学习之DOM编程星星点灯案例

这个案例的实现逻辑是当你点击屏幕时&#xff0c;会完成一个事件&#xff0c;在你的屏幕上生成一张星星图片。然后再设置星星图片的大小将其改为随机。 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><t…

代码随想录刷题——5双指针法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言5.1 移除元素&#xff08;3.30&#xff09;5.2 翻转字符串&#xff08;3.30&#xff09;5.3 替换数字&#xff08;3.30&#xff09;5.4 翻转字符串里的单词(3.3…

使用开源AI引擎:提高合同管理效率与合规性方案|可本地化部署

合同管理是企业运营中的关键环节&#xff0c;它不仅涉及到企业的经济利益&#xff0c;还直接关系到企业的法律风险控制。随着企业规模的扩大和业务的复杂化&#xff0c;传统的人工合同审核方式已经难以满足高效、准确的管理需求。因此&#xff0c;采用技术手段提高合同管理的效…

Vue基础知识:vue路由——模式设置(hash路由,history路由)

路由的路径会出现#,能否将#符号去掉。 1.hash路由&#xff08;默认&#xff09; 例如&#xff1a; “http//local:8080/#/home” 哈希路由&#xff0c;它的底层基于a标签锚 2.history路由&#xff08;常用&#xff09;例如&#xff1a; “http//local:8080/home”&#xff08…

LabVIEW数控磨床振动分析及监控系统

LabVIEW数控磨床振动分析及监控系统 在现代精密加工中&#xff0c;数控磨床作为关键设备之一&#xff0c;其加工质量直接影响到产品的精度与性能。然而&#xff0c;磨削过程中的振动是影响加工质量的主要因素之一&#xff0c;不仅会导致工件表面质量下降&#xff0c;还可能缩短…

zdpdjango_argonadmin Django后台管理系统中的常见功能开发

效果预览 首先&#xff0c;看一下这个项目最开始的样子&#xff1a; 左侧优化 将左侧优化为下面的样子&#xff1a; 代码位置&#xff1a; 代码如下&#xff1a; {% load i18n static admin_argon %}<aside class"sidenav bg-white navbar navbar-vertical na…

【Go】十八、管道

文章目录 1、管道2、管道的定义3、管道的关闭4、管道的遍历5、管道 协程6、只读、只写管道7、管道的阻塞8、select 1、管道 channel本质是一个队列&#xff0c;先进先出自身线程安全&#xff0c;多协程访问时&#xff0c;不用加锁&#xff0c;channel本身就是线程安全的一个s…

练习 19 Web [BJDCTF2020]Easy MD5

如果你是第一批做这个题的&#xff0c;这道题一点也不easy 打开在前端代码里面看到&#xff0c;输入框输入的内容实际是’password’ 随意输入内容&#xff0c;查看响应header中的内容有一句SQL代码&#xff0c;可知我们要让password在md5后返回值为true 然后尬住&#xff…

蓝桥杯嵌入式(G431)备赛笔记——LED

目录 cubeMX配置&#xff1a; 代码模板&#xff1a; 注意&#xff1a; cubeMX配置&#xff1a; 原理图&#xff0c;其中PD2高电平使能锁存器&#xff0c;PC8-15默认给高电平&#xff0c;放置上电初始化LED亮 74HC573是八路输出锁存器 1脚是使能&#xff0c;低电平有效&#…

05-延迟任务精准发布文章

延迟任务精准发布文章 1)文章定时发布 2)延迟任务概述 2.1)什么是延迟任务 定时任务&#xff1a;有固定周期的&#xff0c;有明确的触发时间延迟队列&#xff1a;没有固定的开始时间&#xff0c;它常常是由一个事件触发的&#xff0c;而在这个事件触发之后的一段时间内触发…

深度剖析鞋服品牌商品数字化管理的重要性

随着信息技术的迅猛发展与市场竞争的加剧&#xff0c;鞋服品牌商品数字化管理的重要性愈发凸显。数字化管理不仅关乎企业运营效率的提升&#xff0c;更是品牌实现差异化竞争、提升顾客体验、构建智慧零售生态的关键所在。对于鞋服品牌企业而言&#xff0c;提升商品数字化管理的…

【Linux】环境基础开发工具使用——vim使用

Linux 软件包管理器 yum 什么是软件包 1.在 Linux 下安装软件 , 一个通常的办法是下载到程序的源代码 , 并进行编译 , 得到可执行程序 . 2.但是这样太麻烦了 , 于是有些人把一些常用的软件提前编译好 , 做成软件包 ( 可以理解成 windows 上的安装程序) 放在一个服务器…

深度学习-机器视觉part2

深度学习-机器视觉part2 文章目录 深度学习-机器视觉part2一、从卷积到卷积神经网络二、手撕卷积代码2.1 动机2.2 数据集2.3 卷积操作2.3.1 填充&#xff08;padding&#xff09;2.3.2 卷积块2.3.3 池化2.3.4 Softmax 2.4 完整CNN2.5 训练改进 三、经典CNN模型介绍四、CNN模型的…