2019.06.24

同じ数の組み合わせ

同じ数の見つけ方

ここでは、整数型の配列の中に、同じ値の数値が何種類あるか求める方法を紹介しています。

例えば、配列に格納されている値が、

{ 0、0、7、0、7 }

の場合、

0、7

の2種類の数字が配列に格納されているので、が同じ数の組み合わせ数となります。

他の例で、配列に格納されている値が、

{ 3、3、6、2、1、3 }

の場合、

1、2、3、6

の4つの種類の数字が配列に格納されているので、が同じ数の組み合わせ数となります。

ここで紹介するプログラムは配列昇順ソート(降順でも良い)を使って同じ値を配列の中で連続に並べた後、配列の先頭から後方に向けて順番に値の変化を見ていき、値が変わった数を数えれば、その数が組み合わせの数となります。

例えば、以下の配列昇順ソートすると、

{ 0、0、7、0、7 }
	↓昇順ソート
{ 0、0、0、7、7 }

となり、0が3個、7が2個連続に並んだことが分かります。

同様に、以下の配列昇順ソートすると、

{ 3、3、6、2、1、3 }
	↓昇順ソート
{ 1、2、3、3、3、6 }

となり、1が1個、2が1個、3が3個、6が1個連続に並んだことが分かります。

このようにソートされた配列で、配列の1つ前の値と違った場合の個数を数えることで数の種類を得ることができます。このとき、配列の先頭の値は1つ前の値と違うと判定します。

{ 0、0、0、7、7 }の場合、{ 、0、0、、7 }のように先頭の"0"と4番目の"7"が、1つ前の値と違う箇所になります。この場合、2箇所違ったので2種類です。

{ 1、2、3、3、3、6 }の場合、{ 、3、3、 }のように先頭の"1"と2番目の"2"、3番目の"3"、6番目の"6"が1つ前の値と違う箇所になります。この場合、4箇所違ったので4種類です。

それでは、ここから上記の内容のJavaソースコードを見ていきましょう。

Javaソースコード

NumberCombo1.java

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
import java.util.Arrays;

public class NumberCombo1 {
	// 数の組み合わせ数を取得
	public static int numberCombo( int[] ary )
	{
		int nc;		// 組み合わせ数
		int prenum;	// 1つ前の番号
		int[] tempary;	// 作業用の配列

		// aryがnullなら0を戻す
		if ( null == ary ) return 0;

		// aryの数が0以下ならaryの数を戻す
		if ( 1 >= ary.length ) return ary.length;

		// 元の配列の順番を変えないように配列をコピー
		tempary = array_copy( ary );

		// 昇順ソート
		Arrays.sort( tempary );

		// 組み合わせの数の取得処理
		// 組み合わせ数の初期値を代入
		nc = 1;
		prenum = tempary[ 0 ];
		// 処理本体
		for ( int i = 1; i < tempary.length; ++ i )
		{
			// 1つ前の値と一致しなければ
			if ( prenum != tempary[ i ] ) {
				// 組み合わせの数を増やす
				++ nc;
				prenum = tempary[ i ];
			}
		}

		// 結果を戻す
		return nc;
	}


	// 配列をコピー作成するメソッド
	private static int[] array_copy( int[] srcary )
	{
		// 元の配列srcaryの要素数でint配列desaryを作成
		int[] desary = new int[ srcary.length ];

		// 配列desaryにsrcaryの値を代入
		for ( int i = 0; i < srcary.length; ++ i ) {
			desary[ i ] = srcary[ i ];
		}

		// 作成した配列desaryを戻す
		return desary;
	}


	// メイン
	public static void main( String[] args ) {
		// 組み合わせ数
		int nc;

		// 配列aを宣言
		int[] a;

		// 要素数10を設定
		a = new int[ 10 ];

		// 値を代入
		a[ 0 ] = 0;
		a[ 1 ] = 5;
		a[ 2 ] = 5;
		a[ 3 ] = 1;
		a[ 4 ] = 3;
		a[ 5 ] = 0;
		a[ 6 ] = 5;
		a[ 7 ] = 2;
		a[ 8 ] = 6;
		a[ 9 ] = 7;

		// 組み合わせ数を取得 (0,1,2,3,5,6,7)の7種類
		nc = numberCombo( a );

		// 結果を表示
		System.out.println( "同じ数の組み合わせ:" + nc );
	}
} 

コンパイル ソースコードが「ANSI」の場合

C:\talavax\javasample>javac -encoding sjis NumberCombo1.java

コンパイル ソースコードが「UTF-8」の場合

C:\talavax\javasample>javac NumberCombo1.java

実行

C:\talavax\javasample>java NumberCombo1

実行結果

同じ数の組み合わせ:7

int型配列に格納している値は、0,1,2,3,5,6,7の7種類です。

Javaソースコードの解説

ここから、ソースコードについて解説してきます。

003
public class NumberCombo1 {

クラス名を、NumberCombo1としています。

004
005
006
	// 数の組み合わせ数を取得
	public static int numberCombo( int[] ary )
	{

public static int numberCombo( int[] ary )がint型配列に含まれる数値の種類を取得するメソッドです。

007
008
009
		int nc;		// 組み合わせ数
		int prenum;	// 1つ前の番号
		int[] tempary;	// 作業用の配列

同じ数の組み合わせを取得するために使う変数を宣言しています。

011
012
		// aryがnullなら0を戻す
		if ( null == ary ) return 0;

int型配列aryが初期化されていない場合、0を戻しています。

014
015
		// aryの数が0以下ならaryの数を戻す
		if ( 1 >= ary.length ) return ary.length;

int型配列aryの要素数が1以下の場合は、その要素数を戻しています。要素数が1の場合、数の組み合わせは1で確定です。

017
018
		// 元の配列の順番を変えないように配列をコピー
		tempary = array_copy( ary );

配列aryと同じ値を格納した配列temparyを作成します。ここでは、配列の値を並び替え(ソート)を利用して組み合わせを求めています。このメソッドの中で、配列aryをソートすると呼び出したメソッド側でもソートが行われた状態になるので、配列temparyを作成することで呼び出し側への影響を無くしています。

配列のコピーメソッドarray_copyは、ソースコードの43行目から56秒目を参照してください。

020
021
		// 昇順ソート
		Arrays.sort( tempary );

配列temparyを昇順ソートします。これで、配列temparyの値が、小さい値から大きい値に並び替えられます。

また、ソートすることで同じ値が配列の中で連続して格納されます。

このソースコードの場合、配列temparyの値

{ 0、5、5、1、3、0、5、2、6、7 }

昇順ソートすると、

0、0、1、2、3、5、5、5、6、7 }

となります。

023
024
025
026
		// 組み合わせの数の取得処理
		// 組み合わせ数の初期値を代入
		nc = 1;
		prenum = tempary[ 0 ];

組み合わせ数の初期値ncに1を代入します。そして、配列temparyの先頭(添え字 0)の値を変数prenumに代入しています。

変数prenumの値が、組み合わせの1つ目ということを意味しています。

028
029
		for ( int i = 1; i < tempary.length; ++ i )
		{

for文を、配列temparyの2番目(添え字 1)から配列の最後までのループを作成しています。

ソースコードの15行目の処理で要素数が1以下の場合には、既にこのメソッドを抜けているので、この処理にたどり着いたときには配列temparyの要素数は2以上です。よって、2番目(i=1)から開始することができます。

030
031
032
033
034
035
			// 1つ前の値と一致しなければ
			if ( prenum != tempary[ i ] ) {
				// 組み合わせの数を増やす
				++ nc;
				prenum = tempary[ i ];
			}

配列temparyの値tempary[i]とprenumが違う場合、組み合わせ数ncを1つ増やして(インクリメント)、変数prenumにtempary[i]を代入しています。

配列temparyの値tempary[i]と同じ値であれば、何も処理していません。

038
039
		// 結果を戻す
		return nc;

組み合わせ数を格納した変数ncの値を戻します。

043
044
045
	// 配列をコピー作成するメソッド
	private static int[] array_copy( int[] srcary )
	{

private static int[] array_copy( int[] srcary )が配列をコピーするメソッドです。srcaryがコピー元の配列です。

046
047
		// 元の配列srcaryの要素数でint配列desaryを作成
		int[] desary = new int[ srcary.length ];

コピー元の配列srcaryの要素数(srcary.length)で、コピー先の配列desaryを初期化しています。

049
050
051
052
		// 配列desaryにsrcaryの値を代入
		for ( int i = 0; i < srcary.length; ++ i ) {
			desary[ i ] = srcary[ i ];
		}

for文を使って、コピー先の配列desaryの各要素に、コピー元の配列srcaryの値を代入にしています。

054
055
		// 作成した配列desaryを戻す
		return desary;

メソッドの最後に、配列desaryをreturn文で戻しています。

059
060
	// メイン
	public static void main( String[] args ) {

このmainメソッドからプログラムを実行します。

061
062
		// 組み合わせ数
		int nc;

同じ数の組み合わせ数を格納する変数ncを宣言しています、

064
065
		// 配列aを宣言
		int[] a;

複数の値を格納するint型配列aを宣言しています、

067
068
069
070
071
072
073
074
075
076
077
078
079
080
		// 要素数10を設定
		a = new int[ 10 ];

		// 値を代入
		a[ 0 ] = 0;
		a[ 1 ] = 5;
		a[ 2 ] = 5;
		a[ 3 ] = 1;
		a[ 4 ] = 3;
		a[ 5 ] = 0;
		a[ 6 ] = 5;
		a[ 7 ] = 2;
		a[ 8 ] = 6;
		a[ 9 ] = 7;

ここでは、要素数10個で配列aを初期化して、値を格納しています。この配列要素数と値は任意です。いろいろ試してみてください。

082
083
		// 組み合わせ数を取得 (0,1,2,3,5,6,7)の7種類
		nc = numberCombo( a );

作成したnumberComboメソッド引数配列aを渡して、同じ数の組み合わせ数ncを取得しています。

085
086
		// 結果を表示
		System.out.println( "同じ数の組み合わせ:" + nc );

結果を表示しています。

以上です。

関連コンテンツ

配列をそのままコピーするメソッドの作り方をソースコードを使って詳しく解説しています。

2019.01.03

同じ型の変数(データ)を複数個まとめて管理するデータの持ちかたがあります。これが配列です。くわしくは、記事をご覧ください。

2016.01.14

処理を繰り返すために使用するfor文について解説しています。

2020.03.23

条件式を判断して処理を分岐する方法を詳しく説明しています。

2023.03.20

メソッドを抜けるときに使用するreturn文について説明しています。

2020.03.20

変数やクラスに格納されている値をコンソール出力する方法は?

2020.03.23

プログラムの最初に実行されるメソッドは?

2022.12.13

プログラミングで使う変数って何?

2020.03.23

Javaのプログラムを書いてみませんか?プログラムの書き方をくわしく説明しています。

2020.03.23

「Javaソースコード」から実行可能な「オブジェクトコード」に変換する方法をくわしく説明しています。

2020.03.23

Javaのプログラムを作ってみませんか?プログラミングに必要なものの用意から実行までを説明しています。

2020.03.23

Javaの学習に役立つソースコードを多数紹介しています。是非、ご覧ください。

2022.09.10

Swingパッケージを使ってグラフィック表示を行う方法を解説しています。

2020.03.23

画像フォーマット形式・色・大きさ・傾きなどの変更、特定の図形(文字・記号など)を見つけたり、取り出したりする画像処理について詳しく解説。

2015.11.29

繰り返し処理を使ったJavaのソースコードサンプルを紹介しています。

2020.03.23

配列を使うJavaソースコードを多数紹介しています。

2021.05.18

数学に関係するJavaのメソッドやソースコードなどを紹介しています。

2022.10.25

三角形、台形、円などいろいろな図形の面積を計算するプログラムを紹介しています。詳しくは、記事をご覧ください。

2021.05.18

StringクラスとStringBuilderクラスを利用したプログラミングの仕方を紹介しています。

2016.12.16

Javaを使った簡単な応用プログラム(生年月日から年齢を計算プログラムなど)を紹介しています。

2022.07.07

プログラミング、ITに関する用語をまとめています。

2022.10.17

日本で使われてきた伝統文様「和柄」について解説しています。

2022.07.27

自然数と整数って何が違う?

2020.03.23

配列に格納されている値を順番に並び替える方法を解説しています。

2019.03.11

プログラミング言語とは?種類や特徴について説明しています。

2022.08.03

Javaプログラムの構成について解説しています。詳しくは、こちらをご覧ください。

2020.03.23

メソッドの定義方法を詳しく解説しています。Javaのサンプルソースコードを使った説明もあります。

2020.03.23

繰り返し処理の作り方を解説しています。

2016.03.02

整数型の変数に1を足すインクリメント、1つ引くデクリメントについて詳しく説明しています。

2020.03.23

for文で変数名iがよく使われる理由について説明しています。興味のある方は是非。

2022.08.29

「ゆるゆるプログラム」のコンテンツを紹介しています。興味のある方はこの記事をご覧ください。

2020.03.23

広告