当前位置: 首页 > news >正文

【数据结构】双向链表及LRU缓存的实现

目录

前言

1. 在原有的自定义链表类 Linked 的基础上,添加新的 “节点添加”方法 addNode(Node node)

测试用例

测试结果

2. 在自定义链表类的基础上,使用双重循环“强力” 判断两个节点是否发生相交

测试用例

测试结果

3. 在自定义链表类的基础上,使用“双指针”判断两条链表是否相交

测试用例

测试结果

4. 在自定义链表类的基础上,将一条链表进行分割

测试用例

测试结果 

5. 使用链表实现 LRU缓存

重写toString()方法

测试用例

测试结果


前言

书接上回,我们继续撕链表,不同上次的是,这次双向链表(使用“双向链表 + 哈希表”实现LRUCache缓存)也得被我们撕;

相关传送门:===》【算法】单向链表手撕代码《===


1. 在原有的自定义链表类 Linked 的基础上,添加新的 “节点添加”方法 addNode(Node node)

    //不使用 new Node 创造节点public void addNode(Node node){//获取当前链表的尾节点final Node l =last;if(l !=null){//链表不为空l.next = node;}else{//链表为空first =node;}last = node;size++;}

不同于之前添加节点的方法 add(int val) 的是:这个方法不使用 new Node 创造节点;

原 add(int val) 方法:

    //添加元素(尾插法)public void add(int val){//获取当前链表的尾节点final Node l = last ;//创建新节点final Node newNode = new Node(val);if(l !=null){//链表不为空l.next = newNode;}else{//链表为空first = newNode;}last = newNode;size++;}
  • 测试用例
        Linked.Node node1 =new Linked.Node(1);Linked.Node node2 =new Linked.Node(2);Linked.Node node3 =new Linked.Node(3);Linked.Node node4 =new Linked.Node(4);Linked.Node node5 =new Linked.Node(5);Linked.Node nodeA =new Linked.Node(1);Linked.Node nodeB =new Linked.Node(2);Linked.Node nodeC =new Linked.Node(3);Linked link1 = new Linked();link1.addNode(node1);link1.addNode(node2);link1.addNode(node3);link1.addNode(node4);link1.addNode(node5);Linked link2 =new Linked();link2.addNode(nodeA);link2.addNode(nodeB);link2.addNode(nodeC);link2.addNode(node3);   //链表相交System.out.println(link1);System.out.println(link2);
  • 测试结果

如图所示,link1链表与link2链表发生了链表相交

链表相交:顾名思义,两个链表在某个节点处有相同的节点,即它们共享同一个节点作为交点;


2. 在自定义链表类的基础上,使用双重循环“强力” 判断两个节点是否发生相交

思路:

  • 设置两个变量,分别遍历两个链表,双重 for 循环,在循环遍历过程中,如果两个变量相等,那么两个链表相交;
    //使用双重循环的方式判断两条链表是否相交public  static  boolean isIntersect1(Linked link1,Linked link2){for(Node p=link1.first; p !=null;p = p.next){for(Node q =link2.first; q != null; q = q.next){if( p == q ){return true; //相交}}}return false; // 不相交}

解读:

  • 外部循环从第一个链表的头节点开始,依次遍历每个节点;
  • 内部循环检查第一个链表的当前节点是否与第二个链表的任何节点相同;
  • 在内部循环中,通过比较节点的引用地址来判断两个节点是否相同;
  • 如果找到相同的节点,说明两个链表在此处相交,返回 true
  • 如果外部循环结束后仍未找到相交的节点,那么说明两个链表不相交,返回 false

效率较低,尤其是在处理大型链表时

  • 测试用例

 在 1 的测试用例中,添加:

 System.out.println("link1 与 link2 是否发生相交:"+Linked.isIntersect1(link1,link2));
  • 测试结果


3. 在自定义链表类的基础上,使用“双指针”判断两条链表是否相交

思路:

  • 判断两个链表是否相交,该两个链表中长度必定有长有短,或者相等。如果这两个链表长度不相等,我们可以得到两个链表的长度的插值diff。同样也是设置两个变量 p,q,分别遍历长链表和短链表,与方法使用双重循环不同的是,p遍历长链表的时候不是从第一个节点开始遍历,而是先让p往后移动diff个节点,然后p和q同时循环往后一个节点,如果p == q,那么两个链表就相交。
    //使用“双指针”判断两条链表是否相交public static boolean isIntersect2(Linked link1 ,Linked link2){/*** 不支持这个算法,需要添加代码,对链表元素进行遍历,计算链表长度* public int size(){*  return size;* }*/// p指向长链表//Node p = link1.size() > link2.size() ? link1.first : link2.first;Node q = link1.size() < link2.size() ? link1.first : link2.first;//两条链表的长度差int diff = Math.abs(link1.size() - link2.size());//长链表移动diff个结点while (diff-- >0){p = p.next;}//遍历链表中的剩余结点while (p != q){p = p.next;q = q.next;}if( p != null){return  true;  //相交}return false;  //不相交}

更改原自定义链表类的链表长度计算方法 size()

    //返回链表长度public int size(){int size =0;for(Node x =first;x !=null; x =x.next){size++;}return size;}

解读:

  • 使用链表的 size() 方法获取链表的长度;
  • 通过比较两个链表的长度,选择其中较长的链表,将较长的链表赋值给 p,较短的链表赋值给 q
  • 然后计算两个链表的差值,并将p移动该差值的节点数目,使得 p q 所在位置到链表末尾的距离相同;
  • 使用两个指针同时遍历两个链表,直到 p q 相等,或者遍历到链表结尾;
  • 如果 p q 相等,说明两个链表在某个位置相交,返回 true 表示相交;

时间复杂度为O(m+n),其中m和n分别为两个链表的长度。相较于双重循环的方法,这种方法通常具有更好的性能。

  • 测试用例
        Linked.Node node1 =new Linked.Node(1);Linked.Node node2 =new Linked.Node(2);Linked.Node node3 =new Linked.Node(3);Linked.Node node4 =new Linked.Node(4);Linked.Node node5 =new Linked.Node(5);Linked.Node nodeA =new Linked.Node(1);Linked.Node nodeB =new Linked.Node(2);Linked.Node nodeC =new Linked.Node(3);Linked link1 = new Linked();link1.addNode(node1);link1.addNode(node2);link1.addNode(node3);link1.addNode(node4);link1.addNode(node5);Linked link2 =new Linked();link2.addNode(nodeA);link2.addNode(nodeB);link2.addNode(nodeC);link2.addNode(node3);   //链表相交System.out.println(link1);System.out.println(link2);System.out.println("link1 与 link2 是否发生相交:"+Linked.isIntersect2(link1,link2));
  • 测试结果


4. 在自定义链表类的基础上,将一条链表进行分割

思路:

  • 遍历原链表,判断每个节点,并存入两条不同的新链表中,分别用于保存小于给定值x和大于给定值x的节点,最后合并两条链表。
    //链表的分割public static Node partition(Node head,int x){//准备两条链表,用于分别保存小于x的节点和大于x的节点Node linked1 = new Node(0);Node linked2 = new Node(0);Node cur1 =linked1;Node cur2 =linked2;//从头节点开始遍历,分别判断每个节点与x之间的大小关系while (head !=null){if(head.val <=x){//小于x,存入链表1cur1.next = head;cur1 = cur1.next;}else{//大于x,存入链表2cur2.next = head;cur2 = cur2.next;}head = head.next;}//合并链表cur1.next = linked2.next;cur2.next = null;return linked1.next;}

解读:

  • 定义了一个静态方法 partition,该方法接收两个参数:一个是头节点 head,另一个是值 x;
  • 创建了两个新的链表 linked1 linked2,并分别用 cur1 cur2 来指向这两个链表的当前节点;
  • 从头节点开始遍历原始链表 head,对每个节点的值与给定值 x 进行比较;
  • 如果节点的值小于等于 x,则将该节点添加到 linked1 链表中,并更新 cur1 指针;
  • 如果节点的值大于 x,则将该节点添加到 linked2 链表中,并更新 cur2 指针;
  • 遍历完整个原始链表后,将 linked1 链表的尾部与 linked2 链表的头部连接起来,同时将 linked2 链表的尾部指向 null,以避免形成循环;
  • 最后返回 linked1 链表的头部作为结果,即经过分区后的新链表;
  • 测试用例
        // 创建链表节点Linked.Node node1 = new Linked.Node(3);Linked.Node node2 = new Linked.Node(5);Linked.Node node3 = new Linked.Node(8);Linked.Node node4 = new Linked.Node(5);Linked.Node node5 = new Linked.Node(10);Linked.Node node6 = new Linked.Node(2);Linked.Node node7 = new Linked.Node(1);// 构建链表:3 -> 5 -> 8 -> 5 -> 10 -> 2 -> 1node1.next = node2;node2.next = node3;node3.next = node4;node4.next = node5;node5.next = node6;node6.next = node7;// 执行分割方法Linked.Node result = Linked.partition(node1, 5);// 输出分割后的链表while (result != null) {System.out.print(result.val + " -> ");result = result.next;}System.out.println("null");
  • 测试结果 


5. 使用链表实现 LRU缓存

要求:

实现 LRUCache 类:满足 LRU ( Least Recently User 最近最少使用)缓存实现类;

  • LRUCache(int capacity) 以正整数作为容量 capacity 初始化LRU缓存;
  • int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1;
  • void put(int key,int value) 如果关键字 key 已经存在,则变更其数据值 value;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该逐出最久未使用的关键字;
  • 函数 get() put() 必须以 O(1) 的平均时间复杂度运行;
/*** Your LRUCache object will be instantiated and called as such:* LRUCache obj = new LRUCache(capacity);* int param_1 = obj.get(key);* obj.put(key,value);*/public class LRUCache{public LRUCache(int capacity){}public int get(int key){}public void put(int key,int value){}}

思路:

通过双向链表 + 哈希表实现:

  • 双向链表按照被使用的顺序存储键值对,靠近头部的键值对是最近使用的,而靠近尾部的键值对是最久未使用的,用于实现 Least Recently User 最近最少使用的缓存约束;
  • 哈希表通过缓存数据的键映射在双向链表中的位置;
  • get () 根据 key 获取 value ,并同时将节点移动至链表的头部;
  • put () 添加新缓存键值对,并同时添加至链表的头部。如果超出容量,则删除链表尾部节点;
  • 通过上述操作,可保证查找函数 get() put() 的时间复杂度为 O(1);

基础代码:

在 LRUCache 类中创建 Node 内部类

    //①节点类:双向链表的节点class Node{public int key;public int value;Node prev;  //节点前趋Node next;  //节点后继public Node(){}public Node(int key,int value){this.key = key;this.value = value;}}

 解读:

  • key:表示节点的键,缓存中存储的数据的标识;
  • value:表示节点的值,缓存中存储的数据;
  • prev:表示节点的前趋节点,该节点在链表中的前一个节点;
  • next:表示节点的后继节点,该节点在链表中的后一个节点;
  • 默认构造函数 public Node():创建一个空节点;
  • 构造函数 public Node(int key, int value):创建一个具有指定键值的节点;

定义缓存容量和“伪”头节点和“伪”尾节点

    //②定义缓存容量private int capacity;//②定义“伪”头节点和"伪"尾节点private Node first,last;

 解读:

  • capacity:表示缓存的容量,缓存可以存储的键值对的最大数量。在LRU缓存中,当缓存达到容量上限时,需要进行淘汰操作以腾出空间存储新的数据;

  • first last:分别表示双向链表中的虚拟头节点和虚拟尾节点。在LRU缓存中,使用虚拟头节点和虚拟尾节点的目的是简化链表操作,使得在链表头部和尾部插入、删除节点更加方便高效。这两个节点并不存储实际的数据,只是作为辅助节点来连接实际的数据节点;

定义 LRUCache 的有参构造方法

    public LRUCache(int capacity) {this.capacity = capacity;//③创建first = new Node();last = new Node();//③形成链表first.next = last;last.prev = first;}

解读:

  • 将输入的缓存容量赋给成员变量 capacity,保存缓存的最大容量;

  • 创建虚拟头节点 first 和虚拟尾节点 last,并将它们连接起来形成一个双向链表。这两个节点不存储实际的数据,只作为辅助节点来连接实际的数据节点。在这里,通过将 first next 指向 last,以及 last prev 指向 first,形成了一个空的双向链表结构;

创建操作节点 Node 的三个方法:addFirst、removeNode、removeLast、moveToFirst;

    //④添加新节点至链表头部private void addFirst(Node newNode){newNode.prev = first;newNode.next = first.next;first.next.prev = newNode;first.next = newNode;}//④删除链表中的指定节点private void removeNode(Node node){node.prev.next = node.next;node.next.prev = node.prev;}//④删除链表的尾节点private Node removeLast(){Node res =last.prev;removeNode(res);return res;}//④移动指定节点至链表头部private void moveToFirst(Node node){removeNode(node);addFirst(node);}

解读:

  • addFirst(Node newNode) 方法用于将新节点添加至链表头部。该方法首先将新节点的 prev 指向虚拟头节点 first,将新节点的 next 指向原头节点的下一个节点,然后将原头节点的 prev 指向新节点,最后将虚拟头节点 first next 指向新节点,完成新节点的插入;

  • removeNode(Node node) 方法用于删除链表中的指定节点。该方法通过修改指定节点的前趋节点和后继节点的指针来实现节点的删除操作;

  • removeLast() 方法用于删除链表的尾节点,并返回被删除的节点。该方法首先找到尾节点 last 的前一个节点,然后调用 removeNode(node) 方法删除该节点,并返回被删除的尾节点;

  • moveToFirst(Node node) 方法用于将指定节点移动至链表头部。该方法先调用 removeNode(node) 方法将节点从原位置删除,然后调用 addFirst(node) 方法将节点添加至链表头部,实现节点的移动操作;

初始化哈希表和定义哈希表的 put() 方法

    //⑤创建哈希表,用来提高查询链表的性能private Map<Integer,Node> cache = new HashMap<>();
    //⑤添加新缓存 key-value 键值对public void put(int key, int value) {Node node =cache.get(key);if(node == null){//key 如果不存在//创建新节点Node newNode =new Node(key,value);cache.put(key,newNode); //添加至哈希表addFirst(newNode);  //添加链表头部if(++size > capacity){//⑦超出缓存容量时,删除尾部节点(哈希表、链表)Node last = removeLast();cache.remove(last.key);}}else{//key 如果存在node.value = value;moveToFirst(node);  //移动至链表头部}}

解读:

1. 通过调用 cache.get(key) 方法从哈希表中获取指定键 key 对应的节点 node

2. 如果 nodenull,表示键 key 不存在于缓存中,需要执行以下操作:

  • 创建新的节点 newNode,使用输入的 key 和 value 初始化该节点。
  • 将新节点 newNode 添加至哈希表 cache 中,使用 key 作为键,newNode 作为值。
  • 调用 addFirst(newNode) 方法将新节点 newNode 添加至链表的头部
  • 如果缓存的大小 size 超过了最大容量 capacity,则需要执行以下操作:
    • 调用 removeLast() 方法删除链表的尾节点,并返回被删除的节点 last;
    • 从哈希表 cache 中删除键为 last.key 的键值对;

3. 如果 node 不为 null,表示键 key 已存在于缓存中,需要执行以下操作:

  • 更新节点 node 的值为输入的 value;
  • 调用 moveToFirst(node) 方法将节点 node 移动至链表的头部;

定义链表长度和 哈希表的 put() 方法

    //⑥定义链表长度(缓存个数)private int size;
    //⑥ 根据key,获取valuepublic int get(int key) {Node node =cache.get(key);if(node == null){return -1;  //不存在}moveToFirst(node);  //存在则将这个元素移动至链表的头部return node.value;  //返回这个节点的值}

 解读:

  • 通过调用 cache.get(key) 方法从哈希表中获取指定键 key 对应的节点 node

  • 如果 nodenull,表示缓存中不存在键 key,则返回 -1 表示不存在该键;

  • 如果 node 不为 null,表示缓存中存在键 key,则需要执行以下操作:

    • 调用 moveToFirst(node) 方法将节点 node 移动至链表的头部,以更新节点的访问顺序;
    • 返回节点 node 的值 node.value;

在 put()方法中定义超出容量时的判断逻辑

         if(++size > capacity){//⑦超出缓存容量时,删除尾部节点(哈希表、链表)Node last = removeLast();cache.remove(last.key);}

 解读:

  • 调用 removeLast() 方法删除链表的尾节点,并将被删除的节点赋值给变量 last;

  • 通过 cache.remove(last.key) 从哈希表 cache 中删除键为 last.key 的键值对,即删除了对应的缓存项;

重写toString()方法
  @Overridepublic String toString() {//使用线程不安全,但性能较好的StringBuilderStringBuilder ret = new StringBuilder();String ret1 ="";for(Node x =first;x != null;x =x.next){
//            ret.append(x.key+":"+x.value+"\t");ret1 += x.key + ":"+x.value+"\t\t";}return ret1.toString();}
测试用例
 public static void main(String[] args) {LRUCache lRUCache = new LRUCache(2);lRUCache.put(1, 1);System.out.println(lRUCache);lRUCache.put(2, 2);System.out.println(lRUCache);lRUCache.put(3, 3);System.out.println(lRUCache);lRUCache.put(2, 20);System.out.println(lRUCache);lRUCache.put(4, 4);System.out.println(lRUCache);System.out.println(lRUCache.get(2));    // 返回 20System.out.println(lRUCache);}
测试结果


相关文章:

【数据结构】双向链表及LRU缓存的实现

目录 前言 1. 在原有的自定义链表类 Linked 的基础上&#xff0c;添加新的 “节点添加”方法 addNode(Node node) 测试用例 测试结果 2. 在自定义链表类的基础上&#xff0c;使用双重循环“强力” 判断两个节点是否发生相交 测试用例 测试结果 3. 在自定义链表类的基础上…...

2、计划任务不显示UI的问题

计划任务不显示UI的问题 1、原因&#xff1a; 在windows7以上系统&#xff0c;使用system权限启动的进程默认是没有ui界面&#xff0c;这是windows系统出于安全考虑的限制。防止用户在高权限下误删重要的文件。 2、解决方案&#xff1a; 1、降权 解决的办法&#xff1a;降…...

学C还是学C++?

计算机专业学生&#xff0c;大一上学期学习了C语言&#xff0c;下学期学校要学C&#xff0c;请问我寒假继续深入学习C还是提前学C,大佬们有什么建议吗&#xff1f;&#xff08;个人感觉C学的不是很明白&#xff0c;链表文件什么的还不是很懂…&#xff09; 这个并没有一个统一的…...

Springboot参数分组校验

Springboot参数分组校验 文章目录 Springboot参数分组校验简介代码准备单个或多个参数的校验非 JSON 格式的对象参数校验JSON 格式的对象参数校验Service 层校验项目地址 简介 Java API规范(JSR303)定义了Bean校验的标准validation-api&#xff0c;但没有提供实现。hibernate …...

无缝集成 MongoDB Relational Migrator,Tapdata 提供关系型到 MongoDB 实时迁移优化方案

在去年的 MongoDB 用户大会纽约站上&#xff0c;MongoDB 正式宣布全面推出新工具 MongoDB Relational Migrator&#xff08;MongoDB RM&#xff09;&#xff0c;用以简化应用程序迁移和转换——即从传统关系型数据模型到现代的文档数据模型&#xff0c;助力组织快速提升运营效率…...

【C++】每日一题 146 LRU缓存

请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 int get(int key) 如果关键字 key 存在于缓存中&#xff0c;则返回关键字的值&#xff0c;否则返回 -1 …...

CentOS搭建NAS服务器并使用

CentOS搭建NAS服务器并使用 文章目录 前言一、配置NAS服务器安装 NFS 服务&#xff1a;启动 NFS 服务&#xff1a;使 NFS 服务在系统启动时自动启动&#xff1a; 二、挂载服务器三、常见错误以及解决方案1、mount.nfs: No route to host2、mount.nfs: access denied by server …...

爬虫入门到精通_框架篇16(Scrapy框架基本使用)_名人名言的抓取

1 目标站点分析 抓取网站&#xff1a;http://quotes.toscrape.com/ 主要显示了一些名人名言&#xff0c;以及作者、标签等等信息&#xff1a; 点击next&#xff0c;page变为2&#xff1a; 2 流程框架 抓取第一页&#xff1a;请求第一页的URL并得到源代码&#xff0c;进行下…...

mac inter 芯片遇到程序无法打开(无法验证开发者)

mac inter 芯片遇到程序无法打开&#xff08;无法验证开发者&#xff09; 解决方案 终端运行命令&#xff1a; sudo xattr -r -d com.apple.quarantine 文件路径(直接把文件拖入到终端&#xff0c;可以自动找到文件路径)即可令其获得权限 补充知识&#xff1a; 通过gpt可以…...

科技成果鉴定测试如何进行?第三方检测机构进行鉴定测试的好处

科技成果鉴定测试&#xff0c;作为科技领域中一项重要的质量检验手段&#xff0c;具有广泛的应用范围。旨在为科技成果的研发者和使用者提供客观、科学、权威的鉴定结果&#xff0c;从而评估科技成果的技术水平和市场竞争力。   科技成果鉴定测试是对科技成果进行系统、全面的…...

八、词嵌入语言模型(Word Embedding)

词嵌入&#xff08;Word Embedding, WE&#xff09;&#xff0c;任务是把不可计算、非结构化的词转换为可以计算、结构化的向量&#xff0c;从而便于进行数学处理。 一个更官方一点的定义是&#xff1a;词嵌入是是指把一个维数为所有词的数量的高维空间&#xff08;one-hot形式…...

重学SpringBoot3-WebMvcConfigurer接口

摘要&#xff1a; 本文详细介绍了SpringBoot 3中的WebMvcConfigurer接口&#xff0c;旨在帮助读者深入理解其原理和实现&#xff0c;从而能够更好地使用SpringBoot进行Web开发。阅读本文需要大约30分钟。 关键词&#xff1a;SpringBoot, WebMvcConfigurer, SpringMVC, Web开发…...

《深入理解springCloud与微服务》笔记

第一章 微服务介绍 1.3 微服务的不足 1.3.2 分布式事务 CAP 理论&#xff0c;即同时满足“一致性”“可用性”和“分区容错”是 件不可能的事。 Consistency &#xff1a;指数据的强一致性。如果写入某个数据成功&#xff0c;之后读取&#xff0c;读到的都是新写入的数据&a…...

Vivado原语模板

1.原语的概念 原语是一种元件! FPGA原语是芯片制造商已经定义好的基本电路元件,是一系列组成逻辑电路的基本单元,FPGA开发者编写逻辑代码时可以调用原语进行底层构建。 2.原语的分类 原语可分为预定义原语和用户自定义原语。预定义原语为如and/or等门级原语不需要例化,可以…...

【linux本地安装tinycudann包教程】

【linux本地安装tinycudann包教程】 tiny-cuda-nn官网链接 如果你是windows 10系统的,想要安装tiny-cuda-nn可以参考我的文章——windows 10安装tiny-cuda-n包 根据官网要求:C++要求对应14,其实这样就已经告诉我们linux系统中的gcc版本不能高于9,同时下面又告诉我们gcc版…...

使用Nginx进行负载均衡

什么是负载均衡 Nginx是一个高性能的开源反向代理服务器&#xff0c;也可以用作负载均衡器。通过Nginx的负载均衡功能&#xff0c;可以将流量分发到多台后端服务器上&#xff0c;实现负载均衡&#xff0c;提高系统的性能、可用性和稳定性。 如下图所示&#xff1a; Nginx负…...

什么护眼台灯效果好?热门护眼台灯全方位测评推荐

台灯可以说是佳佳必备&#xff0c;尤其是家中有正在上学的孩子的更是需要一款好的台灯&#xff0c;不管是看书、写字都离不开台灯。不过很多家长在挑选台灯时往往仅关注到光线亮度是否充足&#xff0c;而忽略掉光线均匀度、舒适度等等方面的问题。所以选择一款优质的护眼台灯是…...

云上三问,迈向智能时代的关键

在今天的中国&#xff0c;第一热词是什么&#xff1f;面对这个问题&#xff0c;“新质生产力”当仁不让&#xff0c;而智能化技术毫无疑问是“新质生产力”最重要的来源之一。 在这样的大势下&#xff0c;大型政企是向新技术要“新质生产力”的时代先锋。云服务&#xff0c;则是…...

【网络安全】手机不幸被远程监控,该如何破解,如何预防?

手机如果不幸被远程监控了&#xff0c;用三招就可以轻松破解&#xff0c;再用三招可以防范于未然。 三招可破解可解除手机被远程监控 1、恢复出厂设置 这一招是手机解决软件故障和系统故障的终极大招。只要点了恢复出厂设置&#xff0c;你手机里后装的各种APP全部将灰飞烟灭…...

每日OJ题_哈希表④_力扣219. 存在重复元素 II

目录 力扣219. 存在重复元素 II 解析代码 力扣219. 存在重复元素 II 219. 存在重复元素 II 难度 简单 给你一个整数数组 nums 和一个整数 k &#xff0c;判断数组中是否存在两个 不同的索引 i 和 j &#xff0c;满足 nums[i] nums[j] 且 abs(i - j) < k 。如果存在&am…...

42.坑王驾到第八期:uniCloud报错

uniCloud 报错 今天调用云函数来调试小程序的时候突然暴了一个奇葩错误&#xff0c;require(…).main is not a function。翻官方文档后发现&#xff0c;原来是这样&#xff1a;**如果你写的是云对象&#xff0c;入口文件应为 index.obj.js&#xff0c;如果你写的是云函数入口…...

Linux常用操作命令

Linux常用操作命令 1.文件管理catfile 2.文档编辑3.文件传输4.磁盘管理5.磁盘维护6.网络通讯7.系统管理8.系统设置9.备份压缩10.设备管理 Linux 英文解释为 Linux is not Unix。 Linux内核最初只是由芬兰人李纳斯托瓦兹&#xff08;Linus Torvalds&#xff09;在赫尔辛基大学上…...

OpenCV的常用数据类型

OpenCV涉及的常用数据类型除包含C的基本数据类型,如&#xff1a;char、uchar&#xff0c;int、unsigned int,short 、long、float、double等数据类型外, 还包含Vec&#xff0c;Point、Scalar、Size、Rect、RotatedRect、Mat等类。C中的基本数据类型不需再做说明下面重点介绍一下…...

STM32串口通信—串口的接收和发送详解

目录 前言&#xff1a; STM32串口通信基础知识&#xff1a; 1&#xff0c;STM32里的串口通信 2&#xff0c;串口的发送和接收 串口发送&#xff1a; 串口接收&#xff1a; 串口在STM32中的配置&#xff1a; 1. RCC开启USART、串口TX/RX所对应的GPIO口 2. 初始化GPIO口 …...

《汇编语言》第3版 (王爽) 第14章

第14章 端口 检测点14.1 &#xff08;1&#xff09;.编程&#xff0c;读取CMOS RAM的2号单元的内容。 mov al,2 ;向al写入2 out 70,al ;将2送入端口70h in al,71 ;从端口71h读取2号单元的内容在CMOS RAM中用6个字节存放当前时间&#xff08;以BCD码形式存放&#xff09;&…...

Axure原型设计项目效果 全国职业院校技能大赛物联网应用开发赛项项目原型设计题目

目录 前言 一、2022年任务书3效果图 二、2022年任务书5效果图 三、2022年国赛正式赛卷 四、2023年国赛第一套样题 五、2023年国赛第二套样题 六、2023年国赛第三套样题 七、2023年国赛第四套样题 八、2023年国赛第七套样题 九、2023年国赛正式赛题&#xff08;第八套…...

力扣串题:字符串中的第一个唯一字母

映射做法&#xff1a;将字母转为数字之类的转化必须在运算中实现如-a int firstUniqChar(char * s){int a[26] {0};int len strlen(s);int i;for (i 0; i < len; i)a[s[i] - a];for (i 0; i < len; i) {if (a[s[i] - a] 1)return i;}return -1; }...

【五、接口自动化测试】GET/POST 请求区别

大家好&#xff0c;我是山茶&#xff0c;一个探索AI 测试的程序员 在网上看到了许多关于post与get之间区别的帖子&#xff0c;也有很多帖子是直接粘贴复制的&#xff0c;甚至连标题、符号都没改&#xff0c;甚至还有很多争议 一、post、get 关于post与get之间区别&#xff0c;…...

HDOJ 2036

改革春风吹满地 Problem Description “ 改革春风吹满地, 不会AC没关系; 实在不行回老家&#xff0c; 还有一亩三分地。 谢谢!&#xff08;乐队奏乐&#xff09;” 话说部分学生心态极好&#xff0c;每天就知道游戏&#xff0c;这次考试如此简单的题目&#xff0c;也是云里雾…...

2.案例、鼠标时间类型、事件对象参数

案例 注册事件 <!-- //disabled默认情况用户不能点击 --><input type"button" value"我已阅读用户协议(5)" disabled><script>// 分析&#xff1a;// 1.修改标签中的文字内容// 2.定时器// 3.修改标签的disabled属性// 4.清除定时器// …...