代码随想录--链表相关题目整理

news2024/9/25 10:33:08

代码随想录–链表相关题目整理

1. LeetCode203 移除链表中指定元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

img

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

解题思路1: 采用虚拟头结点的方式删除结点。这种的好处是因为在链表中删除结点我们需要找到被删除结点的前一个结点才可以。如果要删除链表中第一个元素,它没有前驱结点,因此删除的方式可能会不统一。所以我们在链表前面在添加一个虚拟结点。这样删除第一个元素的操作和删除其他元素的操作就统一了。

203_链表删除元素6

public ListNode removeElements(ListNode head, int val) {
  // 如果链表为空
    if (head == null) return null;

    // 创建虚拟头结点
    ListNode pHead = new ListNode(0);
    pHead.next = head;
    ListNode cur = head;
    ListNode pre = pHead;

    while (cur != null) {
        if (cur.val == val) {
            pre.next = cur.next;
        } else {
            pre = cur;
        }
        cur = cur.next;
    }
    return pHead.next;
}

解题思路2: 不设置虚拟头结点。如果不设置虚拟头结点,那么当头结点的值和val相等的时候,我们只需要将头结点向后移动一个即可。对于其他的结点,和上面的操作是一样的。

public ListNode removeElements(ListNode head, int val) {
    if (head == null) return null;
    // 处理头结点
    while (head != null && head.val == val) head = head.next;
    ListNode cur = head;
    while (cur != null && cur.next != null) {
      	// 要删除的元素始终是cur的下一个元素
        if (cur.next.val == val) {
            cur.next = cur.next.next;
        } else {
          	cur = cur.next;
        }
    }
    return head;
}

总结:这两种方法的目的实际上都是让一个指针指向当前判断是否需要删除的元素的上一个结点。

  • 在使用虚拟头结点的方法中,我们是虚拟了一个头结点,让链表中所有的元素都拥有前驱结点。其中cur指向的就是要判断是否删除的结点,pre指向的是当前要判断是否删除元素的前驱结点。
  • 在不使用头结点的方法中。是需要先判断头结点是不是要删除,如果要删除就直接将头指针向后移动。如果不是头结点,而此时cur正好指向头结点,所以我们在判断条件的时候判断的是cur.next.val == val,而不是cur.val == val,所以说在这个方法中cur指向的是当前要判断是否删除元素的前驱结点。

2.LeetCode707 设计链表

设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:

  • get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
  • addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
  • addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
  • addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
  • deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

这道题相对简单,主要需要注意的是,这道题中链表的索引是从0开始的。

class ListNode {
    int val;
    ListNode next;

    public ListNode(int val) {
        this.val = val;
        this.next = null;
    }
}

class MyLinkedList {
    int size;
    ListNode head;

    public MyLinkedList() {
        this.size = 0;
        this.head = new ListNode(0);
    }

    /*
    获取第index个位置的值
     */
    public int get(int index) {
        // 判断index是否满足条件
        if (index >= size || index < 0) {
            return -1;
        }
        ListNode cur = head;
        for (int i = 0; i <= index; i++) {
            cur = cur.next;
        }
        return cur.val;
    }


    public void addAtHead(int val) {
        // 先创建出这个结点
        ListNode node = new ListNode(val);
        node.next = head.next;
        head.next = node;
        this.size++;
    }

    public void addAtTail(int val) {
        ListNode node = new ListNode(val);
        // 遍历到最后一个结点位置
        ListNode cur = head;
        while (cur.next != null) {
            cur = cur.next;
        }
        // 此时cur指向最后一个元素
        cur.next = node;
        this.size++;
    }

    public void addAtIndex(int index, int val) {
        if (index == size) {
            addAtTail(val);
            return;
        }
        if (index < 0) {
            addAtHead(val);
            return;
        }
        ListNode cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        ListNode node = new ListNode(val);
        node.next = cur.next;
        cur.next = node;
        this.size++;
    }

    public void deleteAtIndex(int index) {
        if (index >= size || index < 0) {
            return;
        }
        ListNode cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        // 此时cur指向的就是要删除的元素的前一个元素
        cur.next = cur.next.next;
        this.size--;
    }
}

要删除链表中的某一个元素,一定要找到这个元素的前驱元素

3. LeetCode206 反转链表

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

示例 1:img

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

解题思路:使用两个指针来做

反转链表实际上就是将每一个链表的next指针指向前驱结点。因此可以定义两个指针,一个是pre指向当前遍历元素的前驱结点,初始值为null,因为第一个结点反转后,变成最后一个结点,而最后一个结点的next正好是null。cur指向当前正在遍历的结点

在循环中执行下面的操作

  • 使用temp保存当前遍历元素的next指针
  • 然后将当前元素的next指针赋值为pre
  • 然后将per=cur
  • 最后cur=cur.next

注意:这里一定要将cur.next先使用temp保存起来,否则因为在第二步cur.next值已经被修改了,再次访问cur=cur.next就不对了。

public ListNode reverseList(ListNode head) {
    // 如果链表为空,则返回空
    if (head == null) return null;
    // 如果链表中只有只有一个元素,则直接返回
    if (head.next == null) return head;

    ListNode pre = null, cur = head;
    ListNode temp;
    while (cur != null) {
        temp = cur.next;
        cur.next = pre;
        pre = cur;
        cur = temp;
    }
    return pre;
}

解题思路2: 只要是反转顺序的都可以考虑用栈来做。

  • 首先将所有的结点入栈
  • 然后创建一个虚拟虚拟头结点,让cur指向虚拟头结点。然后开始循环出栈,每出来一个元素,就把它加入到以虚拟头结点为头结点的链表当中,最后返回即可。
public ListNode reverseList(ListNode head) {
    // 如果链表为空,则返回空
    if (head == null) return null;
    // 如果链表中只有只有一个元素,则直接返回
    if (head.next == null) return head;

    // 创建栈 每一个结点都入栈
    Stack<ListNode> stack = new Stack<>();
    ListNode cur = head;
    while (cur != null) {
        stack.push(cur);
        cur = cur.next;
    }

    // 创建一个虚拟头结点
    ListNode pHead = new ListNode(0);
    cur = pHead;
    while (!stack.isEmpty()) {
        ListNode node = stack.pop();
        cur.next = node;
        cur = cur.next;
    }
    // 最后一个元素的next要赋值为空
    cur.next = null;

    return pHead.next;

}

采用这种方法需要注意一点。就是当整个出栈循环结束以后,cur正好指向原来链表的第一个结点,而此时结点1中的next指向的是结点2,因此最后还需要cur.next = null

image-20230117202045647

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

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

img

解题思路

  • 首先判断链表是否为空和链表中是否只有一个元素的条件
  • 创建一个指针cur指向头结点,然后依次交换cur和cur的下一个元素的值。
  • 交换完成后,cur向后移动两个单位
  • 循环的终止条件是cur != null && cur.next != null,也就是只有当cur和cur的下一个元素都不为空的时候,才继续交换。
public ListNode swapPairs(ListNode head) {
    // 如果链表为空
    if (head == null) return null;
    // 如果链表只有一个元素 则直接返回这个元素
    if (head.next == null) return head;
    ListNode cur = head;
    while (cur != null && cur.next != null) {
        // 交换cur和cur的下一个结点
        swap(cur, cur.next);
        cur = cur.next.next;
    }
    return head;
}

private void swap(ListNode a, ListNode b) {
    int temp = a.val;
    a.val = b.val;
    b.val = temp;
}

上边那个代码是交换的数值,虽然AC了但是不符合题意。

public ListNode swapPairs(ListNode head) {
    // 如果链表为空
    if (head == null) return null;
    // 如果链表只有一个元素 则直接返回这个元素
    if (head.next == null) return head;

    // 创建虚拟头结点
    ListNode pHead = new ListNode(0);
    pHead.next = head;
    ListNode cur = pHead;

    while (cur.next != null && cur.next.next != null) {
        ListNode temp = cur.next;
        ListNode temp1 = cur.next.next.next;
        cur.next = cur.next.next;
        cur.next.next = temp;
        temp.next = temp1;
        cur = temp;
    }

    return pHead.next;
}

画图示意如下:

image-20230117210504565

5. LeetCode19 删除链表的倒数第N个结点

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

示例 1:

img

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

解题思路: 使用快慢指针,快指针先走N步,然后快慢指针同时走,最终当快指针指向链表中最后一个元素时,慢指针正好指向倒数N个结点的前一个结点。然后进行删除即可。

这里需要注意n给的值可能不合法的情况。

public ListNode removeNthFromEnd(ListNode head, int n) {
    if (head == null) return null;
    // 定义快慢指针
    ListNode pHead = new ListNode(0);
    pHead.next = head;
    ListNode slow = pHead, fast = pHead;
    for (int i = 1; i <= n; i++) {
        fast = fast.next;
    }
    // n不合法
    if (fast == null) return null;
		
    while (fast.next != null) {
        fast = fast.next;
        slow = slow.next;
    }
    slow.next = slow.next.next;
    return pHead.next;
}

image-20230117215346273

和这个题类似的,找到链表中倒数第K个元素。

public ListNode FindKthToTail(ListNode pHead, int k) {
    // write code here
    ListNode fast = pHead;
    ListNode slow = pHead;

    for (int i = 0; i < k; i++) {
        // 需要注意的是 如果链表长度小于k的情况
        // 通过下面的if判断判断了链表为空的情况和链表长度小于k的情况
        if (fast == null)
            return null;
        fast = fast.next;
    }
    while (fast != null) {
        slow = slow.next;
        fast = fast.next;
    }
    return slow;
}

6. 面试题 02.07. 链表相交

输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:

img

可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点。

解题思路:分别建立两个指针,从两个链表开始遍历,如果有公共结点,那么两个指针第一次相遇的时候就是第一个公共结点。

当链表1遍历到头结点后,将链表1的下一个指针指向链表2的头结点。

同理,当链表2遍历到头结点后,将链表1的下一个指针指向链表1的头结点。

36

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
  ListNode cur1 = headA;
  ListNode cur2 = headB;

  while (cur1 != cur2) {

      if (cur1 == null) {
          cur1 = headB;
          continue;
      }

      if (cur2 == null) {
          cur2 = headA;
          continue;
      }

      cur1 = cur1.next;
      cur2 = cur2.next;
  }
  return cur2;
}

有人可能会有疑问,如果链表中没有公共结点,则while会不会是死循环。实际上不会,因为如果没有公共结点,那么最终cur1 == cur2 == null

解题思路2: 利用双指针。

img

通过上面的图可以看到,如果我们使用两个指针同时指向两个链表的头结点。在两个链表长度相等的情况下,可以一一遍历。但是现在的情况是两个链表长度不相同,因此可以让长的链表指针先移动几位,和短链表的指针保持到同一个位置,然后两个指针同时遍历链表,并比较指向的元素是不是同一个即可。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
  ListNode curA = headA;
  ListNode curB = headB;
  int lenA = 0, lenB = 0;
  // 求两个链表的长度
  while (curA != null) {
      lenA++;
      curA = curA.next;
    }
  while (curB != null) {
      lenB++;
      curB = curB.next;
  }
  curA = headA;
  curB = headB;

  if (lenA > lenB) {
      int gap = lenA - lenB;
      for (int i = 0; i < gap; i++) {
          curA = curA.next;
      }
  } else {
      int gap = lenB - lenA;
      for (int i = 0; i < gap; i++) {
          curB = curB.next;
      }
  }
  // 目前两个指针指向的位置是一样的 然后开始同时向前移动,然后判断两个指针指向的元素是不是一样
  // 如果一样,则返回元素
  System.out.print(1);
  while (curA != null || curB != null) {
      if (curA == curB)
          return curA;
      curA = curA.next;
      curB = curB.next;
  }
    return null;
}

解题思路3:可以利用set集合,将链表1中所有元素都保存到set中,然后遍历链表2,每遍历一个元素,就去set中看一看是否包含,如果包含则直接返回。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    if (headA == null) return null;
    // 创建一个set集合,保存链表A中所有元素
    Set<ListNode> set = new HashSet<>();
    ListNode cur = headA;
    while (cur != null) {
        set.add(cur);
        cur = cur.next;
    }

    // 遍历链表B
    cur = headB;
    while (cur != null) {
        if (set.contains(cur))
            return cur;
        cur = cur.next;
    }
    return null;
}

7. Leetcode142 环形链表II

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

示例 1:

img

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

解题思路1: 这个方法很难想到,可以作为结论记录下来。

  • 首先定两个指针,一个快指针,一个满指针,都指向链表的头结点。快指针一次走两个元素,慢指针一次走一个元素。
  • 开始遍历,如果存在环,那么快慢指针一定会相遇。如果没有环,那么fast指针会率先指向null
  • 两个指针相遇后,再让满指针重新指向链表头结点,然后快慢指针同时一次移动一个单位。
  • 最后快慢指针再次相遇的时候,就是环中第一个结点位置。
public ListNode detectCycle(ListNode head) {
    if (head == null || head.next == null) return null;

    // 定义快慢指针
    ListNode fast = head, slow = head;

    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
        if (fast == slow)
            break;
    }
    // 不存在环
    if (fast == null || fast.next == null) return null;

    slow = head;

    while (slow != fast) {
        slow =slow.next;
        fast =fast.next;
    }
    return slow;
}

如果单纯判断链表中是否有环,不需要返回环的入口结点,那么直接判断快慢指针是否会相遇即可。相遇则一定有环,否则就没有环。

解题思路2: 利用set集合。遍历链表,将元素存入set,在存入之间判断当前元素是否已经存在于set中,如果存在则直接返回该元素即可。

public ListNode detectCycle(ListNode head) {
    if (head == null || head.next == null) return null;

    Set<ListNode> set = new HashSet<>();
    ListNode cur= head;
    while (cur != null) {
        if (set.contains(cur))
            return cur;
        set.add(cur);
        cur = cur.next;
    }
    return null;
}

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

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

相关文章

如何免费创建PDF文档?创建PDF文档的9个工具

PDF 创建器是一种程序、应用程序或软件&#xff0c;旨在制作或创建 PDF 文档。自可移植文档格式 ( PDF ) 出现以来&#xff0c;文档共享和存储变得更加容易。PDF 还使文件交换更加安全。由于 PDF 格式的众多优点&#xff0c;PDF 文档被全球范围内的人们广泛使用。因此&#xff…

Java数据结构(List介绍和顺序表)

1、List的介绍 在集合框架中&#xff0c;List是一个接口&#xff0c;继承自Collection&#xff08;也是一个接口&#xff09;。 Collection也是一个接口&#xff0c;该接口中规范了后序容器中常用的一些方法&#xff0c;Iterable也是一个接口&#xff0c;表示实现该接口的类是可…

第一天总结 之 用户管理界面的实现 之 修改操作 的实现

修改操作 首先 明确 修改操作的前提是 先在页面显示修改前的数据 然后对其进行修改 之后点击提交在页面显示修改前的数据 方法一&#xff1a; 带着数据直接跳转 到添加页面 即在跳转的url后 直接通过&#xff1f;携带数据跳转 缺点&#xff1a; &#xff01;&#xff01;…

6、Ubuntu20的JDKMySQLtomcatRedis安装

安装JDK 这里以安装版本8为例 进入存放jdk目录创建目录 cd /usr/local mkdir jdk cd jdk 把下好的jdk8压缩包拖拽到Ubuntu连接用户下 移动jdk包文件 mv /home/starfish/jdk-8u351-linux-x64.tar.gz . 解压jdk tar -zxvf jdk-8u351-linux-x64.tar.gz cd jdk1.8.0_351/ p…

【C#】C#Process调用外部程序

前言 使用C#调用外部程序&#xff0c;一种是通过Process类&#xff0c;一种是通过命令行&#xff0c;本文主要说一下使用C#中的Process类调用外部程序的方式。 过程&#xff1a; 创建Process对象配置启动选项&#xff08;输入、输出等&#xff09;切换工作目录设置外部程序名…

Java——全排列

题目链接 leetcode在线oj题——全排列 题目描述 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 题目示例 输入&#xff1a;nums [1,2,3] 输出&#xff1a;[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]] …

Linux防火墙状态查看 | 端口关闭 | 端口开启 | 修改命令

目录 firewall防火墙 【1】查看firewall状态 【2】开启、重启、关闭firewalld服务 【3】查看防火墙规则 【3】 添加指定需要开放的端口&#xff08;开启8088&#xff09; 【4】重载入添加的端口 【5】查询指定端口是否开启成功 firewall防火墙 【1】查看firewall状态 s…

Java日志系统log4j2的使用配置和异步日志使用

目录1. log4j21.1 log4j2介绍1.2 Log4j2入门1.2.1 log4j2(日志门面 日志框架)使用1.2.2 slf4j log4j2使用1.3 Log4j2配置1.4 Log4j2异步日志1.4.1 全局异步AsyncLogger1.4.2 混合异步AsyncLogger1.4.3 AsyncAppender1. log4j2 1.1 log4j2介绍 Apache Log4j2是Log4j的升级版…

IB地理学什么?适合什么人学习?

IB精选&#xff1a;IB地理学什么&#xff1f;快速搞懂自己适不适合修读地理&#xff01; 核心目的IB地理科是一个很特别的科目&#xff0c;目的是要帮助同学掌握一些认识和了解现实世界的技能。这个现实世界包括了两大部分。 第一个部分是自然环境&#xff0c;当中包括生态系统…

你还在恐惧指针吗?点进来,带你全方位深入了解指针

指针是什么&#xff1f; 指针也就是内存地址&#xff0c;指针变量是用来存放内存地址的变量。(存放在指针中的值都被当做地址处理) 对于32位的机器&#xff0c;假设有32根地址线&#xff0c;那么假设每根地址线在寻找地址的时候会产生高电平&#xff08;高电压&#xff09;和…

[ZJCTF 2019]NiZhuanSiWei

目录 信息收集 代码审计 第一层 第二层 第三层 信息收集 打开页面又是代码审计 代码如下 <?php $text $_GET["text"]; $file $_GET["file"]; $password $_GET["password"]; if(isset($text)&&(file_get_contents($text,…

React + TS + TDD 扫雷游戏学习心得

React TS TDD 扫雷游戏学习心得 试玩地址&#xff1a;https://goldenaarcher.com/minesweeper&#xff0c;stroybook 的地址&#xff1a;https://www.chromatic.com/build?appId63b2530f575ed5942cf105be&number1 测试主要使用 jest&#xff08;mock&#xff09; RTL …

Linux进程控制(进程替换)

目录 一、进程程序替换原理 二、进程替换函数 三、函数实现子进程进程替换 3.1 测试函数 3.2 写时拷贝保证替换后的进程独立性 四、自我实现一个简单的 shell 五、内置命令 5.1 pwd查询路径本质 5.2 内置命令概念 5.3 自我实现shell Pro 先见见进程替换&#xff1a; …

Unity学习笔记--如何在Unity中把自己的代码打包成dll给别人使用?(纯保姆式教学,看完还不会,今晚八点,来沙城砍我)

目录前言背景步骤一步骤二步骤三步骤四&#xff08;关键&#xff01;&#xff01;&#xff01;&#xff09;步骤五步骤六步骤七步骤八步骤九步骤十总结前言 最近公司放年假了&#xff0c;没什么事做&#xff0c;所以来公司学习&#xff08;蹭吃蹭喝ing&#xff09; 突然记起来…

CSS总结笔记+案例

此文章属于前端篇中的第二节CSS样式 继前期HTML标记语言 CSS总结笔记&#xff1a; 3.CSS样式 css&#xff0c;专门用来“美化”标签。 基础CSS&#xff0c;写简单页面&看懂&改。模块、调整和修改 3.1CSS应用方法 1.在标签上 - 高度和宽度样式&#xff1a; <i…

linux基本功系列之alias命令实战

本文目录 文章目录前言&#x1f680;&#x1f680;&#x1f680;一. alias命令介绍二. 语法格式及常用选项三. 参考案例3.1 查看系统已经存在的别名3.2 设置别名的操作3.3 取消别名3.4 alias的全局生效和当前用户生效四. 使用命令的注意事项总结前言&#x1f680;&#x1f680;…

行云洞见 | 为什么说云端IDE代表未来趋势?

原文作者&#xff1a;行云创新解决方案架构师 李楠 预知未来最可靠的方法是了解历史&#xff0c;让我们简单回顾下IDE的发展史。 所谓IDE&#xff0c;即集成开发环境&#xff0c;是软件开发人员在他们用于编程的计算机本地安装的应用程序。伴随着计算机编程语言从第一代机器语…

【NI Multisim 14.0虚拟仪器设计——放置虚拟仪器仪表(万用表)】

目录 序言 &#x1f34d;放置虚拟仪器仪表 &#x1f349;万用表 序言 NI Multisim最突出的特点之一就是用户界面友好。它可以使电路设计者方便、快捷地使用虚拟元器件和仪器、仪表进行电路设计和仿真。 首先启动NI Multisim 14.0&#xff0c;打开如图所示的启动界面&#x…

【虹科分享】虹科ATEasy软件,您的测试执行和开发专家!

测试和执行专家 虹科ATEasy是功能测试&#xff0c;自动测试系统&#xff0c;数据采集&#xff0c;过程控制和仪表系统的测试执行和快速应用开发框架。虹科ATEasy提供开发&#xff0c;部署和维护软件组件的所有必要工具&#xff0c;包括仪器驱动程序&#xff0c;测试程序&#x…

SGA与PGA的区别

前几天有被别人问到什么是SGA和PGA&#xff0c;说实在的&#xff0c;之前一直搞分布式&#xff0c;已经基本把单机里面的这两个概念忘记的差不多了&#xff0c;不过当时还是根据自己的一点数据库经验说了点七七八八&#xff0c;后来网上查了一下相关说明&#xff0c;发现自己的…