2019/06/24 公開
・同じ数の組み合わせ
ここでは、整数型の配列の中に、同じ値の数値が何種類あるか求める方法を紹介しています。
例えば、配列に格納されている値が、
{ 0、0、7、0、7 }
の場合、
0、7
の2種類の数字が配列に格納されているので、2が同じ数の組み合わせ数となります。
他の例で、配列に格納されている値が、
{ 3、3、6、2、1、3 }
の場合、
1、2、3、6
の4つの種類の数字が配列に格納されているので、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、0、7、7 }のように先頭の"0"と4番目の"7"が、1つ前の値と違う箇所になります。この場合、2箇所違ったので2種類です。
{ 1、2、3、3、3、6 }の場合、{ 1、2、3、3、3、6 }のように先頭の"1"と2番目の"2"、3番目の"3"、6番目の"6"が1つ前の値と違う箇所になります。この場合、4箇所違ったので4種類です。
それでは、ここから上記の内容のJavaのソースコードを見ていきましょう。
NumberCombo1.java ← クリックしてダウンロードページに移動
001: import java.util.Arrays; 002: 003: public class NumberCombo1 { 004: // 数の組み合わせ数を取得 005: public static int numberCombo( int[] ary ) 006: { 007: int nc; // 組み合わせ数 008: int prenum; // 1つ前の番号 009: int[] tempary; // 作業用の配列 010: 011: // aryがnullなら0を戻す 012: if ( null == ary ) return 0; 013: 014: // aryの数が0以下ならaryの数を戻す 015: if ( 1 >= ary.length ) return ary.length; 016: 017: // 元の配列の順番を変えないように配列をコピー 018: tempary = array_copy( ary ); 019: 020: // 昇順ソート 021: Arrays.sort( tempary ); 022: 023: // 組み合わせの数の取得処理 024: // 組み合わせ数の初期値を代入 025: nc = 1; 026: prenum = tempary[ 0 ]; 027: // 処理本体 028: for ( int i = 1; i < tempary.length; ++ i ) 029: { 030: // 1つ前の値と一致しなければ 031: if ( prenum != tempary[ i ] ) { 032: // 組み合わせの数を増やす 033: ++ nc; 034: prenum = tempary[ i ]; 035: } 036: } 037: 038: // 結果を戻す 039: return nc; 040: } 041: 042: 043: // 配列をコピー作成するメソッド 044: private static int[] array_copy( int[] srcary ) 045: { 046: // 元の配列srcaryの要素数でint配列desaryを作成 047: int[] desary = new int[ srcary.length ]; 048: 049: // 配列desaryにsrcaryの値を代入 050: for ( int i = 0; i < srcary.length; ++ i ) { 051: desary[ i ] = srcary[ i ]; 052: } 053: 054: // 作成した配列desaryを戻す 055: return desary; 056: } 057: 058: 059: // メイン 060: public static void main( String[] args ) { 061: // 組み合わせ数 062: int nc; 063: 064: // 配列aを宣言 065: int[] a; 066: 067: // 要素数10を設定 068: a = new int[ 10 ]; 069: 070: // 値を代入 071: a[ 0 ] = 0; 072: a[ 1 ] = 5; 073: a[ 2 ] = 5; 074: a[ 3 ] = 1; 075: a[ 4 ] = 3; 076: a[ 5 ] = 0; 077: a[ 6 ] = 5; 078: a[ 7 ] = 2; 079: a[ 8 ] = 6; 080: a[ 9 ] = 7; 081: 082: // 組み合わせ数を取得 (0,1,2,3,5,6,7)の7種類 083: nc = numberCombo( a ); 084: 085: // 結果を表示 086: System.out.println( "同じ数の組み合わせ:" + nc ); 087: } 088: }
NumberCombo1.Javaの出力結果
同じ数の組み合わせ:7
int型の配列に格納している値は、0,1,2,3,5,6,7の7種類です。
ここから、ソースコードについて解説してきます。
003: public class NumberCombo1 {
クラス名を、NumberCombo1としています。
004: // 数の組み合わせ数を取得 005: public static int numberCombo( int[] ary ) 006: {
public static int numberCombo( int[] ary )がint型の配列に含まれる数値の種類を取得するメソッドです。
007: int nc; // 組み合わせ数 008: int prenum; // 1つ前の番号 009: int[] tempary; // 作業用の配列
同じ数の組み合わせを取得するために使う変数を宣言しています。
011: // aryがnullなら0を戻す 012: if ( null == ary ) return 0;
int型の配列aryが初期化されていない場合、0を戻しています。
014: // aryの数が0以下ならaryの数を戻す 015: 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の値が、小さい値から大きい値に並び替えられます。
また、ソートすることで同じ値が配列の中で連続して格納されます。
{ 0、5、5、1、3、0、5、2、6、7 }
を昇順ソートすると、
{ 0、0、1、2、3、5、5、5、6、7 }
となります。
023: // 組み合わせの数の取得処理 024: // 組み合わせ数の初期値を代入 025: nc = 1; 026: prenum = tempary[ 0 ];
組み合わせ数の初期値ncに1を代入します。そして、配列temparyの先頭(添え字 0)の値を変数prenumに代入しています。
変数prenumの値が、組み合わせの1つ目ということを意味しています。
028: for ( int i = 1; i < tempary.length; ++ i ) 029: {
for文を、配列temparyの2番目(添え字 1)から配列の最後までのループを作成しています。
ソースコードの15行目の処理で要素数が1以下の場合には、既にこのメソッドを抜けているので、この処理にたどり着いたときには配列temparyの要素数は2以上です。よって、2番目(i=1)から開始することができます。
030: // 1つ前の値と一致しなければ 031: if ( prenum != tempary[ i ] ) { 032: // 組み合わせの数を増やす 033: ++ nc; 034: prenum = tempary[ i ]; 035: }
配列temparyの値tempary[i]とprenumが違う場合、組み合わせ数ncを1つ増やして(インクリメント)、変数prenumにtempary[i]を代入しています。
配列temparyの値tempary[i]と同じ値であれば、何も処理していません。
038: // 結果を戻す 039: return nc;
組み合わせ数を格納した変数ncの値を戻します。
043: // 配列をコピー作成するメソッド 044: private static int[] array_copy( int[] srcary ) 045: {
private static int[] array_copy( int[] srcary )が配列をコピーするメソッドです。srcaryがコピー元の配列です。
046: // 元の配列srcaryの要素数でint配列desaryを作成 047: int[] desary = new int[ srcary.length ];
コピー元の配列srcaryの要素数(srcary.length)で、コピー先の配列desaryを初期化しています。
049: // 配列desaryにsrcaryの値を代入 050: for ( int i = 0; i < srcary.length; ++ i ) { 051: desary[ i ] = srcary[ i ]; 052: }
for文を使って、コピー先の配列desaryの各要素に、コピー元の配列srcaryの値を代入にしています。
054: // 作成した配列desaryを戻す 055: return desary;
メソッドの最後に、配列desaryをreturn文で戻しています。
059: // メイン 060: public static void main( String[] args ) {
このmainメソッドからプログラムを実行します。
061: // 組み合わせ数 062: int nc;
同じ数の組み合わせ数を格納する変数ncを宣言しています、
064: // 配列aを宣言 065: int[] a;
067: // 要素数10を設定 068: a = new int[ 10 ]; 069: 070: // 値を代入 071: a[ 0 ] = 0; 072: a[ 1 ] = 5; 073: a[ 2 ] = 5; 074: a[ 3 ] = 1; 075: a[ 4 ] = 3; 076: a[ 5 ] = 0; 077: a[ 6 ] = 5; 078: a[ 7 ] = 2; 079: a[ 8 ] = 6; 080: a[ 9 ] = 7;
ここでは、要素数10個で配列aを初期化して、値を格納しています。この配列の要素数と値は任意です。いろいろ試してみてください。
082: // 組み合わせ数を取得 (0,1,2,3,5,6,7)の7種類 083: nc = numberCombo( a );
作成したnumberComboメソッドの引数に配列aを渡して、同じ数の組み合わせ数ncを取得しています。
085: // 結果を表示 086: System.out.println( "同じ数の組み合わせ:" + nc );
結果を表示しています。
■関連コンテンツ
配列のコピーを作る | 配列のコピーを作る方法を解説 |
Javaの配列 | 同じ型の変数をまとめた配列について解説 |
![]() |
for文繰り返し処理に使用するfor文をJavaのソースコードを使って説明しています。 |
■新着情報
2022.07.07 | 外部プログラムの実行 | exeファイル実行 |
2022.07.06 | 完全数 | 6=1+2+3 |