【数据结构】ArrayList的具体使用(杨辉三角、扑克牌游戏)

news2025/1/12 1:57:17

目录

1、了解集合的框架

2、了解ArrayList类

2.1、认识ArrayList类当中的属性

2.1、认识ArrayList类库当中的方法

2.1.1、了解构造方法 

2.2、ArrayList类当中的Add(新增元素)方法

2.3、了解ensureCapacityInternal(判断是否需要扩容)方法

2.4、认识grow(扩容)方法  

2.5、 在数组的某个位置新增元素

 2.6、删除数组当中的元素

2.7、 get方法

 2.8、clear方法(置空)

2.9、 截取数组部分内容(subList)

 2.9、ArrayList的遍历输出

3、来看一道面试题

4、杨辉三角 

5、扑克牌游戏  

1、扑克(Poker)类

 2、游戏(Game)类

3、测试类


1、了解集合的框架

 Java 集合框架 Java Collection Framework ,又被称为容器 container ,是定义在 java.util 包下的一组接口 interfaces 和其实现类 classes 。


2、了解ArrayList类

ArrayList是一个泛型类,同时他继承了AbstractList这个抽象类,同时他也实现了List,RandomAccess,Cloneable,java.io.Serializable接口。 

2.1、认识ArrayList类当中的属性

 ArrayList类当中定义了常量、不可修改的静态的数组。

2.1、认识ArrayList类库当中的方法

2.1.1、了解构造方法 

方法解释
ArrayList()无参构造方法
ArrayList(Coiiection<? extends E> c)利用其他Collection构建ArrayList
ArrayList(int  initialCapacity)指定顺序表初始容量

1、ArrayList()无参构造方法

通过构造方法,将数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA赋值给数组elememtData ,当再实例化ArrayList时,调用无参构造方法,此时并没有为数组elemntData分配内存

2、ArrayList(int initialCapacity)有参构造方法

3、 ArrayList(Coiiection<? extends E> c)构造方法

 可以这样测试这个方法

import java.util.ArrayList;
import java.util.LinkedList;
public class Test {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        list.add(12);
        list.add(35);
        list.add(55);
//当然这里指定的参数也可以修改为Number,Integer类是Number的子类,list指定的参数是Integer。
//ArrayList类在实例化的时候调用的第三种构造方法,list当作参数传给构造方法
        ArrayList<Integer> arrayList1 = new ArrayList<>(list);//将另一个集合拿过来作为这个集合的参数。
        //这样就可以将list数组当中的元素放到arrayList1当中去。
        arrayList1.add(1);
        System.out.println(arrayList1);
    }
}

2.2、ArrayList类当中的Add(新增元素)方法

  •  第一步调用的方法ensureCapacityInternal,作用是,用来检查数组是否已满,
  • 第二步,用来将添加的数据放在数组的最后,size再++,记录数组当中的个数。

再add方法中调用了 ensureCapacityInternal方法,所以这里来了解一下ensureCapacityInternal方法。

2.3、了解ensureCapacityInternal(判断是否需要扩容)方法

假设我们再定义add的时候,给了add方法的参数Integer类型的数据1.

在add方法中调用了ensureCapacityInternal方法,传给这个方法的值为size+1,实际值为1.

但是在 ensureCapacityInternal方法中,有调用了ensureExplicitCapacity方法,ensureExplicitCapacity方法中又调用了calculateCapacity方法,calculateCapacity方法的返回值作为ensureExplicitCapacity方法的参数。

来看calculateCapacity(比较方法)方法

 if当中判断elememtData数组是否和数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA相等,在构造方法中数组DEFAULTCAPACITY_EMPTY_ELEMENTDATA给elememtData数组赋值,所以这两数组的引用表示的是同一个数组。

因为DEFAULT_CAPACITY在定义ArrayList类的时候,指定了值,所以Math.max(DEFAULT_CAPACITY, minCapacity);中比较的是10和1的最大值。

 所以返回10。

10作为ensureExplicitCapacity方法的参数

 数组需要的最小容量是10,现在数组大小为0,所以进入if 条件内部,调用grow方法进行扩容。

2.4、认识grow(扩容)方法  

 newCapacity = oldCapacity + (oldCapacity >> 1);

这句代码表示的意思是:newCapacity 等于oldCapacity+oldCapacity/2,扩大到原来的二倍。

>>1表示:向右移动一位,二进制中向右移动一位,相当于除以2.

  • 接下来判断,newCapacity - minCapacity是否大于0,因为minCapacity是10,而oldCapacity是0,导致newCapacity是0,所以他们的值小于0。
  • 进入第一个if,将minCapacity赋值给newCapacity等于10.
  • 接下来,进行第二次判断,判断newCapacity是否大于MAX_ARRAY_SIZE的最大数组大小,数组的容量要重新计算。

  • 最后elementData数组分配的大小为10.

 ❗❗❗总结:

  • 在第一次调用add方法新增元素的时候,才会为ArrayList类当中的elementData数组分配内存,且大小为10.
  • 当后面新增元素,数组再满了的时候,他会以原数组大小的1.5倍扩容。


2.5、 在数组的某个位置新增元素

他的思想和我们在上一个博客当中写的思路是一样。

 2.6、删除数组当中的元素

他的思想和我们自己写的方法一致

remove方法,在这里稍微有一些特殊,我们想要删除数组中2元素,在我们自己写的remove方法中,要删某个元素,直接输入元素,在数组中找到就可以删除。

但是在源方法中,remove方法是重写的,他又两种删除方式

  •  第一种:通过找下标删除元素,调用这个方法时,传入的参数代表的是下标
  • 第二种:通过数组元素,找到对应的下标,删除该元素,调用这个方法时,传入的参数代表的是元素。

❗❗❗在这里我们要说一个知识点,在实例化类的时候,指定的类型Integer,Character等都是类类型。在第一次新增元素的时候,将1放入到ArrayList数组当中的时候,发生了装箱操作

public class Test {
    public static void main(String[] args) {
    ArrayList<Integer> arrayList1 = new ArrayList<>();
//第一次新增元素的时候,由于Integer是类类型,将1放入到数组当中的时候发生了,装箱的操作
        arrayList1.add(1);
        arrayList1.add(1,10);
        System.out.println(arrayList1);
    }
}

当要删1的时候,就要这样来写

public class Test {
    public static void main(String[] args) {
    ArrayList<Integer> arrayList1 = new ArrayList<>();
//第一次新增元素的时候,由于Integer是类类型,将1放入到数组当中的时候发生了,装箱的操作
        arrayList1.add(1);
        arrayList1.add(1,10);
        arrayList1.remove(new Integer(1));//实例化一个Integer类,找到这个类型的对象
        System.out.println(arrayList1);
    }
}

2.7、 get方法

 2.8、clear方法(置空)

2.9、 截取数组部分内容(subList)

 

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>( );
        arrayList1.add(11);
        arrayList1.add(12);
        arrayList1.add(13);
        arrayList1.add(14);
        arrayList1.add(15);
        arrayList1.add(16);
        List<Integer> sub = arrayList1.subList(1,3);//截取1下标到3下标的元素
        System.out.println(sub);
        sub.set(0,888);//修改截取数组的0下标元素为888.
        System.out.println(sub);
        System.out.println(arrayList1);
    }
}

 ❗❗❗总结:

subList方法截取数组的某一部分,实际上是将elementData数组的1下标给了sub引用,实际上,sub引用和arrayList1引用指向同一个数组,所以通过sub修改0下标的值,也就修改了elementData数组的1下标元素。


 2.9、ArrayList的遍历输出

在上述的代码中,我们通过System.out.println();直接输出引用sub和arrayList1所指向的对象,

理论上引用sub应该存储arrayList1.subList()的地址,怎么通过System.out.println(sub)输出的呢?

  • 说明ArrayList类一定是重写了toString方法。
  • 但是通过查找ArrayList类当中没有找到toString方法。
  • 由于ArrayList类是继承了父类的,ArrayList继承了父类的方法,我们可以看他的父类当中有没有toString方法。
  • 最终在他父类的父类AbstractCollection当中找到了toString方法。

📕这是第一种遍历方式,可以通过 System.out.println();直接输出。

📕第二种方式:可以通过for循环输出。

public class Test {
    public static void main(String[] args) {
        ArrayList<Integer> arrayList1 = new ArrayList<>( );
        arrayList1.add(11);
        arrayList1.add(12);
        arrayList1.add(13);
        arrayList1.add(14);
        arrayList1.add(15);
        arrayList1.add(16);
        System.out.println("============");
        for (int i = 0; i < arrayList1.size(); i++) {
            System.out.print(arrayList1.get(i)+" ");//加空格,尚在输出的时候数字之间可以隔开
        }
        System.out.println();

       

        for(Integer x:arrayList1){
            System.out.print(x+" ");
        }
        System.out.println();

📕第三种方式:迭代器

        ListIterator<Integer> it = arrayList1.listIterator();
        while(it.hasNext()){
            System.out.print(it.next()+" ");
        }
        System.out.println();

 ❗❗❗总结:

常用的遍历输出,是第一种和第二种输出方式,迭代器用的很少,迭代器会用就行。


3、来看一道面试题

给出两个字符串

s1:"welcome  to  world"

s2:"come"

要求删除s1当中的字符,这些字符都是s2中出现的。

删完之后s1:只剩wl  t  bit.

public class Test {
    public static void main(String[] args) {
        ArrayList<Character> list = new ArrayList<>();
        String s1 = "welcome to bit";
        String s2 = "come";
        for (int i = 0; i < s1.length(); i++) {
            char ch = s1.charAt(i);//多次循环,将s1当中的每个字符存入ch中
            if(!s2.contains(ch+"")){//判断s2中不包含ch当中的这个字符
                list.add(ch);//将s2中不包含的字符,放入ArrayList类当中elementData数组中
            }
        }
        //这里是为了让输出的结果更加美观
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i));
        }
    }

 ❓❓❓上述代码中,出现了一个小问题若这样写,编译器会报错。  

 而String类,是实现了这个接口的

 所以我们在传参数的时候,最起码要传一个字符串类型的数据,不能传字符类型的数据。

📕第一种解决方式 

if(!s2.contains(ch+"")){//给字符拼接一个"",让ch当中的字符呈现的形式为"w"(字符串的形式)。

📗第二种解决方式 

可以直接使用valueOf方法来解决。这样也就满足了contains方法的参数类型实现了CharSequence接口

if(!s2.contains(valueOf(ch))){//valueOf方法的返回值是String类型的,满足了contains方法的 要求

4、杨辉三角 

给定一个非负整数numRows,生成【杨辉三角】的前numRows行。在【杨辉三角】中,每个数据是他左上方和右上方的数的和。

示例:

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

  这里了解一个知识点:

   List<List<Integer>>generate(int numRows){

他表示的意思是:集合类型表示的二维数组

❗❗代码的大致思路:

就是将row数组中的元素,通过[i][j] = [i-1][j]+[i-1][j-1]补齐,并将row数组放入到ret数组中。 

import java.util.ArrayList;
import java.util.List;

public class Test {
   List<List<Integer>>generate(int numRows){
       List<List<Integer>> ret = new ArrayList<>();//这里实例化,相当于这个数组是ArrayList类型的,数组中的元素是List类型的,而数组元素指向的数组元素是Integer类型的
       //创建第一行数组
       List<Integer> row = new ArrayList<>();
       row.add(1);
       ret.add(row);//这里是让ret引用当中的数组,与row引用当中的数组产生联系
       for (int i = 0; i < numRows; i++) {//举例:调用这个方法者,想要3行,到2下标
           List<Integer> prevRow = ret.get(i-1);//获取前一行
           List<Integer> curRow = new ArrayList<>();
           curRow.add(1);//第一个1
           //中间curRow  list的赋值
           for (int j = 1; j < i; j++) {//j<i表示的意思是,当ret数组中第二个元素的时候,第二行row数组有俩个元素,ret数组当中第三个元素,第三行row数组有三个元素。
               int x = prevRow.get(j)+prevRow.get(j-1);
                curRow.add(x);
           }
           curRow.add(1);//最后一个1
           ret.add(curRow);//将最后一行的数组放到ret所引用的数组当中。
       }
        return ret;
   }

}

 


5、扑克牌游戏  

功能描述:

  • 抽象出扑克牌类。包括四种花色(黑桃、红心、梅花、方块),每种都有十三张牌(1-13,J,Q,K用11,12,13代替),不考虑大小王。
  • 创建一个游戏类,包含洗牌方法,生成扑克牌的方法,揭牌的方法
  • 要求:每人揭五张牌,没人一次只揭一张牌

代码实现:

1、扑克(Poker)类

package demo;

public class Poker {
    private String suit;//颜色
    private int rank;//数字

    public Poker(String suit, int rank) {
        this.suit = suit;
        this.rank = rank;
    }
//由于这个类当中的属性是用private分装起来的,所以给两个属性提供get和set方法。
    public String getSuit() {
        return suit;
    }

    public void setSuit(String suit) {
        this.suit = suit;
    }

    public int getRank() {
        return rank;
    }

    public void setRank(int rank) {
        this.rank = rank;
    }

    @Override
    public String toString() {
        return "{"+suit+" "+rank+"}";
    }
}

 2、游戏(Game)类

package demo;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Game {
    private static final String[] suits = {"♥","♠","♣","♦"};
    public List<Poker> buyPoker(){//生成52张扑克牌
        List<Poker> pokers = new ArrayList<>();//生成的牌要放在数组当中
        for (int i = 0; i < 4; i++) {//表示4中花色
            for (int j = 1; j <= 13; j++) {//每种花色都有13张牌,每种花色都从1开始。
                String suit = suits[i];//每次循环的花色
                int rank = j;//循环生成的牌的点数
                Poker poker = new Poker(suit,rank);//生成一张牌
                //牌这个对象放在pokers这个对象的数组中。
                pokers.add(poker);
            }
        }
        return pokers;
    }
    //洗牌
    public void shuffle(List<Poker> pokers){//这个方法只是将牌打乱。
        for (int i = pokers.size()-1; i > 0 ; i--) {
            Random random = new Random();//利用random生成随机数
            int index = random.nextInt(i);
            swap(pokers,i,index);
        }
    }
    private void swap(List<Poker> pokers,int i,int j){//数组元素交换方法
        Poker tmp = pokers.get(i);
        pokers.set(i,pokers.get(j));
        pokers.set(j,tmp);
    }
    //揭牌
    public List<List<Poker>> game(List<Poker> pokers){
        List<List<Poker>> hand = new ArrayList<>();//这里利用二维数组,让下边的三个手产生联系。
        List<Poker> hand1 = new ArrayList<>();
        List<Poker> hand2 = new ArrayList<>();
        List<Poker> hand3 = new ArrayList<>();
        hand.add(hand1);
        hand.add(hand2);
        hand.add(hand3);
        for (int i = 0; i < 5; i++) {//最外层控制揭牌的轮数
            for (int j = 0; j < 3; j++) {//控制揭牌的人数
                Poker removePoker = pokers.remove(0);//揭完之后,每次删除0下标位置元素。
                hand.get(j).add(removePoker);//每个人揭的牌,就是数组中删除的元素。
            }
        }
        return hand;
    }
}
  • 揭牌的方法中示例化三个ArrayList类,分别用List类型的hand1、2、3接收,这样写的好处是 :拿接口来接收,可以做到接受不同的对象,只要实现了这个接口的都可以。
  • 并且示例化一个ArrayList类,用 List<List<Poker>>类型的对象接收,实现一个二维数组。
  • 通过hand.add(hand1);这样的操作,让对象hand和hand1、2、3产生联系。

 

 

3、测试类

ackage demo;

import java.util.List;

public class Test {
    public static void main(String[] args) {
        Game game = new Game();
        List<Poker> pokers = game.buyPoker();
        System.out.println(pokers);
        //洗牌
        game.shuffle(pokers);
        System.out.println("洗牌");
        System.out.println(pokers);
        //揭牌
        List<List<Poker>> hand = game.game(pokers);
        System.out.println("揭牌");
        for (int i = 0; i < hand.size(); i++) {
            System.out.println("第 "+(i+1)+"个人的牌:"+hand.get(i));
        }
        System.out.println("剩下的牌:");
        System.out.println(pokers);
    }
}

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

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

相关文章

【Rust】18. Rust 的面向对象特性

18.1 面向对象语言的特征 18.1.1 对象&#xff1a;数据 行为 18.1.2 封装隐藏了实现细节 在 Rust 中&#xff0c;在代码中不同的部分考虑使用 pub 可以封装其实现细节 18.1.3 继承&#xff0c;作为类型系统与代码共享 在 Rust 中&#xff0c;不存在继承的机制&#xff0c;而…

【C++11】初始化列表、decltype操作符、nullptr

目录 一、初始化列表 1.1 花括号初始化 1.2 initializer_list 二、decltype 三、nullptr 一、初始化列表 1.1 花括号初始化 在C98中&#xff0c;标准允许使用花括号{ }对数组或结构体元素进行统一的列表初始值设定。 而在C11推出后&#xff0c;使用初始化列表时&#x…

java的方法使用

1.方法概述1.1什么是方法方法(method)是将具有独立功能的代码块组织成为一个整体&#xff0c;使其具有特殊功能的代码集注意&#xff1a;方法必须先创建才可以使用&#xff0c;该过程称为方法定义方法创建后并不是直接运行的&#xff0c;需要手动使用后才执行&#xff0c;该过程…

深入理解mysql性能优化以及解决慢查询问题

MySql系列整体栏目 内容链接地址【一】深入理解mysql索引本质https://blog.csdn.net/zhenghuishengq/article/details/121027025【二】深入理解mysql索引优化以及explain关键字https://blog.csdn.net/zhenghuishengq/article/details/124552080【三】深入理解mysql的索引分类&a…

GPT1、GPT2、GPT3原理

一 背景 GPT1:Generative Pre-Training。是一种生成式的预训练模型,由OpenAi团队发表自论文《Improving Language Understanding by Generative Pre-Training》。 h0=UWe+Wp 二 模型整体结构(宏观) 图1 GPT整体结构 左侧为模型的整体结构,由12个Transformer中的Decoder模块…

App的分类与简析

引言随着智能手机的普及&#xff0c;移动端应用几乎成为每个互联网产品的标配。在快速迭代的互联网战场中高效开发、低成本上线产品&#xff0c;是每个应用开发团队追求的目标。此时&#xff0c;选择合适的应用类型和开发模式便至关重要。移动应用可以粗分为三种&#xff1a;原…

Hystrix线程池隔离与接口限流

前面了解了Hystrix的请求缓存、fallback降级、circuit breaker断路器快速熔断,下面来看下Hystrix的线程池隔离与接口限流。 Hystrix通过判断线程池或者信号量是否已满,超出容量的请求,直接Reject走降级,从而达到限流的作用。限流是限制对后端服务的访问量,比如对MySQL、Re…

CentOS7 LVM 逻辑卷2种读写策略(磁盘IO性能优化)—— 筑梦之路

LVM 逻辑卷的读写策略有两种&#xff1a; linear&#xff1a;线性方式&#xff0c;一块块盘来读写&#xff0c;写完一块盘再写第二块盘、第 N 块盘&#xff0c;性能低striped&#xff1a;条带方式&#xff0c;多块盘一起并行读写&#xff0c;性能高查看 LVM 逻辑卷的读写策略的…

元宇宙,会成为下一代互联网的主场吗?

导语 | 2022 年元宇宙风靡全网&#xff0c;作为过去一年科技界的“当红扛把子”&#xff0c;引多家科技巨头“竞折腰”。近日&#xff0c;《福布斯》双周刊网站在报道中指出&#xff0c;2030 年全球元宇宙的市场规模有望高达 5 万亿美元&#xff0c;2023 年可能是确定其发展方向…

机器学习0 — 总体架构,chatgpt时代必须掌握的

1 从chatgpt看目前AI重要性 随着chatgpt的一声巨响&#xff0c;拉响了强人工智能的序幕。chatgpt相对于目前的各种机器人&#xff0c;简直就是弓箭和导弹的区别。沉寂了两三年后&#xff0c;AI如今又一次站在了人类工业的最高舞台。个人认为AI已经成为所有人&#xff0c;特别是…

vitest第二章(入门)

Vitest 是一个由 Vite 提供支持的极速单元测试框架 tips vite>3 node>14 安装 1.使用npm init -y 生成 package json 2.安装依赖 挑选一种即可 npm install -D vitestyarn add -D vitestpnpm add -D vitest3.新建一个文件calc.ts 开始第一个单元测试吧&#xff0c;…

【数据结构和算法】使用数组的结构实现链表(单向或双向)

上文我们通过结构体的结构实现了队列、以及循环队列的实现&#xff0c;我们或许在其他老师的教学中&#xff0c;只学到了用结构体的形式来实现链表、队列、栈等数据结构&#xff0c;本文我想告诉你的是&#xff0c;我们可以使用数组的结构实现链表、单调栈、单调队列 目录 前言…

2022最火科技~AIGC

2022年最火的信息科技~AIGC 人工智能内容生成 趣讲大白话&#xff1a;输入几个词&#xff0c;立刻生成机器创造的内容 ************** 从人工智能决策 走向 人工智能生成 人工智能决策&#xff1a;自动驾驶、抖音推荐算法 人工智能生成内容&#xff1a;即AI Generated Conten…

【算法练习】两个链表的第一个公共节点

描述输入两个无环的单向链表&#xff0c;找出它们的第一个公共结点&#xff0c;如果没有公共节点则返回空。&#xff08;注意因为传入数据是链表&#xff0c;所以错误测试数据的提示是用其他方式显示的&#xff0c;保证传入数据是正确的&#xff09;数据范围&#xff1a; 0n≤1…

下一代编解码技术Ali266在视频超高清领域的应用展望

超高清与各领域的需求融合和创新正在发生。 2022年是一个体育大年&#xff0c;众多世界级体育赛事通过视频直播、转播等形式给观众带来畅爽的观看体验。 2022年北京冬奥会&#xff0c;实现了奥运会历史上首次赛事全程4K制作播出&#xff0c;并在开幕式上提供了8K超高清公共信号…

安全多方计算之五:零知识证明(从入门到入土。。)

零知识证明1. 简介2. 零知识证明的例子2.1 向红绿色盲证明红球、绿球2.2 数独的零知识证明2.3 三染色问题的零知识证明2.4 Quisquater-Guillou 零知识协议3. ElGamal加密的零知识证明3.1 ElGamal加密的已知明文证明3.2 ElGamal加密的二选一零知识证明3.3 ElGamal加密的1-out-of…

MATLAB - 查找数据峰值

语法如下&#xff1a; pks findpeaks(data) [pks,locs] findpeaks(data) [pks,locs,w,p] findpeaks(data) [___] findpeaks(data,x) [___] findpeaks(data,Fs) [___] findpeaks(___,Name,Value) findpeaks(___)where&#xff0c;pks是峰值返回值&#xff0c;locs是数据索…

特斯拉 FSD 背后的技术(1)—从 BEV 到占用网络

在今年 tesla 的 AI Day 给我这个业余自动驾驶爱好者给留下了深刻印象&#xff0c;在看过之后&#xff0c;通过收集资料对其中阐述的技术进行简单的了解&#xff0c;在这里拿出来跟大家分享一下&#xff0c;有点长&#xff0c;所以划分了一下 3 个部分。从 BEV 到占用网络激进无…

chrome查看网页性能

1 Performance 1.1 打开开发者工具&#xff08;cmdshiftc&#xff09; 1.2 打开Performance面板&#xff0c;点击录制按钮&#xff08;开始录制&#xff09; 1.3 刷新页面&#xff0c;再次点击录制按钮&#xff08;结束录制&#xff09; 录制按钮高亮&#xff0c;表示录制中…

算法训练营DAY47|198.打家劫舍、213.打家劫舍II 、337.打家劫舍III

这一期到了打家劫舍的专题&#xff0c;说是专题但实际上只有一期&#xff0c;而且只有三道题&#xff0c;我们把这三道题放在一起讲&#xff0c;第一道题简单一些&#xff0c;后两道略有不同方向上的难度。但总体来看第一次做可能有一点难想到思路&#xff0c;其实代码实现还是…