Java楊輝三角、洗牌算法詳細(xì)示例代碼
一、楊輝三角
給定一個(gè)非負(fù)數(shù)numRows,生成楊輝三角的前 numRows 行。
在楊輝三角中,每個(gè)數(shù)是它左上方和右上方的數(shù)之和。
示例:輸入:numRows = 5
輸出: [ [1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1] ]
思路:使用二維數(shù)組 的思路,使用列表的思路創(chuàng)建二維數(shù)組,定義行和列。

我們說過要用List列表的思路去創(chuàng)建二維數(shù)組:

示例:可以往這個(gè)列表中添加元素,只不過這個(gè)元素是一個(gè)個(gè)實(shí)例化的對(duì)象(傳遞的參數(shù)是一個(gè)泛型類,那么它也需要明確傳遞的參數(shù)類型,因此需要實(shí)例化對(duì)象),證明是一個(gè)二維數(shù)組:

輸出結(jié)果:

那么,具體如何向這個(gè)二維數(shù)組存放具體的元素呢?
—— 前面說過,傳遞的參數(shù)是一個(gè)泛型類,因此需要實(shí)例化對(duì)象,但是不可以這樣:

那么我們可以單獨(dú)將列表每個(gè)實(shí)例化的元素寫出來,往這一個(gè)個(gè)元素中,使用add方法添加元素,然后再將這些實(shí)例化的對(duì)象的引用傳遞給列表:

輸出結(jié)果:

我們也可以通過調(diào)試觀察:

前面的準(zhǔn)備知識(shí)學(xué)習(xí)完后,我們正式開始寫楊輝三角:
使用 [i][j] = [i-1][j-1] + [i-1][j-1] 的思路。

寫一個(gè)方法 generate ,它的返回值是List<LIst<Integer>>,在方法中,我們首先處理第一行,因?yàn)闂钶x三角的第一行只有一個(gè)元素,那就是1,因此,我們先處理第一行,將這一行的元素先添加到列表中;然后從第二行開始,進(jìn)行求每一個(gè)元素(使用前面的公式),由于楊輝三角的每一行的第一個(gè)元素和最后一個(gè)元素都是1,于是也可以直接添加,從每一行的第二個(gè)元素開始求,也就是中間的這些位置:根據(jù)公式,需要先求該行的前一行的元素信息,然后利用這些信息進(jìn)行該行的元素求解;最后返回列表。
public class Test {
public static List<List<Integer>> generate(int numRows) {
List<List<Integer>> ret = new ArrayLIst<>();
//處理第一行
List<Integer> list0 = new ArrayList<>();
list0.add(1);
ret.add(list0);
//從第2行開始 進(jìn)行求元素
for(int i = 1;i < numRows; i++) {
//處理第一個(gè)元素
List<Integer> curRow = new ArrayList<>();
curRow.add(1);
//中間
//從第二個(gè)元素開始求元素
List<Integer> preRow = ret.get(i-1);//前一行
for(int j = 1;j < i; j++) {
//[i][j] = [i-1][j-1] + [i-1][j-1]
int val1 = preRow.get(j);
int val2 = preRow.get(j-1);
ret.add(val1 + val2);
}
//尾巴
curRow.add(1);
ret.add(curRow);
}
return ret;
}
public static void main(String[] args) {
List<List<Integer>> list = new ArrayList<>();
List<List<Integer>> ret = generate(4);
for(int i = 0;i < ret.size(); i++) {
for(int j = 0;j < ret.get(i).size(); j++) {
System.out.print(ret.get(i).get(j) + " ");
}
System.out.println();
}
}
}輸出結(jié)果:

二、洗牌算法
要完成洗牌,有三個(gè)步驟:
- 1.買撲克牌 52張牌
- 2.洗牌
- 3.設(shè)有3個(gè)人,每個(gè)人輪流揭5張牌
1.Card類——描述一副牌的組成
首先我們寫一個(gè)類Card,用來描述買來的一副牌的組成:
public class Card {
private String suit;//花色
private int rank;//牌面值
//構(gòu)造方法
public Card(String suit,int rank) {
this.suit = suit;
this.rank = rank;
}
//重寫toSTring
public void toString() {
return "{" + suit + rank + "}";
}
}2.CardDemo類——完成買牌、洗牌等操作
然后再寫一個(gè)類CardDemo,在這個(gè)類中,完成買牌、洗牌等一些列事情;一副牌中,包括四種花色,分別是紅心、方塊、梅花和黑桃,每種花色有13張牌,總計(jì)52張牌。
因此,我們可以先定義一個(gè)字符串?dāng)?shù)組,數(shù)組內(nèi)存放四種花色牌,各一張,由于這四種花色是固定不變的,可以寫成一個(gè)常量數(shù)組(final修飾);
然后寫一個(gè) buyCard 方法,它的返回值是List<Card>,表示買牌的動(dòng)作,在這個(gè)方法中:先實(shí)例化一個(gè)Card類對(duì)象,然后通過for循環(huán)嵌套將各個(gè)花色的所有牌放入對(duì)象中(每個(gè)花色的牌各有13張,一樣的牌各有4張),最后通過add方法添加到Card類對(duì)象中。
注意:該方法的返回值是一個(gè)泛型類,它的參數(shù)是一個(gè)Card類類型,因此,需要實(shí)例化Card類對(duì)象,這里每添加一個(gè)花色牌就利用Card的構(gòu)造方法初始化一下suit和rank,最后將這個(gè)Card類型引用作為參數(shù)傳遞給泛型類。
public class CardDemo {
public static final String[] suits = {"?","?","?","?"};
//買一副牌
public List<Card> buyCard() {
List<Card> cardList = new ArrayList<>();
for(int i = 1;i <= 13; i++) {
for(int j = 0;j < 4; j++) {
int rank = i;
String suit = suits[j];
Card card = new Card(suit,rank);
cardList.add(card);
}
}
return cardList;
}
}接著寫一個(gè) shuffle 方法,表示洗牌的動(dòng)作,在這個(gè)方法中,我們需要做的就是打亂牌的順序,即洗牌。這里需要用到一個(gè)類——Random,這個(gè)類中的一個(gè) nextInt 方法,用于生成一個(gè)隨機(jī)數(shù)值,該方法的有兩種使用方式:
- nextInt():生成一個(gè)隨機(jī)的 int 值,范圍是所有可能的 int 值
- nextInt(int bound):生成一個(gè)在 [0, bound) 范圍內(nèi)的隨機(jī) int 值,包含 0 但不包含 bound
而我們此時(shí)需要用的是第2種方式。
寫一個(gè)for循環(huán),初始條件從最后一張牌開始,在這個(gè)循環(huán)中,使用random.nextInt() 方法,每次將隨機(jī)生成的數(shù)值和最后一張牌進(jìn)行隨機(jī)交換,比如,有52張牌,它們對(duì)應(yīng)下標(biāo)是0~51,對(duì)這副牌進(jìn)行洗牌,從最后一張牌開始進(jìn)入循環(huán),通過random.nextInt(51)生成0~50之間的隨機(jī)牌,讓最后一張牌,即第52張牌與隨機(jī)的一張牌進(jìn)行位置交換,接著是通過random.nextInt(50)生成0~49之間的隨即牌,再將此時(shí)的最后一張牌與隨機(jī)牌位置交換,直到全部牌交換完成,就完成了洗牌的動(dòng)作。
注意:循環(huán)繼續(xù)直到i > 0,當(dāng)i變成0時(shí),循環(huán)停止。這是因?yàn)楫?dāng)i=0時(shí),只有一個(gè)元素 left,不需要交換自己。
而位置交換的動(dòng)作則寫一個(gè) swap 方法來完成:按照之前寫swap方法的思路:
- Card tmp = cardLIst[i];
- cardList[i] = cardList[j];
- cardList[j] = tmp;
但是這樣寫是不行的,cardList引用的類型是List<Card>泛型類,并不是一個(gè)數(shù)組,不可以使用數(shù)組下標(biāo)運(yùn)算符[],對(duì)于List<Card>類,應(yīng)該使用 get() 和 set() 方法來代替進(jìn)行位置交換操作。
public void shuffle(List<Card> cardList) {
Random random = new Random();
for(int i = cardList.size()-1;i > 0; i--) {
int index = random.nextInt(i);
swap(cardList,i,index);
}
}
public void swap(List<Card> cardList,int i,int j) {
Card tmp = cardList.get(i);
cardList.set(i,cardList.get(j));
cardList.set(j,tmp);
}最后寫一個(gè)輪流揭牌的方法 play ,假設(shè)有3個(gè)人,每個(gè)人要揭5張牌,那么每個(gè)人的5張牌要如何存放呢?—— 3個(gè)人各自實(shí)例化一個(gè)List泛型類,將各自的牌存放在各自的引用對(duì)象中;使用for循環(huán)嵌套,進(jìn)行輪流揭牌,每次揭玩一張牌,牌就會(huì)少一張,使用remove方法,每次揭玩一張牌就刪除最上面的那張牌,即下標(biāo)為0的那張牌。
問題:如何將對(duì)應(yīng)的牌放到對(duì)應(yīng)的人手里呢?
—— 使用二維數(shù)組。
public <List<Card>> play(List<Card> cardList) {
List<Card> hand0 = new ArrayList<>();
List<Card> hand1 = new ArrayList<>();
List<Card> hand2 = new ArrayList<>();
List<List<Card>> hand = new ArrayList<>();
hand.add(hand0);
hand.add(hand1);
hand.add(hand2);
for(int i = 0;i < 5; i++) {
for(int j = 0;j < 3; j++) {
Card card = cardList.remove(0);
hand.get(j).add(card);//比如:hand.hand0.add(card);
}
}
return hand;
}3.完整代碼
//Card類
public class Card {
private String suit;
private int rank;
public Card(String suit,int rank) {
this.suit = suit;
this.rank = rank;
}
public void toString() {
return "{" + suit + rank + "}";
}
}//CardDemo類
public class CardDemo {
public static final String[] suits = {"?","?","?","?"};
//買一副牌
public List<Card> buyCard() {
List<Card> cardList= new ArrayList<>();
for(int i = 1;i <= 13; i++) {
for(int j = 0;j < 4; j++) {
int rank = i;
String suit = suits[j];
Card card = new Card(suit,rank);
cardList.add(card);
}
}
return cardList;
}
//洗牌
public void shuffle(List<Card> cardList) {
Random random = new Random();
for(int i = cardList.size()-1;i > 0; i--) {
int index = random.nextInt(i);
swap(cardList,i,index);
}
}
public void swap(List<Card> cardList,int i,int j) {
Card tmp = cardList.get(i);
cardList.set(i,cardList.get(j));
cardList.set(j,tmp);
}
//3個(gè)人,輪流揭5張牌
public List<List<Card>> play(List<Card> cardList) {
List<Catd> hand0 = new ArrayList<>();
List<Card> hand1 = new ArrayList<>();
List<Card> hand1 = new ArrayList<>();
List<List<Card>> hand = new ArrayList<>();
for(int i = 0;i < 5; i++) {
for(int j = 0;j < 3; j++) {
Card card = cardList.remove(0);
hand.get(j).add(card);
}
}
return hand;
}
}4.測(cè)試
public class Test {
public static void main(String[] args) {
CardDemo cardDemo = new CardDemo();
//買一副牌
System.out.println("洗牌前:");
List<Card> cardList = cardDemo.buyCard();
System.out.println(cardList);
//洗牌
System.out.println("洗牌后:");
cardDemo.shuffle(cardList);
System.out.println(cardList);
//3個(gè)人輪流揭5張牌
System.out.println("抽牌:");
List<List<Card>> ret = cardDemo.play(cardList);
for(int i = 0;i < ret,size(); i++) {
System.out.println("第"+(i+1)+"個(gè)人的牌:"+ret.get(i));
}
System.out.println("剩下的牌:");
System.out.println(cardList);
}
}輸出結(jié)果:

總結(jié)
到此這篇關(guān)于Java楊輝三角、洗牌算法的文章就介紹到這了,更多相關(guān)Java楊輝三角、洗牌算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
springboot實(shí)現(xiàn)跨域的五種方式總結(jié)
在Spring Boot中實(shí)現(xiàn)跨域,可以采用全局跨域和局部跨域兩種方式,下面這篇文章主要給大家介紹了關(guān)于springboot實(shí)現(xiàn)跨域的五種方式,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01
Spring MVC創(chuàng)建項(xiàng)目踩過的bug
這篇文章主要介紹了Spring MVC創(chuàng)建項(xiàng)目踩過的bug,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Mybatis-plus配置分頁插件返回統(tǒng)一結(jié)果集
本文主要介紹了Mybatis-plus配置分頁插件返回統(tǒng)一結(jié)果集,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06
Java實(shí)現(xiàn)ATM機(jī)操作系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)ATM機(jī)操作系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
springBoot熱部署、請(qǐng)求轉(zhuǎn)發(fā)與重定向步驟詳解
這篇文章主要介紹了springBoot熱部署、請(qǐng)求轉(zhuǎn)發(fā)與重定向,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06
java中的char占幾個(gè)字節(jié)實(shí)例分析
這篇文章主要介紹了java中的char占幾個(gè)字節(jié)實(shí)例分析的相關(guān)資料,需要的朋友可以參考下2017-04-04

