ListNode相关

目录

2. 链表相关题目

2.1 合并两个有序链表(简单):递归

2.2 删除排序链表中的重复元素(简单):一次遍历

2.3 两链表相加(中等):递归

2.4 删除链表倒数第N个节点(中等):倒数第N个元素是遍历的第L-N+1个元素

2.5 两两交换链表中的节点(中等):递归

2.6 旋转链表(中等):链表成环后断开

2.7 判断是否存在环形链表(简单):Set集合 + 重复判断

2.8 环形链表若存在返回其入环的第一个节点(中等):Set集合 + 重复判断

2.9 LRU缓存(中等,也可以说困难):哈希表 + 双向链表

2.10 反转链表(简单):迭代

2.11 分隔链表(中等):

2.12 反转给定节点处的链表(中等):穿针引线

2.13 链表的总结

2. 链表相关题目

2.1 合并两个有序链表(简单):递归

题目:将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的

思想:将两个链表头部值中较小的一个节点和剩下元素的merge操作合并


总结:将链表头部单独拿出来先比较,比较完后确立了合并链表的头部,剩下的元素按照这种思路继续比较


代码:

class Solution {public ListNode mergeTwoLists(ListNode list1, ListNode list2) {//判断 list1 或者 list2 是否为空,为空则直接返回if(list1 == null){return list2;}else if(list2 == null){return list1;}//如果list1头部更小,则list1头部作为合并后链表的头部,然后继续合并其它链表else if(list1.val < list2.val){list1.next = mergeTwoLists(list1.next, list2);return list1;}//如果list2头部更小,则list2头部作为合并后链表的头部,然后继续合并其它链表else{list2.next = mergeTwoLists(list1,list2.next);return list2;}}
}

2.2 删除排序链表中的重复元素(简单):一次遍历

题目:给定一个已排序的链表的头 head删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表

思想:给定的链表是已经排好序的,重复的元素在链表中出现的位置是连续的;因此我们比较curr和curr.next,若相等则删除curr.next


总结:curr.next不为空时判断:curr和curr.next是否相等

  • 相等则删除curr.next;

  • 不相等则继续判断下一个节点


代码:

class Solution {public ListNode deleteDuplicates(ListNode head) {if (head == null) {return head;}
​ListNode cur = head;while (cur.next != null) {if (cur.val == cur.next.val) {cur.next = cur.next.next;} else {cur = cur.next;}}
​return head;}
}

2.3 两链表相加(中等):递归

题目:给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

思想:链表都是逆序存储数字的,因此链表中同一位置的数可以直接相加;且

  • sum = l1.val + l2.val + carry

  • 存入结果链表的是 % 10之后的值

  • 下一次的carry是 / 10之后的值


总结:使用递归法,将每一次的sum求出,然后十进制转换后存入结果链表


代码:

class Solution {public ListNode addTwoNumbers(ListNode l1, ListNode l2) {return add(l1, l2, 0);}
​public ListNode add(ListNode l1, ListNode l2, int carry){//如果l1、l2为空,且此时carry进位为0;则返回nullif(l1 == null && l2 == null && carry == 0){return null;}//sum = l1.val + l2.val + carryif(l1 != null){carry += l1.val;l1 = l1.next;}if(l2 != null){carry += l2.val;l2 = l2.next;}//将相加后的数 % 10,然后存入结果链表ListNode result = new ListNode(carry % 10);
​//递归:并将新的carry值传入,为下一次sum做准备result.next = add(l1, l2, carry / 10);
​return result;}
}

2.4 删除链表倒数第N个节点(中等):倒数第N个元素是遍历的第L-N+1个元素

题目:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点

思想:首先得到链表的长度L,从头节点开始遍历到第L - N + 1个节点时,该节点就是需要删除的节点;


总结:创建一个哑节点,用来指向链表的第一个节点;从头节点开始遍历1 --> L - N - 1,该节点的下一个节点即是待删除元素


代码:

class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {//创建一个哑节点,指向第一个元素ListNode dummy = new ListNode(0,head);
​//获取链表长度int length = getLength(head);
​//将哑节点作为当前元素ListNode curr = dummy;
​//获得倒数第N个节点的前一个结点:从i = 1 遍历到l - n + 1之前,第l - n + 1个节点就是该节点for(int i = 1; i < length - n + 1; i++){//每遍历一次,都将下一个节点值赋给该节点curr = curr.next;}
​//遍历完后,下一个节点值就是待删除节点值curr.next = curr.next.next;
​ListNode result = dummy.next;return  result;
​}
​public int getLength(ListNode head){int length = 0;while(head != null){length++;head = head.next;}return length;}
}

2.5 两两交换链表中的节点(中等):递归

题目:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题

思想:首先交换头节点和第二个节点的位置,然后递归的实现第三个节点、第四个节点、、、的交换;结束条件是链表中没有节点或者只剩下一个节点

  • 原始链表的头节点head:新链表的第二个节点

  • 原始链表的第二个节点:新链表的头节点newhead

  • 原始链表其他节点的头节点:newhead

  • 原始链表其他节点交换后是放在原始链表头部节点(此时是新链表的第二个节点)的后面的


总结:重点是交换时的顺序:

  • 先找到新链表的头节点

  • 然后根据新链表的头节点找到该节点在原始链表中的下一个节点来递归

  • 最后将原始节点的头节点作为新链表的第二个节点


代码:

class Solution {public ListNode swapPairs(ListNode head) {if(head == null || head.next == null){return head;}
​//原始链表头部的下一个节点就是新链表的头节点ListNode newHead = head.next;//这两行的顺序不能变化,因为此时是对原始链表的第三个节点进行的交换,若先将head赋值给newHead.next就没有了意义//新链表头节点在原始链表中的下一个节点(第三个节点)就是head的下一个节点head.next = swapPairs(newHead.next);
​//head是新链表节点的下一个节点newHead.next = head;
​return newHead;}
}

2.6 旋转链表(中等):链表成环后断开

题目:给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。

思想:若链表长度为n则:

  • 若向右移动的k >= n时,实际上移动k mod n

  • 新链表的最后一个节点是原链表的第 (n-1)-(k mod n)个节点

  • 将链表连接成环:将链表的尾节点连接上头节点,然后找到新链表的最后一个节点,将其断开即可


总结:创建一个哑节点,用来指向链表的第一个节点;从头节点开始遍历1 --> L - N - 1,该节点的下一个节点即是待删除元素


代码:

class Solution {public ListNode rotateRight(ListNode head, int k) {//1.若不移动或者根节点为空或者只有一个根节点if(k == 0 || head == null || head.next == null){return head;}
​//2.计算出链表长度(从1开始计数,此时即head一定有值)int n = 1;ListNode curr = head;while(curr.next != null){n++;curr = curr.next;}
​//3.新链表的最后一个节点是原链表的第n - k mod n个节点(从1开始计数)int add = n - k % n;//如果最后一个节点n - k mod n等于原链表的第n个节点,说明k为n的倍数,不需要旋转if(add == n){return head;}
​//4.将链表成环,然后找到新链表的最后一个节点(原链表的第n -(k mod n)个节点),将其断开curr.next = head; //链表成环
​//找到旋转后新链表的最后一个节点while(add > 0){curr = curr.next;add--;}//闭环中,新链表的最后一个节点的下一个节点就是新链表的头节点ListNode result = curr.next;
​//将环断开curr.next = null;
​return result;
​}
}

2.7 判断是否存在环形链表(简单):Set集合 + 重复判断

题目:给你一个链表的头节点 head ,判断链表中是否有环。如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况

思想:遍历所有节点,每遍历到一个节点,就存入哈希表中,并判断该节点是否被访问过(如果存在环形链表,则遍历的过程中会出现环形链表的节点会被访问两次,第一个被访问两次的节点就是环形链表的头节点位置),若访问过则说明是环形链表


总结:遍历链表,存入set集合,利用set集合的自身特性来判断


代码:

public class Solution {public boolean hasCycle(ListNode head) {//用一个HashSet集合存储每次遍历过程中链表中的节点Set<ListNode> set = new HashSet<>();
​while(head != null){//set是无需不可重复的,若set.add()返回false,说明已添加过该节点if(!set.add(head)){return true;}//节点后移head = head.next;}
​//遍历结束仍不存在相同节点,说明没有环形链表存在return false;}
}

2.8 环形链表若存在返回其入环的第一个节点(中等):Set集合 + 重复判断

题目:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos-1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况

思想:遍历所有节点,每遍历到一个节点,就存入哈希表中,并判断该节点是否被访问过(如果存在环形链表,则遍历的过程中会出现环形链表的节点会被访问两次,第一个被访问两次的节点就是环形链表的头节点位置),若访问过则说明是环形链表,且第一个访问到的重复访问节点就是入环的第一个节点


总结:遍历链表,存入set集合,利用set集合的自身特性来判断:如果存在则直接返回该节点,不存在则加入set中


代码:

public class Solution {public ListNode detectCycle(ListNode head) {//创建存储集合setSet<ListNode> set = new HashSet<>();ListNode curr = head;
​//遍历链表中的所有值while(curr != null){//判断是否存在重复节点:存在一定是第一个节点,直接返回,不存在则继续遍历下一个if(set.contains(curr)){return curr;}else{set.add(curr);}curr = curr.next;}//不存在返回nullreturn null;}
}

2.9 LRU缓存(中等,也可以说困难):哈希表 + 双向链表

题目:请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构

实现 LRUCache 类:

  • LRUCache(int capacity)正整数 作为容量 capacity 初始化 LRU 缓存

  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1

  • void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity则应该 逐出 最久未使用的关键字

函数 getput 必须以 O(1) 的平均时间复杂度运行。

思想:

LRU 缓存机制可以通过哈希表辅以双向链表实现,我们用一个哈希表和一个双向链表维护所有在缓存中的键值对。

  • 双向链表按照被使用的顺序存储了这些键值对,靠近头部的键值对是最近使用的,而靠近尾部的键值对是最久未使用的。

  • 哈希表即为普通的哈希映射(HashMap),通过缓存数据的键映射到其在双向链表中的位置。

这样以来,我们首先使用哈希表进行定位,找出缓存项在双向链表中的位置,随后将其移动到双向链表的头部,即可在 O(1)O(1)O(1) 的时间内完成 get 或者 put 操作。具体的方法如下:

  • 对于get 操作,首先判断 key 是否存在:

    • 如果 key不存在,则返回 −1

    • 如果key 存在,则key 对应的节点是最近被使用的节点。通过哈希表定位到该节点在双向链表中的位置,并将其移动到双向链表的头部,最后返回该节点的值。

  • 对于put操作,首先判断 key是否存在:

    • 如果 key 不存在,使用keyvalue 创建一个新的节点,在双向链表的头部添加该节点,并将 key和该节点添加进哈希表中。然后判断双向链表的节点数是否超出容量,如果超出容量,则删除双向链表的尾部节点,并删除哈希表中对应的项;

    • 如果key 存在,则与get操作类似,先通过哈希表定位,再将对应的节点的值更新为 value,并将该节点移到双向链表的头部。


总结:遍历链表,存入set集合,利用set集合的自身特性来判断:如果存在则直接返回该节点,不存在则加入set中


代码:

class LRUCache {class MyLinkedNode{int key;int value;MyLinkedNode prev;MyLinkedNode next;public MyLinkedNode(){}public MyLinkedNode(int key,int value){this.key = key;this.value = value;}}//需要使用哈希表和双向链表需要自己实现来实现//哈希表用来快速定位缓存中的元素所在位置,从而方便的get与put;哈希表中存储索引值和双向链表值,链表有key及valueprivate Map<Integer,MyLinkedNode> cache = new HashMap<>();
​//记录链表长度private int size;//记录LRU容量private int capacity;//定义两个哑节点用来指向链表的头尾节点private MyLinkedNode head;private MyLinkedNode tail;
​//创建时:定义LRU的size与capacity;并创建头尾伪节点public LRUCache(int capacity) {this.size = size;this.capacity = capacity;//构建头尾指针head = new MyLinkedNode();tail = new MyLinkedNode();head.next = tail;tail.prev = head;}//get时:先判断Map是否存在该节点,若不存在返回-1;若存在则将其展示,并把它移动到双向链表的头部public int get(int key) {MyLinkedNode node = cache.get(key);if(node == null){return -1;}//将节点移动到双向链表的头部moveToHead(node);return node.value;}//put时:先判断Map中是否存在该节点,若存在则直接改变value,并将其移动到头部;//若不存在,则将其添加到哈希表和链表头部,并判断当链表长度size>LRU容量则将链表尾部节点删除public void put(int key, int value) {MyLinkedNode node = cache.get(key);if(node != null){//存在该节点则改变其value值node.value = value;moveToHead(node);}else{//将节点添加到链表和哈希表中,然后移动到链表头部MyLinkedNode newNode = new MyLinkedNode(key,value);cache.put(key,newNode);addToHead(newNode);size++;
​//判断是否超出容量:超出则在链表和哈希表中删除尾部节点if(size > capacity){MyLinkedNode tail = removeTail();cache.remove(tail.key);size--;}}}
​public void moveToHead(MyLinkedNode node){removeNode(node);addToHead(node);}
​//删除节点public void removeNode(MyLinkedNode node){node.prev.next = node.next;node.next.prev = node.prev;}
​//将节点添加到头部public void addToHead(MyLinkedNode node){node.prev = head;node.next = head.next;head.next.prev = node;head.next = node;}
​//删除尾部节点:拿到尾部节点,然后删除并返回删除后的节点public MyLinkedNode removeTail(){MyLinkedNode result = tail.prev;removeNode(result);return result;}
}

2.10 反转链表(简单):迭代

题目:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

思想:遍历链表,让遍历的节点的next指向前一个节点;注意:头节点没有引用前一个节点,因此要先存储一个前节点为null;并且要创建一个新节点,最终返回新的链表头部


总结:在进行反转时,需要变化的量有:节点值(为了迭代变为下一个节点值)、节点的下一个值(指向节点的上一个值)、节点的上一个值(为了迭代每次变为上一次迭代的当前节点值)


代码:

class Solution {public ListNode reverseList(ListNode head) {//创建一个空节点,用来指向nullListNode prev = null;//创建一个临时节点ListNode curr = head;
​//如果当前节点不为空:反转链表时://当前节点的下一个节点先存下来,然后将让当前节点的next指向前一个结点;//每轮循环中,前一个节点都是上一次循环的当前节点while(curr != null){ListNode next = curr.next;curr.next = prev;prev = curr;curr = next;}return prev;}
}

2.11 分隔链表(中等):

题目:给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 保留 两个分区中每个节点的初始相对位置

思想:维护两个链表samll和large,按照顺序分别存储小于x的节点值和大于等于x的节点值,最后将前一个链表的尾节点指向钱一个链表的头节点即可


总结:为防止头节点的边界条件(需要对头节点进行特殊判断,为了防止这个特殊判断),设置一个哑节点指向头节点


代码:

class Solution {public ListNode partition(ListNode head, int x) {//创建两个链表,分别用来存储小于x和大于等于x的节点ListNode small = new ListNode(0);ListNode large = new ListNode(0);
​//创建两个哑节点,此时哑节点并不指向新链表的头节点,而是等于头节点(后面讲头节点改为新添加的节点)ListNode smallHead = small;ListNode largeHead = large;
​//遍历当前链表值,根据与x的比较存入两个新链表while(head != null){//将小于x的节点存入small链表,并更改头部if(head.val < x){small.next = head;small = small.next;}//将大于等于x的节点存入large链表,并更改头部else{large.next = head;large = large.next;}head = head.next;}//将samll的尾节点指向large的头节点small.next = largeHead.next;//将large的尾节点指向nullarge.next = null;return smallHead.next;}
}

2.12 反转给定节点处的链表(中等):穿针引线

题目:给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 保留 两个分区中每个节点的初始相对位置

思想:先将需要反转的位置进行反转得到反转后链表,然后将left的前一个节点prev指向反转后的链表的头部,将反转后链表的尾部指向right的next节点即可


总结:只要是头节点可能发生变化的情况,都设置一个哑节点,用来处理这种特殊情况;


代码:

class Solution {public ListNode reverseBetween(ListNode head, int left, int right) {//创建一个哑节点,指向链表头部ListNode dummy = new ListNode();dummy.next = head;
​//一开始记left的前一个节点为哑节点,然后从哑节点出发走left - 1步,找到left节点的前一个节点prevListNode prev = dummy;for(int i = 0; i < left - 1; i++){prev = prev.next;}
​//从prev出发,走right - left + 1 步,找到right节点ListNode rightNode = prev;for(int i = 0; i < right - left + 1; i++){rightNode = rightNode.next;}
​//先将prev的下一个节点left和rightNode的下一个节点next保存起来,然后将链表截断ListNode leftNode = prev.next;ListNode next = rightNode.next;prev.next = null;rightNode.next = null;
​//将截断后的元素进行反转reverseListNode(leftNode);
​//让prev节点指向新链表的头节点(rightNode),新链表的尾节点(leftNode)指向保存下的next节点prev.next = rightNode;leftNode.next = next;return dummy.next;
​}
​public void reverseListNode(ListNode head){ListNode prev = null;ListNode curr = head;while(curr != null){ListNode next = curr.next;curr.next = prev;prev = curr;curr = next;}}
}

2.13 链表的总结

链表主要注意几点:

  • 对于头节点可能发生变化的情况,可以设置一个哑节点,用来指向头节点,从而减少对头节点特殊情况的判断;同理,特殊情况也可以构造尾节点的哑节点

  • 链表中的指针很神奇,能够控制链表的指向,若指向null或者指向头部就能轻松改变一个链表的状态,使之断开或者成环,谨慎改变指针的指向,能够解决很多问题

  • 在树结构中很多时候可以使用递归,链表中也一样,因为都是一样的结构,构造好递归函数就能省去很多时间

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

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

相关文章

MySQL 索引为什么使用 B+ 树,而不使用红黑树 / B 树 ?

面试官问 &#xff1a;索引为什么使用 B 树&#xff0c;而不使用 B 树&#xff0c;不使用红黑树呢 首先 B 树和 B 树 都是多叉搜索树&#xff0c;然后我们先来观察一下 B 树和 B 树的数据结构&#xff1a; B 树的数据结构实现 >> B 树的数据结构实现 >> 【B 树相…

2023国赛数学建模思路 - 案例:FPTree-频繁模式树算法

文章目录 算法介绍FP树表示法构建FP树实现代码 建模资料 ## 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法&#xff0c;就是频繁模式树算法&#xff0c…

代码随想录算法训练营day39 | 62. 不同路径,63. 不同路径 II

目录 62. 不同路径 63. 不同路径 II 62. 不同路径 类型&#xff1a;动态规划 难度&#xff1a;medium 思路&#xff1a; 应用二维数组的动态规划&#xff0c;到达某个方格的方法数目&#xff0c;为这个方格的上一个方格和左一个方格的方法数目和。 需要先初始化第一行和第一…

08.SpringBoot请求相应

文章目录 1 请求1.1 Postman1.2 简单参数1.2.1 原始方式1.2.2 SpringBoot方式1.2.3 参数名不一致 1.3 实体参数1.3.1 简单实体对象1.3.2 复杂实体对象 1.4 数组集合参数1.4.1 数组1.4.2 集合 1.5 日期参数1.6 JSON参数1.7 路径参数 2 响应2.1 ResponseBody注解2.2 统一响应结果…

GAN!生成对抗网络GAN全维度介绍与实战

目录 一、引言1.1 生成对抗网络简介1.2 应用领域概览1.3 GAN的重要性 二、理论基础2.1 生成对抗网络的工作原理2.1.1 生成器生成过程 2.1.2 判别器判别过程 2.1.3 训练过程训练代码示例 2.1.4 平衡与收敛 2.2 数学背景2.2.1 损失函数生成器损失判别器损失 2.2.2 优化方法优化代…

收集的一些比较好的git网址

1、民间故事 https://github.com/folkstory/lingqiu/blob/master/%E4%BC%A0%E8%AF%B4%E9%83%A8%E5%88%86/%E4%BA%BA%E7%89%A9%E4%BC%A0%E8%AF%B4/%E2%80%9C%E6%B5%B7%E5%BA%95%E6%8D%9E%E6%9C%88%E2%80%9D%E7%9A%84%E6%AD%A6%E4%B8%BE.md 2、童话故事 https://gutenberg.org/c…

12. Docker可视化工具

目录 1、前言 2、Docker UI 2.1、部署Docker UI 2.2、管理容器 3、Portainer 3.1、部署Portainer 3.2、管理容器 3.3、添加远程Docker 4、Shipyard 1、前言 Docker 提供了命令行工具来管理 Docker 的镜像和运行 Docker 的容器。我们也可以使用图形工具来管理 Docker。…

C# 观察者模式

一、概述 观察者模式是一种常用的设计模式&#xff0c;它属于行为型模式。在C#中&#xff0c;观察者模式通过定义一种一对多的依赖关系&#xff0c;使得当一个对象的状态发生变化时&#xff0c;所有依赖于它的对象都会得到通知并自动更新。这种模式可以实现松耦合&#xff0c;…

Ribbon负载均衡

Ribbon与Eureka的关系 Eureka的服务拉取与负载均衡都是由Ribbon来实现的。 当服务发送http://userservice/user/xxxhtt://userservice/user/xxx请求时&#xff0c;是无法到达userservice服务的&#xff0c;会通过Ribbon会把这个请求拦截下来&#xff0c;通过Eureka-server转换…

常见排序集锦-C语言实现数据结构

目录 排序的概念 常见排序集锦 1.直接插入排序 2.希尔排序 3.选择排序 4.堆排序 5.冒泡排序 6.快速排序 hoare 挖坑法 前后指针法 非递归 7.归并排序 非递归 排序实现接口 算法复杂度与稳定性分析 排序的概念 排序 &#xff1a;所谓排序&#xff0c;就是使一串记录&#…

排名前 6 位的数学编程语言

0 说明 任何对数学感兴趣或计划学习数学的人&#xff0c;都应该至少对编程语言有一定的流利程度。您不仅会更有就业能力&#xff0c;还可以更深入地理解和探索数学。那么你应该学习什么语言呢&#xff1f; 1.python 对于任何正在学习数学的人来说&#xff0c;Python都是一门很棒…

【Linux从入门到精通】动静态库的原理与制作详解

本篇文章主要是围绕动静态库的原理与制作进行展开讲解的。其中涉及到了inode的概念引入和软硬连接的讲解。会结合实际操作对这些抽象的概念进行解释&#xff0c;希望会对你有所帮助。 文章目录 一、inode 概念 二、软硬链接 2、1 软连接 2、2 硬链接 三、动静态库概念 3、1 静态…

编织梦想:SpringBoot AOP 教程与自定义日志切面完整实战

什么是 AOP AOP 是指通过预编译方式和运行期动态代理的方式&#xff0c;在不修改源代码的情况下对程序进行功能增强的一种技术。AOP 不是面向对象编程&#xff08;OOP&#xff09;的替代品&#xff0c;而是 OOP 的补充和扩展。它是一个新的维度&#xff0c;用来表达横切问题&a…

常见前端基础面试题(HTML,CSS,JS)(三)

JS 中如何进行数据类型的转换&#xff1f; 类型转换可以分为两种&#xff0c;隐性转换和显性转换 显性转换 主要分为三大类&#xff1a;数值类型、字符串类型、布尔类型 三大类的原始类型值的转换规则我就不一一列举了 数值类型&#xff08;引用类型转换&#xff09; Numbe…

设计模式之状态模式(State)的C++实现

1、状态模式的提出 在组件功能开发过程中&#xff0c;某些对象的状态经常面临变化&#xff0c;不同的状态&#xff0c;其对象的操作行为不同。比如根据状态写的if else条件情况&#xff0c;且这种条件变化是经常变化的&#xff0c;这样的代码不易维护。可以使用状态模式解决这…

如何在window下cmd窗口执行linux指令?

1.Git&#xff1a;https://git-scm.com/downloads(官网地址) 2.根据自己的实际路径,添加两个环境变量 3.重启电脑

删除有序链表中重复的元素-II(链表)

乌&#xff01;蒙&#xff01;山&#xff01;连&#xff01;着&#xff01;山&#xff01;外&#xff01;山&#xff01; 题目&#xff1a; 思路&#xff1a; 双指针&#xff0c;slow和fast&#xff0c;并且增加标记flag初始为1。 如果slow指向节点值等于fast指向节点值&…

Servlet 初步学习

文章目录 Servlet1 简介2 快速入门3 执行流程4 生命周期5 方法介绍6 体系结构7 urlPattern配置8 XML配置 Servlet 1 简介 Servlet是JavaWeb最为核心的内容&#xff0c;它是Java提供的一门 动态 web资源开发技术。 使用Servlet就可以实现&#xff0c;根据不同的登录用户在页面…

什么是cURL?

cURL无处不在。它几乎隐藏在所有设备中&#xff0c;例如汽车&#xff0c;蓝光播放器等。它通过互联网协议传输任意类型数据。 在本文中&#xff0c;我们将揭开cURL神秘命令行工具的面纱&#xff0c;解释它是如何成为一种通用代码的&#xff0c;并举例说明其用法。 cURL是什么意…

PHP海外代购管理系统mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP 海外代购管理系统是一套完善的web设计系统&#xff0c;对理解php编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 代码下载 https://download.csdn.net/download/qq_41221322/88229435 论文 https://…