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;则返回null
        if(l1 == null && l2 == null && carry == 0){
            return null;
        }
        //sum = l1.val + l2.val + carry
        if(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) {
        //创建存储集合set
        Set<ListNode> set = new HashSet<>();
        ListNode curr = head;
​
        //遍历链表中的所有值
        while(curr != null){
            //判断是否存在重复节点:存在一定是第一个节点,直接返回,不存在则继续遍历下一个
            if(set.contains(curr)){
                return curr;
            }else{
                set.add(curr);
            }
            curr = curr.next;
        }
        //不存在返回null
        return 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及value
    private 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) {
        //创建一个空节点,用来指向null
        ListNode 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的尾节点指向nul
        large.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节点的前一个节点prev
        ListNode 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或者指向头部就能轻松改变一个链表的状态,使之断开或者成环,谨慎改变指针的指向,能够解决很多问题

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何在网页下载腾讯视频为本地MP4格式

1.打开腾讯视频官网地址 腾讯视频 2.搜索你想要下载的视频 3. 点击分享,选择复制通用代码 <iframe frameborder="0" src="ht

新生录取信息收集

随着高等教育的普及&#xff0c;每年都有大量的学生被大学录取。对于学校来说&#xff0c;新生录取确认和信息收集是一项重要的工作&#xff0c;但也是一项繁琐而耗时的任务。然而&#xff0c;通过合理的规划和利用现代科技手段&#xff0c;我们可以轻松搞定这一工作&#xff0…

在mac下,使用Docker安装达梦数据库

前言&#xff1a;因为业务需要安装达梦数据库 获取官网下载tar包&#xff08;达梦官网的下载页面https://www.dameng.com/list_103.html&#xff09;&#xff0c;或者通过命令 一、下载tar包 命令下载&#xff1a;wget -O dm8_docker.tar -c https://download.dameng.com/eco/…

自定义mybatis拦截器,在若依springboot项目中不起作用的原因

自定义mybatis拦截器&#xff0c;在若依springboot项目中不起作用的原因 找到 MyBatisConfig 配置类&#xff0c;引入自定义配置 在sqlSessionFactory中添加自定义拦截器&#xff0c;就可以正常使用了 package com.lingxu.framework.config;import com.lingxu.common.core.…

uniapp使用uni.chooseLocation()打开地图选择位置

使用uni.chooseLocation()打开地址选择位置&#xff1a; 在Uniapp源码视图进行设置 添加这个属性&#xff1a;"requiredPrivateInfos":["chooseLocation"] ​ </template><view class"location_box"><view class"locatio…

基于CentOS7.9安装部署docker(简洁版)

安装部署 1基于官方脚本安装&#xff08;不推荐 不能自行选择版本&#xff09; 官方文档&#xff1a;https://docs.docker.com/engine/install/centos/ 2 使用yum安装 阿里云文档&#xff1a;docker-ce镜像_docker-ce下载地址_docker-ce安装教程-阿里巴巴开源镜像站 # ste…

(二)k8s实战-深入Pod详解

一、配置文件详解 创建Pod nginx样例 apiVersion: v1 # api文档版本 kind: Pod # 资源对象类型&#xff0c;Pod, Deployment,StatefulSet metadata: # Pod相关的元数据&#xff0c;用于描述Pod的数据name: nginx-demo # Pod的名称labels: # 定义Pod的标签type: app # 自定义l…

AVL——平衡搜索树

✅<1>主页&#xff1a;我的代码爱吃辣&#x1f4c3;<2>知识讲解&#xff1a;数据结构——AVL树☂️<3>开发环境&#xff1a;Visual Studio 2022&#x1f4ac;<4>前言&#xff1a;AVL树是对二叉搜索树的严格高度控制&#xff0c;所以AVL树的搜索效率很高…

数据库索引优化策略与性能提升实践

文章目录 什么是数据库索引&#xff1f;为什么需要数据库索引优化&#xff1f;数据库索引优化策略实践案例&#xff1a;索引优化带来的性能提升索引优化规则1. 前导模糊查询不适用索引2. 使用IN优于UNION和OR3. 负向条件查询不适用索引4. 联合索引最左前缀原则5. 范围条件查询右…

【TS】typescript基础知识

一、类型注解 : number就是类型注解&#xff0c;为变量添加类型约束的方式&#xff0c;约定了什么类型&#xff0c;就只能给变量赋什么类型的值 let age: number 18二、变量命名规则和规范 命名规则&#xff1a;变量名称只能出现数字&#xff0c;字母&#xff0c;下划线(_)…

python rtsp 硬件解码 二

上次使用了python的opencv模块 述说了使用PyNvCodec 模块&#xff0c;这个模块本身并没有rtsp的读写&#xff0c;那么读写rtsp是可以使用很多方法的&#xff0c;我们为了输出到pytorch直接使用AI程序&#xff0c;简化rtsp 输入&#xff0c;可以直接使用ffmpeg的子进程 方法一 …

DNQ算法原理(Deep Q Network)

1.强化学习概念 学习系统没有像很多其它形式的机器学习方法一样被告知应该做出什么行为 必须在尝试了之后才能发现哪些行为会导致奖励的最大化 当前的行为可能不仅仅会影响即时奖励&#xff0c;还会影响下一步的奖励以及后续的所有奖励 每一个动作(action)都能影响代理将来的…

手机无人直播软件,有哪些优势?

近年来&#xff0c;随着手机直播的流行和直播带货的市场越来越大&#xff0c;手机无人直播软件成为许多商家开播带货的首选。在这个领域里&#xff0c;声音人无人直播系统以其独特的优势&#xff0c;成为市场上备受瞩目的产品。接下来&#xff0c;我们将探讨手机无人直播软件给…

OpenCV中QR二维码的生成与识别(CIS摄像头解析)

1、QR概述 QR(Quick Response)属于二维条码的一种&#xff0c;意思是快速响应的意思。QR码不仅信息容量大、可靠性高、成本低&#xff0c;还可表示汉字及图像等多种文字信息、其保密防伪性强而且使用非常方便。更重要的是QR码这项技术是开源的&#xff0c;在移动支付、电影票、…

Elasticsearch Split和shrink API

背景&#xff1a; 尝试解决如下问题&#xff1a;单分片存在过多文档&#xff0c;超过lucene限制 分析 1.一般为日志数据或者OLAP数据&#xff0c;直接删除索引重建 2.尝试保留索引&#xff0c;生成新索引 - 数据写入新索引&#xff0c;查询时候包含 old_index,new_index 3.…

内容分发网络CDN与应用程序交付网络ADN之间的异同

当您想要提高网站性能时&#xff0c;需要考虑许多不同的配置和设施&#xff0c;CDN和ADN是我们常遇见的几种选项之一。“CDN”指“内容分发网络”&#xff0c;而“ADN”指“应用程序交付网络”&#xff0c;但他们两者很容易被混淆&#xff0c;虽然它们的功能和作用都有较大差异…

使用多个神经网络进行细菌分类(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

vellum (Discovering Houdini VellumⅡ柔体系统)学习笔记

视频地址&#xff1a; https://www.bilibili.com/video/BV1ve411u7nE?p3&spm_id_frompageDriver&vd_source044ee2998086c02fedb124921a28c963&#xff08;搬运&#xff09; 个人笔记如有错误欢迎指正&#xff1b;希望可以节省你的学习时间 ~享受艺术 干杯&#x1f37b…

[Mac软件]AutoCAD 2024 for Mac(cad2024) v2024.3.61.182中文版支持M1/M2/intel

下载地址&#xff1a;前往黑果魏叔官网 AutoCAD是一款计算机辅助设计&#xff08;CAD&#xff09;软件&#xff0c;目前已经成为全球最受欢迎的CAD软件之一。它可以在二维和三维空间中创建精确的技术绘图&#xff0c;并且可以应用于各种行业&#xff0c;如建筑、土木工程、机械…

【操作系统】24王道考研笔记——第三章 内存管理

第三章 内存管理 一、内存管理概念 1.基本概念 2.覆盖与交换 覆盖技术&#xff1a; 交换技术&#xff1a; 总结&#xff1a; 3.连续分配管理方式 单一连续分配 固定分区分配 动态分区分配 动态分区分配算法&#xff1a; 总结&#xff1a; 4.基本分页存储管理 定义&#xf…