ArrayList集合的两个实例应用,有趣的洗牌算法与杨辉三角

简介: ArrayList集合的两个实例应用,有趣的洗牌算法与杨辉三角



一、杨辉三角

这不是普通的杨辉三角,这是力扣里面的杨辉三角

1.题目详情及链接

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

有同学说,这里的题目也看不出跟ArrayList集合有鸡毛关系呀?我说,你别急,继续往下看

看到这里,你急了没有,题目给的类型是什么狗屎?这不就与ArrayList扯上关系了嘛,这到底是什么意思呢?接着往下看

2.剖析题目  

(1)题目的要求是根据参数,生成杨辉三角的前numRows行,并返回存放杨辉三角的空间

比如:numRows=3,就生成杨辉三角的前面3行;如果你用普通的二维数组存储,那就返回该二维数组的地址。

(2)剖析返回值

我们也应该可以猜到,List<List<Integer>>也是表示二维数组的意思

此时还不算完整的二维数组,List只是一个接口,需要实例化对象

(3)我们需要将这些数字放入该二维数组中

3.思路及代码

(1)思路解析

通过面向对象的思想来完成

第一步:分析杨辉三角的规律

题目要求生成杨辉三角的前numRows行,也就是可以一行一行生成

规律是显而易见的,除了第一行,其他每行的第一个元素和最后一个元素的值都是1;从第3行开始,中间的值与前一行的值紧密相连

第二步:创建二维数组并单独完成杨辉三角的第一行

不用担心测试用例一行都没有,1<=numRows<=30

List<List<Integer>> list = new ArrayList<>();
List<Integer> first = new ArrayList<>();
//先设置第一行的元素
first.add(1);
list.add(first);

核心思想:先单独建立一个一维的顺序表,存放好一行的元素,然后再将这个一维的顺序表当成一个元素放入二维的顺序表中,后面也是一样的思想

第三步:存放第二行及后面的元素

for (int i = 1; i < numRows; i++) {//每层循环代表一行
     List<Integer> ret = new ArrayList<>();//定义一个一维数组    
}

我们将在这个循环里面存放完成后续的行,如果只有一行,就不会进入这个循环内

第四步:分析如何将每一行存入

由前面分析知道,第二行开始,第一个和最后一个元素都是1,我们可以在前面和最后面存入1

for (int i = 1; i < numRows; i++) {//每层循环代表一行
            List<Integer> ret = new ArrayList<>();//定义一个一维数组
            //1.添加第一个元素
            ret.add(1);
            //2.设置中间元素,从第二列开始
           
            //3.添加最后元素
            ret.add(1);
            list.add(ret);//将每一行放入二维数组中
    }

然后中间的元素如何添加?第二行是没有中间元素的,而且中间的元素都是与前一行的元素有着紧密的关系,所以我们也需要考虑好。首先,我们需要从第二个位置开始存放;然后,第几行就说明那一行有多少个元素,就与行号绑定了关系

for (int i = 1; i < numRows; i++) {//每层循环代表一行
            List<Integer> ret = new ArrayList<>();//定义一个一维数组
            //1.添加第一个元素
            ret.add(1);
            //2.设置中间元素,从第二列开始
            for (int j = 1; j < i; j++) {
                //利用面向对象的思想,拿到元素
                int tmp = list.get(i-1).get(j)+list.get(i-1).get(j-1);
                ret.add(tmp);
            }
            //3.添加最后元素
            ret.add(1);
            list.add(ret);
        }

(2)完整代码

public List<List<Integer>> generate(int numRows) {
         List<List<Integer>> list = new ArrayList<>();
        List<Integer> first = new ArrayList<>();
        //先设置第一行的元素
        first.add(1);
        list.add(first);
        //从第二行开始
        for (int i = 1; i < numRows; i++) {//每层循环代表一行
            List<Integer> ret = new ArrayList<>();//定义一个一维数组
            //1.添加第一个元素
            ret.add(1);
            //2.设置中间元素,从第二列开始
            for (int j = 1; j < i; j++) {
                int tmp = list.get(i-1).get(j)+list.get(i-1).get(j-1);
                ret.add(tmp);
            }
            //3.添加最后元素
            ret.add(1);
            list.add(ret);
        }
        return list;
}

(3)总结一下思路

第一:将杨辉三角分成两个部分存储(第一行和第一行后面的

第二:存储第一行后面的时候,又分成三部分存储(第一个元素、中间部分元素、最后一个元素)

第三:存储中间部分元素时,通过与前一行的元素的关系进行存储(利用面向对象的思想获得前一行的元素)

二、洗牌算法

其实,洗牌算法就是ArrayList的一种应用,或者运用,没有那么的高大尚,下面简单介绍洗牌算法的一些基本功能和流程

下面是程序运行起来的结果:

什么是洗牌算法?

(1)使用类和对象的知识定义一个牌对象

(2)创造出一副排序好的牌,存储在ArrayList中(有牌)

(3)然后将这些牌的顺序打乱(洗牌)

(4)将洗乱的牌随机分发给三个人(发牌)

下面开始讲解洗牌算法

1.创造牌对象

牌这个对象的属性有两个:第一是花色,第二就是号码;然后我们提供一下构造方法,在创建每一张牌的时候就赋值;最后,重写一下toString方法,用来打印牌。

public class Card {
    //用来定义一张牌
    public String suit;//牌的花色
    public int num;//号码
    public Card(String suit, int num) {
        this.suit = suit;
        this.num = num;
    }
    @Override
    public String toString() {
       return suit+num;
    }
}
2.创造一副牌

main函数,用来实例化对象,和调用对象中的方法(创造牌的方法)

public static void main(String[] args) {
        PlayCard game = new PlayCard();
        System.out.println("设置牌:");
        List<Card> cards = game.setCard();
        System.out.println(cards);
}

创建一个类,用来表示玩牌的游戏,里面存放创建牌、洗牌和发牌的操作

public class PlayCard {
    
    public static final String[] suits = {"?","?","?","?"};//定义花色的数组
    //1.设置牌操作
    public List<Card> setCard() {
        List<Card> cards = new ArrayList<>();//定义一个数组,用来存放所有牌
        for (int i = 0; i < 4; i++) {//每次循环代表一个花色
            for (int j = 1; j <=13 ; j++) {//13个号码
                String suit = suits[i];//获得一个花色
                Card card = new Card(suit,j);//定义一个牌对象并赋值
                cards.add(card);//将牌放入一个牌数组中
            }
        }
        return cards;//返回一副牌
    }
}

(1)这是一个带返回值的函数。

(2)第一层循环,代表花色;第二层循环代码号码;每循环一次:拿到一个花色和号码,然后将这两个赋值给牌对象,并将牌放入ArrayList集合中(cards)

(3)最后将这个集合返回(接收返回值就拿到了返回值)

3.洗牌操作

这里先把上一阶段创造牌的操作隐藏,独将洗牌操作

这里洗牌的思想是:(1)从后面遍历这副牌,每张牌都随机与前面某一张牌交换

(2)获得前面随机牌使用产生随机数种子

(3)交换则单独包装成一个方法

public class PlayCard {
    //在这里类里面操作牌:设置牌,洗牌和发牌
    public static final String[] suits = {"?","?","?","?"};//定义花色的数组
    //1.设置牌操作
   //这里介绍洗牌操作,所以设置牌的操作就省略了
    //2.洗牌操作
    public void shuffle(List<Card> cards) {
        Random random = new Random();
        for (int i = 51; i > 0; i--) {
            int index  = random.nextInt(i);//随机获取一个牌下标与i下标的牌交换
            swap(cards,i,index);
        }
        //return cards;
    }
    private static void swap(List<Card> cards,int i,int j) {
        //交换两张牌
        Card tmp = cards.get(i);
        cards.set(i,cards.get(j));
        cards.set(j,tmp);
    }
}
4.发牌操作

同样的,我们把前面创造牌和洗牌的操作隐藏起来,单独介绍发牌操作

我们发牌的思路是:(1)有三个人轮流接牌,每次接一张,一共接五轮(2)每个人随机接牌,每拿到一张牌,就从这副牌中删除(3)每个人拿到五张牌,每个人看作一个一维数组;要保存三个人的牌,就需要一个二维数组。

public class PlayCard {
    //在这里类里面操作牌:设置牌,洗牌和发牌
    public static final String[] suits = {"?","?","?","?"};//定义花色的数组
    //1.设置牌操作
  
    //2.洗牌操作
  
    //3.发牌操作
    public List<List<Card>> getCard(List<Card> cards) {
        //定义三个对象,存取牌
        List<Card> hand1 =new ArrayList<>();
        List<Card> hand2 =new ArrayList<>();
        List<Card> hand3 =new ArrayList<>();
        //定义一个二维数组,存取三个对象
        List<List<Card>> hand = 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++) {
              Card card = cards.remove(0);//每次拿到第一张牌,并从数组中删掉
              //放入每个人手中
              hand.get(j).add(card);
            }
        }
        return hand;
    }
}

(1)用三个一维的集合代表三个一维数组 (2)再定义一个集合,存放三个一维集合 (3)第一层循环,每循环一次就是一张牌;第二层循环就是每个人轮流拿牌 (4) hand.get(j)代表第几个人,add(card)代表把这张牌给某个人

完整代码:

public static void main(String[] args) {
        PlayCard game = new PlayCard();
        System.out.println("设置牌:");
        List<Card> cards = game.setCard();
        System.out.println(cards);
        System.out.println("洗牌后:");
        game.shuffle(cards);
        System.out.println(cards);
        System.out.println("发牌:");
        List<List<Card>> hand = game.getCard(cards);
        for (int i = 0; i < 3 ; i++) {
            System.out.println("第"+(i+1)+"个人的牌为:"+hand.get(i));
        }
        System.out.println("剩余的牌为:");
        System.out.println(cards);
    }
public class Card {
    //用来定义一张牌
    public String suit;//牌的花色
    public int num;//号码
    public Card(String suit, int num) {
        this.suit = suit;
        this.num = num;
    }
    @Override
    public String toString() {
       return suit+num;
    }
}
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
public class PlayCard {
    //在这里类里面操作牌:设置牌,洗牌和发牌
    public static final String[] suits = {"?","?","?","?"};//定义花色的数组
    //1.设置牌操作
    public List<Card> setCard() {
        List<Card> cards = new ArrayList<>();//定义一个数组,用来存放所有牌
        for (int i = 0; i < 4; i++) {//四种花色
            for (int j = 1; j <=13 ; j++) {//13个号码
                String suit = suits[i];//获得一个花色
                Card card = new Card(suit,j);//定义一个牌对象并赋值
                cards.add(card);//将牌放入一个牌数组中
            }
        }
        return cards;//返回一副牌
    }
    //2.洗牌操作
    public void shuffle(List<Card> cards) {
        Random random = new Random();
        for (int i = 51; i > 0; i--) {
            int index  = random.nextInt(i);//随机获取一个牌下标与i下标的牌交换
            swap(cards,i,index);
        }
        //return cards;
    }
    private static void swap(List<Card> cards,int i,int j) {
        //交换两张牌
        Card tmp = cards.get(i);
        cards.set(i,cards.get(j));
        cards.set(j,tmp);
    }
    //3.发牌操作
    public List<List<Card>> getCard(List<Card> cards) {
        //定义三个对象,存取牌
        List<Card> hand1 =new ArrayList<>();
        List<Card> hand2 =new ArrayList<>();
        List<Card> hand3 =new ArrayList<>();
        //定义一个二维数组,存取三个对象
        List<List<Card>> hand = 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++) {
              Card card = cards.remove(0);//每次拿到第一张牌,并从数组中删掉
              //放入每个人手中
              hand.get(j).add(card);
            }
        }
        return hand;
    }
}

本节的内容就是介绍ArrayList集合的用法,可以当成一维数组,也可以当成二维数组。看到这里本机就结束了,快趁着这个感觉去刷题吧!

相关文章
|
5天前
|
机器学习/深度学习 数据采集 自然语言处理
理解并应用机器学习算法:神经网络深度解析
【5月更文挑战第15天】本文深入解析了神经网络的基本原理和关键组成,包括神经元、层、权重、偏置及损失函数。介绍了神经网络在图像识别、NLP等领域的应用,并涵盖了从数据预处理、选择网络结构到训练与评估的实践流程。理解并掌握这些知识,有助于更好地运用神经网络解决实际问题。随着技术发展,神经网络未来潜力无限。
|
5天前
|
算法 Python
利用贝叶斯算法对简单应用实现预测分类
利用贝叶斯算法对简单应用实现预测分类
6 0
|
5天前
|
机器学习/深度学习 算法 API
【Paddle】PCA线性代数基础 + 领域应用:人脸识别算法(1.1w字超详细:附公式、代码)
【Paddle】PCA线性代数基础 + 领域应用:人脸识别算法(1.1w字超详细:附公式、代码)
9 0
|
5天前
|
机器学习/深度学习 数据采集 算法
深入理解并应用机器学习算法:支持向量机(SVM)
【5月更文挑战第13天】支持向量机(SVM)是监督学习中的强分类算法,用于文本分类、图像识别等领域。它寻找超平面最大化间隔,支持向量是离超平面最近的样本点。SVM通过核函数处理非线性数据,软间隔和正则化避免过拟合。应用步骤包括数据预处理、选择核函数、训练模型、评估性能及应用预测。优点是高效、鲁棒和泛化能力强,但对参数敏感、不适合大规模数据集且对缺失数据敏感。理解SVM原理有助于优化实际问题的解决方案。
|
5天前
|
机器学习/深度学习 算法
理解并应用机器学习算法:决策树
【5月更文挑战第12天】决策树是直观的分类与回归机器学习算法,通过树状结构模拟决策过程。每个内部节点代表特征属性,分支代表属性取值,叶子节点代表类别。构建过程包括特征选择(如信息增益、基尼指数等)、决策树生成和剪枝(预剪枝和后剪枝)以防止过拟合。广泛应用在信贷风险评估、医疗诊断等领域。理解并掌握决策树有助于解决实际问题。
|
5天前
|
机器学习/深度学习 算法
应用规则学习算法识别有毒的蘑菇
应用规则学习算法识别有毒的蘑菇
|
5天前
|
存储 机器学习/深度学习 算法
R语言贝叶斯Metropolis-Hastings采样 MCMC算法理解和应用可视化案例
R语言贝叶斯Metropolis-Hastings采样 MCMC算法理解和应用可视化案例
|
5天前
|
算法 数据安全/隐私保护 计算机视觉
基于二维CS-SCHT变换和LABS方法的水印嵌入和提取算法matlab仿真
该内容包括一个算法的运行展示和详细步骤,使用了MATLAB2022a。算法涉及水印嵌入和提取,利用LAB色彩空间可能用于隐藏水印。水印通过二维CS-SCHT变换、低频系数处理和特定解码策略来提取。代码段展示了水印置乱、图像处理(如噪声、旋转、剪切等攻击)以及水印的逆置乱和提取过程。最后,计算并保存了比特率,用于评估水印的稳健性。
|
1天前
|
算法
m基于BP译码算法的LDPC编译码matlab误码率仿真,对比不同的码长
MATLAB 2022a仿真实现了LDPC码的性能分析,展示了不同码长对纠错能力的影响。短码长LDPC码收敛快但纠错能力有限,长码长则提供更强纠错能力但易陷入局部最优。核心代码通过循环进行误码率仿真,根据EsN0计算误比特率,并保存不同码长(12-768)的结果数据。
20 9
m基于BP译码算法的LDPC编译码matlab误码率仿真,对比不同的码长
|
3天前
|
算法
MATLAB|【免费】融合正余弦和柯西变异的麻雀优化算法SCSSA-CNN-BiLSTM双向长短期记忆网络预测模型
这段内容介绍了一个使用改进的麻雀搜索算法优化CNN-BiLSTM模型进行多输入单输出预测的程序。程序通过融合正余弦和柯西变异提升算法性能,主要优化学习率、正则化参数及BiLSTM的隐层神经元数量。它利用一段简单的风速数据进行演示,对比了改进算法与粒子群、灰狼算法的优化效果。代码包括数据导入、预处理和模型构建部分,并展示了优化前后的效果。建议使用高版本MATLAB运行。
http://www.vxiaotou.com