堆排序 TopK 优先级队列的部分源码 JAVA对象的比较

news2024/9/28 15:24:27

一.堆排序:我们该如何借助堆来对数组的内容来进行排序呢?

假设我们现在有一个数组,要求从小到大进行排序,我们是需要进行建立一个大堆还是建立一个小堆呢?

1)我的第一步的思路就是建立一个小堆,因为每一次堆顶上面的元素就是最小的元素,直接按照顺序进行弹出堆顶元素不就可以了吗

2)但是当前我们要对数组整体本身进行排序,将来的数组,0下标就是最小的元素,不是每一次依次输出最小的元素,不是从小到大进行输出

总结:我们是将数组从小到大进行排序,那么我们建立一个大根堆,如果将数组按照从大到小进行排序,那么我们就建立一个小根堆,如果想让数组从小到大进行排序,那么就建立成一个大根堆

1)先进行把数组元素调整成大根堆,因为我们以后进行数据的交换的时候,总是要把最大的元素放到数组的最后一个位置

2)我们让堆的根节点也就是0小标和数组的最后一个位置未排序的元素进行交换即可,这样就可以保证数组的最后一个end位置一定是当前堆的最大元素,数组的最后一个位置一定是原数组中最大的元素

3)调整成大根堆,因为此时只有根节点的元素所在的位置不是一个大根堆,那么就向下进行调整这棵树

4)定义一个end值等于数组有效数据的长度,并且重复和堆顶元素进行交换,向下进行调整

5)例如我们想要对数组进行从大到小进行排序,那么我们要建立一个大堆;

建立大堆的时间复杂度是O(N),空间复杂度是O(1)

这个代码是错误的,自己去细细地品吧;
  public void sort()
    {
        int len=usedsize;
        while(len!=0)
        {
            int temp=array[len-1];
            array[len-1]=array[0];
            array[0]=temp;
            len--;
            adjustDown(0,len);

        }

  public void heartsort()
        {
            int index=usedsize-1;
            while(index!=0)//让顶上的元素与末尾元素交换,在对啊让arr1[0]进行向上调整
            {
                int temp=arr1[0];
                arr1[0]=arr1[index];
                arr1[index]=temp;
                downadjust(0,index);
                index--;
            }
        }

三:TopK问题

1)有十万个数据,你给我找前十个最大的数据?假设你的数据在内存中是可以进行存放的

思路1:建立一个大堆,弹出堆顶元素10次

就是将所有元素建立一个大堆,既然是找前10个最大的数据,那么就需要pop()10次就可以了(缺点:有多少个数据,堆就有多大),建堆的时间复杂度是O(N),每一次进行向下进行调整的时间复杂度是log(N),所以时间复杂度就是K*logN,其中的logN是向下进行调整的高度

思路2:建立一个大小为K的小堆

1)将前10个数据建立一个大小为10的小堆,遍历剩下的元素如果元素比堆顶元素大,就入堆,同时删除堆顶元素,再将剩下的元素调整成一个小堆;

2)当前我们找的是前十个最大的数据,那么我们为什么要建立一个小堆呢?

因为此时堆顶的元素,一定是当前K个元素中最小的元素,如果有元素比当前的堆顶元素大,那么这个元素很有可能就是Topk中的一个;

3)当我们要找第K大的元素的时候,首先我们要建立一个小堆,遍历剩下的元素,不断地进行比较,最终堆顶元素就是第K小的元素;

时间复杂度:我们要进行遍历这个数组中的所有元素,所以说时间复杂度是O(N),每当我们进行遍历到一个元素的时候,我们都要进行出堆顶元素,并且进行向下调整,每一次进行向下调整的次数是logK,所以说整个TopK问题的时间复杂度就是N*logK

思路:求前K大的元素 

1)先把前K个元素,建立成一个小根堆

2)遍历后面的元素,只要当前遍历的元素比堆顶元素大,就进行弹出堆顶元素,将遍历到的这个元素这个元素入堆操作

3)将这个元素进行入堆之后,我们可以继续将这个堆中的元素,调整成一个小根堆

TopK问题的解决思路:比如说求前K个最小的元素

1)创建一个大小为K的大根堆

2)遍历数组中的元素,将前K个元素放入到队列里面

3)从K+1个元素开始,每一个元素都和堆顶元素进行比较,先弹出,后压入

 

总结:

1)如果说求前K个最大的元素,我们要构建一个小根堆,如果遍历的元素比堆顶的元素大,那么就将它入堆,重新调整成一个小根堆

2)如果说我们求前K个最小的元素,我们需要构建大根堆,如果说遍历的元素比堆顶的元素小,那么就将它入堆,重新调整成一个大根堆

3)如果需要求第K大的元素,建一个小堆,进行遍历原来的数组,最终得到的堆顶元素就是第K大的元素

4)PriorityQueue在进行插入元素的时候,是不可以进行插入null值的,因为我们要进行插入的元素要可以进行比较,况且要有可比较的能力,那么我们如何向优先级队列里面存放自定义元素呢?那么我们这个自定义的类必须事先Compareable接口或者是是Comparator接口

static void TopK(int[]arr1)
      {//创建一个大小为K的大根堆
          PriorityQueue<Integer> priorityQueue=new PriorityQueue<>(3, new Comparator<Integer>() {
//他的意思就是说有一个类,实现了Comparator接口,并且重写了compare方法,相当于就是匿名内部类
              @Override
              public int compare(Integer o1, Integer o2) {
                  return o1-o2;//小堆是o1-o2,大堆是o2-o1
              }
          });
          for(int i=0;i<arr1.length;i++)
          {
//遍历数组中的元素,将前K个元素放到队列里面
              if(priorityQueue.size()<3)
              {
                  priorityQueue.add(arr1[i]);
              }
              else
              {
                  int num=priorityQueue.peek();
//代码走到这里面,说明队列中已经存放了三个元素了
//从第K+1个元素开始,每一个元素都要和当前堆顶元素进行比较
//先找到当前堆顶的元素,如果这个元素比数组元素大,就取出对顶元素,放数组元素入队列
                  if(arr1[i]>num)
                  {
//先进行弹出,在进行存入
                      priorityQueue.poll();
                      priorityQueue.add(arr1[i]);
                  }
              }
          }
          System.out.println(priorityQueue);
         int array[]=new int[k];
        for(int i=0;i<array.length;i++)
        {
            int data=queue.poll();
            array[i]=data;
        }
      
      }
    public static void main(String[] args) {
        int arr1[]={34,23,89,78,123,67,87,55};
//写一个topk问题,找到数组中8个数中前三个最大的
        TopK(arr1);

    }
 public static void main(String[] args) {
     PriorityQueue<Integer> queue=new PriorityQueue<>(new Comparator<Integer>() {
         @Override
         public int compare(Integer o1, Integer o2) {
             return o2-o1;
         }
     });
     int[] array={10,90,100,110,89,78};
     InsertQueue(array,queue);
     System.out.println(queue.poll());
     System.out.println(queue.poll());
     System.out.println(queue.poll());
    }

    private static void InsertQueue(int[] array, PriorityQueue<Integer> queue) {
        for(int i=0;i<array.length;i++){
            queue.offer(array[i]);
        }
    }

 

前K个最大的数对:力扣

这个题还是用TopK来进行解决,我们还是先要创建一个大堆,但是此时优先级队列中放的就不是一个数字了,他存放的是一个数对,也就是说,优先级队列中的每一个元素是一个List<Integer>,以后遍历元素的时候,我们就需要比较的值是每一个List中的两个元素的和;

 class Hello{
    public static void main(String[] args) {
      int arr1[]={1,7,11};
      int arr2[]={2,4,6};
      PriorityQueue<List<Integer>> priorityQueue=new PriorityQueue<>(3, new Comparator<List<Integer>>() {
        @Override
        public int compare(List<Integer> o1, List<Integer> o2) {
          return o2.get(0)+o2.get(1)-o1.get(0)-o1.get(1);
        }
      });
      for(int i=0;i<arr1.length;i++){
        for(int j=0;j<arr2.length;j++) {
          if(priorityQueue.size()<3)
          {
            ArrayList list=new ArrayList<>();
            list.add(arr1[i]);
            list.add(arr2[j]);
            priorityQueue.add(list);
          }
          else
          {
            int top=priorityQueue.peek().get(0)+priorityQueue.peek().get(1);
            if(top>arr1[i]+arr2[j])
            {
              priorityQueue.poll();
              ArrayList list=new ArrayList<>();
              list.add(arr1[i]);
              list.add(arr2[j]);
              list.addAll(list);
            }
          }
        }
      }
      List<List<Integer>> list1=new ArrayList<>();
      for(int k=0;k<3&&!priorityQueue.isEmpty();k++)
      {
        list1.add(priorityQueue.poll());
      }
      System.out.println(list1);


    }

练习:前K个高频单词

题目关键:返回的答案应该按单词出现频率由高到低进行排序,咱们建的是小堆

如果有不同的单词按照相同的出现频率,应该按照字典顺序来进行排序

1)我们遍历原来的哈希表,我们创建一个HashMap里面进行记录每一个字符串出现的次数

2)相当于现在待排序序列是哈希表中的每一个(Key-Value)键值对,我们要根据写键值对来进行建立一个小堆(本质上来说是依靠单词出现的次数建立一个小堆)

3)频率高低为前提,频率高低相同比较字典大小,字典小的入堆


package Demo;

import java.util.*;

class Solution {
    public List<String> topKFrequent(String[] words, int k) {
       HashMap<String,Integer> map=new HashMap<>();
       for(int i=0;i<words.length;i++){
           if(!map.containsKey(words[i])){
               map.put(words[i],1);
           }else{
               int count=map.get(words[i]);
               count++;
               map.put(words[i],count);
           }
       }
       PriorityQueue<Map.Entry<String,Integer>> queue=new PriorityQueue<>(k, new Comparator<Map.Entry<String, Integer>>() {
           @Override
           public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
               if(o1.getValue().compareTo(o2.getValue())==0)
               {
                   return o2.getKey().compareTo(o1.getKey());//当放的元素小于堆的个数处理的时候变成大堆;a-2,b-2;
               }
               return o1.getValue()-o2.getValue();//核心是根据value值进行比较的
           }
       });
       for(Map.Entry<String,Integer> entry:map.entrySet()){
           if(queue.size()<k){
               queue.add(entry);//放入元素的时候会自动帮助我们建立一个大堆
           }else{
               Map.Entry<String,Integer> s1=queue.peek();
               if(entry.getValue().compareTo(s1.getValue())>0){//先看比较堆顶元素和即将要存放的元素出现频率大小
                   queue.poll();
                   queue.add(entry);
               }else if(entry.getValue().compareTo(s1.getValue())==0){//当频率相同的时候,比较长度
                   if(entry.getKey().compareTo(s1.getKey())<0) {//单次顺序在后面的入堆
                       queue.poll();
                       queue.add(entry);
                   }
               }

           }

       }
       List<String> list=new ArrayList<>();
       // System.out.println(queue);
        while(!queue.isEmpty()){
           Map.Entry<String,Integer> entry=queue.poll();
           list.add(entry.getKey());
       }
        Collections.reverse(list);
       return list;
    }
}

对象排序的比较以及PriorityQueue的部分源码

一:向优先级队列里面添加元素:offer的源码

public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
            siftUp(i, e);
        return true;
    }

优先级队列的扩容以及容量问题:

1)当你调用不带有参数的构造方法的时候,默认容量就是11,况且他默认传入的comparator比较器就是空

2)对于优先级队列的扩容,用grow函数进行扩容,如果原来数组的长度小于64,那么以原来的长度的2倍+2进行扩容,如果原来的容量不是小于64的,反之就要以1.5倍进行扩容

存放数据:

3)当我们进行第一次存放元素的时候,会先把第一个元素直接放到底层的queue的0下标、

4)当我们不是第一次存放的时候,会调用siftUp方法,第一个参数是即将要放到数组下标的位置,第二个参数就是要具体存放的引用(对象)

o1就是新存放的元素

 private void siftUp(int k, E x) {//k==2,e等于自定义类型
        if (comparator != null)
//这里面的comparotor是优先级队列中的一个属性,是我们需要在构造方法中进行传入的,在这里面会进行指定比较类型
            siftUpUsingComparator(k, x);
        else
//如果我们没有进行传入comparator比较器,那么最终会默认把我们传输过来的自定义类型强制转化成Comparable类型
            siftUpComparable(k, x);
    }
//假设我们在创建一个优先级队列的时候,既没有向里面传入一个比较器,自定义类型还没有实现Compareator接口,那么最后当我们向队列中存放第二个元素的时候,此时就会发生报错

由于我们使用的是无参的构造方法,没有进行传入一个比较器,所以在上面就会调用siftUpComparable()方法

  @SuppressWarnings("unchecked")
    private void siftUpComparable(int k, E x) {
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
     int parent = (k - 1) >>> 1;//计算父亲节点的下标
            Object e = queue[parent];
            if (key.compareTo((E) e) >= 0)
//这个布尔表达式为假就进行交换,为真就不会进行交换
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }

    @SuppressWarnings("unchecked")
    private void siftUpUsingComparator(int k, E x) {
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (comparator.compare(x, (E) e) >= 0)
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = x;
    }

1)如果说一个没有实现Comparator接口,构建优先级队列的时候还没有进行传一个比较器,那么代码就会抛出,这个类 cannot be cast to java.lang.Comparable

2)上述代码第一行会把对象转化成比较器,在while循环里面会调用compareTo方法

3)如果进入到循环里面,break出去,就不会进行交换,如果可以正确执行到break之后的代码,就可以正确的进行交换了

4)如果换成大堆,直接把compareTo方法的return顺序换一下,这个时候 PriorityQueue是大堆还是小堆完全取决于自定义类实现比较接口的compareTo的方法是怎么写的

1)我们在正常情况下priorityQueue使用的是Compareable接口,当我们没有传入任何的比较器的时候,默认的就是使用Compareable接口,会将元素转化成Compable类型,在进行向上调整的时候,使用了自定义类重写的CompareTo()方法,但是我们要对比较的类实现Compareable接口,这样对于类的侵入性太强了,一旦写好了根据那一种规则进行修改,就不可以进行发生变化了

public PriorityQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }
public PriorityQueue(int initialCapacity) {
        this(initialCapacity, null);
    }
public PriorityQueue(Comparator<? super E> comparator) {
        this(DEFAULT_INITIAL_CAPACITY, comparator);
    }

上面的默认两种方法都是基于compareable接口来进行实现的

2)我们自己可以写一个比较器,所以之前默认构造方法就不可以用了,咱们需要自己写一个比较器:

1)public PriorityQueue(Comparator<? super E> comparator) {
        this(DEFAULT_INITIAL_CAPACITY, comparator)
2)public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {}

里面的while循环都是用compare方法,建立大堆或者小堆都是依靠return语句里面的写法

class AgeComparator implements Comparator<Student>{
    public int compare(Student o1,Student o2){
         return o1.age-o2.age;
    }
}
class Student{
    public int age;
    public String username;
    public Student(int age,String username){
        this.age=age;
        this.username=username;
    }
}
public class Main{
    public static void main(String[] args) {
        AgeComparator comparator=new AgeComparator();
        PriorityQueue<Student> queue=new PriorityQueue<>(3,comparator);
    }   
}

4)自定义类型的比较,一定要实现比较接口;

5)父类的equals方法默认比较的是地址,但是在类中重写equals方法进行比较,比较的是对象里面的内容,先比较两个引用是不是同一种类型,在比较他们具体的内容;

创建小堆o1-o2;创建大堆o2-o1;

@Override
public boolean equals(Object o) {
    if (this == o) return true;//判断他们是否是地址相同,也就是说看看他们是否引用的是同一个对象
    if (o == null || getClass() != o.getClass()) return false;
//看看他们的类对象是否相同,是不是属于同一个类创建的两个对象,比较他们的类型

    //接下来我们要把Object类型转化成Student类型
    Student student = (Student) o;
//比较它们是否对象内容相同
    return age == student.age && Objects.equals(name, student.name);
}

对于String重写equals方法:

 public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;//判断他们是否是地址相同,也就是说看看他们是否引用的是同一个对象
        }
        if (anObject instanceof String) {
//如果说anObject也是一个字符串类型的,就进入到if语句里面进行下一步的比较
            String anotherString = (String)anObject;
//将Object类型转化成字符串类型
            int n = value.length;
            if (n == anotherString.value.length) //在这里面判断他们的长度是否相同
{
//在进行取出两个字符串的每一个字符一一进行比较,如果不相等,那么就直接返回false
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

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

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

相关文章

MGRE和ospf的综合运用

目录实验需求知识点实验过程一&#xff0c;在R1 R2 R3中的MGRE搭建二&#xff0c;在R1 R4 R5中的MGRE搭建三&#xff0c;整个内网的ospf协议实验需求 一 题目要求 1&#xff0c;R6为ISP代表运营商&#xff0c;只能配置ip地址&#xff0c;R1-R5环回 代表私有网段 2&#xff0c…

【Linux】顶级编辑器Vim的基本使用及配置

&#x1f451;作者主页&#xff1a;进击的安度因 &#x1f3e0;学习社区&#xff1a;进击的安度因&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;Linux 文章目录一、前言二、vim基本概念三、vim 基本操作1、模式切换2、命令模式3、插入模式4、底行模式四…

[Vue的数据绑定]一.Vue的数据绑定;二.Vue的事件绑定;三.Class和Style的绑定;四.Vue的过滤器;五.Vue脚手架的使用

目录 一.Vue的数据绑定 1.单向数据绑定&#xff1a;将Model绑定到View上&#xff0c;当通过JavaScript代码改变了Model时&#xff0c;View就会自动刷新。不需要进行额外的DOM操作就可以实现视图和模型的联动 &#xff08;1&#xff09;插值表达式&#xff1a;{{ 表达式 }}&am…

pandas 使用

import pandas as pd a [3,7,2] myvar pd.Series(a,index["x","y","z"]) print(myvar["x"]) #结果是3 #给序列赋值index &#xff0c;然后可以根据index找到对应的数 data {"col1": range(-5,0), "col2": r…

半入耳式耳机适合跑步吗、最适合跑步的五款耳机分享

好的跑步耳机可以帮助您跑得更努力、更快和更久。研究发现&#xff0c;听音乐可以提高跑步成绩&#xff0c;尤其是在速度方面。同时&#xff0c;随着音乐锻炼可以提高跑步者的速度并减少精神疲劳&#xff0c;帮助您自信地打破这些束缚。那么目前市面上有哪些无线耳机是适合跑步…

【算法】分治算法(第三章习题解答)

3 分治算法 3.1 设 AAA 是 nnn 个非 000 实数构成的数组, 设计一个算法重新排列数组中的数, 使得负数都排在正数前面. 要求算法使用 O(n)O(n)O(n) 的时间和 O(1)O(1)O(1) 的空间. 算法设计&#xff1a;由于算法要求使用 O(n)O(n)O(n) 的时间和 O(1)O(1)O(1) 的空间&#xff0…

力扣sql入门篇(八)

力扣sql入门篇(八) 1 订单最多的客户 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 SELECT customer_number FROM Orders GROUP BY customer_number having count(order_number)(SELECT max(o1.number)FROM (SELECT count(order_number) numberFRO…

电压放大器在超声导波声弹特性的液压管路压力检测中的应用

实验名称&#xff1a;电压放大器在超声导波声弹特性的液压管路压力检测中的应用 研究方向&#xff1a;超声检测 实验目的&#xff1a; 为实现农机装备液压系统的非介入式压力检测&#xff0c;在分析适合压力检测的超声导波声弹敏感模态与激励频率的基础上&#xff0c;搭建了一套…

用埃式筛法来求解素数。————C++

目录埃式筛法埃式筛法求解某一个数字包含的所有素数数组Code运行结果埃式筛法判断某一个数字是否为素数Code运行结果埃式筛法 首先要了解什么式埃式筛法之前&#xff0c;需要知道一个定理。 就是素数的整数倍一定不是素数。 了解了这个就基本大概懂了埃式筛法。 首先初始化…

C语言线性表实现:顺序表

文章目录&#xff1a;概念理解&#xff1a;1. 动态顺序表结构体&#xff1a;2. 顺序表动态初始化&#xff1a;3. 顺序表扩容&#xff1a;4. 插入&#xff1a;5. 删除&#xff1a;6. 按位序查找&#xff1a;7. 按值查找&#xff1a;8. 输出顺序表&#xff1a;9. 判断顺序表是否相…

UniSCA漏洞优先级排序

当谈到开源漏洞时&#xff0c;我们会发现它们似乎永远处于增长状态。事实上&#xff0c;UniSCA的开源风险报告显示&#xff0c;与2021年同期相比&#xff0c;2022年前9个月添加到UniSCA漏洞数据库中的开源软件漏洞数量增长了33% 。然而&#xff0c;虽然有些漏洞会带来严重的业务…

Altium Designer 20 凡亿教育视频学习-04

第四部分学习 unknow pin错误原因 将原理图导入到PCB时会出现问题 管脚未使用报错 导入PCB器件全部绿 删掉下面的紫红色框架即可&#xff08;Sheet2&#xff09; 视频讲的方法是&#xff1a;一开始把所有的规则删掉&#xff0c;只保留电气规则 板子大小评估-把器件聚集在一…

16---实现权限菜单管理(一)

1、实现角色管理 建role表 USE management; DROP TABLE IF EXISTS role;CREATE TABLE role (id int(11) NOT NULL AUTO_INCREMENT COMMENT id,name varchar(50) DEFAULT NULL COMMENT 名称,description varchar(255) DEFAULT NULL COMMENT 描述,PRIMARY KEY (id) ) ENGINEInn…

活动星投票最美空姐网络评选微信的投票方式线上免费投票

如何进行“最美空姐”的投票活动_投票小程序投票_投票助力方式大家在选择投票小程序之前&#xff0c;可以先梳理一下自己的投票评选活动是哪种类型&#xff0c;目前有匿名投票、图文投票、视频投票、赛事征集投票等。我们现在要以“最美空姐”为主题进行一次投票活动&#xff0…

Docker 三剑客

Docker 三剑客包括Docker Machine、Docker Compose、Docker Swarm。 1. Docker Machine 1.1 简介 Docker Machine 是 Docker 官方三剑客项目之一&#xff0c;使用它可以在多个平台上快速安装部署Docker环境&#xff0c;还可以在短时间内快速构建起一套Docker主机集群。 Do…

最近手头有点紧,于是用Python来冲一波股票...

文章目录前言准备工作获取数据部分爬虫的基本流程代码展示数据可视化分析最后前言 快过年了&#xff0c;手头有点紧&#xff0c;但是作为一个男人&#xff0c;身上怎么能够没有大把钞票呢&#xff1f; 于是我决定用Python来分析一波股票&#xff0c;赢了会所嫩*&#xff0c;输…

在线设计邀请函

不用ps就能制作邀请函的工具&#xff01;在线就能搞定你的邀请函设计和链接分享&#xff01;只要跟着小编下面的设计步骤&#xff0c;掌握在线工具乔拓云轻松设计在线邀请函&#xff0c;在线一键就能生成活动邀请函和邀请函链接&#xff0c;下面就跟着小编的教学开始学习如何在…

【力扣经典题目】复制带随机指针的链表,穿插链表法

题目描述&#xff1a; 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成&#xff0c;其中每个新节点的值都设为其对应的…

接口的理解

文章目录一、接口匿名实现类、匿名对象练习1练习2JDK8接口的新特性一、接口 1、接口使用interface定义 2、Java中接口和类是并列结构 3、如何定义接口——定义接口中的成员 JDK7之前&#xff1a;只能定义全局常量和抽象方法 全局常量&#xff1a;public static final的&#x…

力扣 2042. 检查句子中的数字是否递增

题目 句子是由若干 token 组成的一个列表&#xff0c;token 间用 单个 空格分隔&#xff0c;句子没有前导或尾随空格。每个 token 要么是一个由数字 0-9 组成的不含前导零的 正整数 &#xff0c;要么是一个由小写英文字母组成的 单词 。 示例&#xff0c;“a puppy has 2 eye…