• ベストアンサー

配列の中に複数存在する数がいくつあるか

お世話になります。配列の中に同じ数が存在する数がいくつあるかを調べたいのですが、途中でつまづいてしまいました。 例えば配列arrayの中に、0, 0, 5, 0, 5, 1, 5といった数が格納されているとしたら 複数ある数は0と5の2つなので、2を返す、というだけのプログラムです。 int n=array.length; int cnt=0; for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ if(array[i]==array[j]){ cnt++; break; } } } return cnt; forループで配列0から同じ数を順番に調べ、もしヒットすればカウントを増やして内側のループをブレイクし、配列1からまた順番に調べようとしたのですが、 上の例の場合、配列0と配列1が同じ数(0)ですので、カウントが余計に増えてしまいます。 どのように組めばうまく動作するでしょうか。宜しくお願いします。

  • Java
  • 回答数4
  • ありがとう数3

質問者が選んだベストアンサー

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.4

>ソートしたあとでも同じ数が連続してしまうので、どのようにしてカウントすればいいのでしょうか・・・ int cnt = 0; int t = 0; //現在調べている数値が最初に出てくる位置 for( int i = 1 ; i < n ; i ++ ) { if( array[t] != array[i] ) { //今までと違う数値になった if ( i > t +1) { //次の数値の先頭(i)のが、現在の数値の先頭の隣(t+1)より大きかったら //現在の数値は2つ以上あったということ cnt ++ ; } //次からは、iの位置を先頭として調べる t = i; } } //配列の最後に重複があっても(array[t] != array[i])で判定ができないので //ループの外で判定する if ( n > t + 1) { cnt ++ ; }

lockwell
質問者

お礼

大変参考になりました!本当にありがとうございました!

その他の回答 (3)

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.3

アイディア1) 集計済を示すboolean配列(長さはarrayと同じ)を作って(checkedとでもしておく)、falseで初期化しておく。 重複していたら、 checkedの対応する要素をtrueにする。 checkedがtrueならすでに確認済なので次へ。 int n=array.length; int cnt=0; boolean[] checked = new boolean[n] ; java.util.Arrays.fill(checked,false); for(int i=0;i<n;i++){ //array[i]がすでに重複として判定済なら次へ if ( checked[i] ) {continue ;} //重複があったことを示すフラグ boolean isdup = false ; for(int j=i+1;j<n;j++){ //array[j]がすでに重複として判定済なら次へ if ( checked[j] ) {continue ;} if ( array[i]==array[j]) ){ //全部の重複要素をchecked=trueにするためにbreakしない checked[j]= true ; //breakしない代りに、重複があったことを示すフラグを立てる isdup= true ; } } if ( isdup ) { checked[i] = true ; //重複があったらcntをインクリメント cnt++; } } return cnt; } アイディア2) 重複したものは配列から削除→残っている配列について重複確認 元の配列を保存するため、あらかじめコピーを作っておく必要がある アイディア3) arrayをソート。同じ値が並ぶので順番に数を数える 元の配列を保存するため、あらかじめコピーを作っておく必要がある

lockwell
質問者

補足

みなさん ありがとうございます!ソートで調べる方法を試してみようと思い、まずソートを作りました。 int[] a = { 0, 0, 5, 0, 5, 1, 5 }; int n = a.length; int temp = 0; for (int i = 0; i < n; i++) { for (int j = 0; j < n - 1; j++) { if (a[j] > a[j + 1]) { temp = a[j]; a[j] = a[j + 1]; a[j + 1] = temp; } } } ここで質問なのですが、ソートしたあとでも同じ数が連続してしまうので、どのようにしてカウントすればいいのでしょうか・・・

  • Lchan0211
  • ベストアンサー率64% (239/371)
回答No.2

(案1) チェックする配列と同じ要素数を持つboolean配列を用意し、 対象配列番号が重複検出済みかどうかを表すフラグとして使う。 重複数値(array[i]==array[j])を見つけたら、 その配列番号の重複検出済みフラグをONにする。 (jのループはbreakしないで、他の同じ数値も重複検出済みに する必要がある。cnt++はjのループ後にする。) 各配列の数値をチェックする前に、重複検出済みフラグが ONか確認し、ONだったら、チェックをスキップする。 (案2) チェックする配列の半分の要素数を持つint配列を用意し、 「重複数値格納配列」として使用する。 同じ数値(array[i]==array[j])を見つけたら、 「重複数値格納配列」にその数値を格納し、 格納位置の配列番号をカウントアップする。 各配列の数値をチェックする前に、「重複数値格納配列」 の中にこれからチェックする数値が存在するか 確認し、存在していたらチェックをスキップする。 「重複数値格納配列」の最終格納位置が、重複数値 検出数になる。 (案3) 配列を一旦小さい順にソートしてからチェックする。 ソートアルゴリズムは有名なものを参考に。 その後のチェックの仕方はわかると思います。 どれが一番効率いいんでしょうね・・

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

配列を変更していいならソートしてしまえばいい. その方が悩みどころが減る. 変更しちゃだめといわれると, かえって時間がかかるんだよな~.

関連するQ&A

  • 配列

    最後にもう一つだけお願いします。ずっと格闘しても解決できません・・ 配列の中の数字で、偶数を全て奇数の前にもって行きます 例) {1,0,1,0,0,1,1} → {0,0,0,1,1,1,1} {3,3,2} → {2,3,3} {2,2,2} → {2,2,2} 流れとしては、まず奇数の数を数えます。これは何回シフトするから知るためです。 配列0から奇数を探し、あればそれを一番最後の配列へとシフトします。 奇数を探す作業が一度終わっても、まだシフトさせないといけない奇数があるかもしれないので(奇数が連続で並んでる場合)、最初に数えた奇数の数分だけちゃんとシフトするようにしようと思います。 public void evensLeft(int[] array) { int odd=0; for (int i = 0; i < array.length; i++) { if(array[i]%2!=0) odd++; //奇数の個数 } while (odd>0) { //奇数分シフトするためのカウント for(int j=0;j<array.length;j++){ //奇数を探す if (array[j] % 2 != 0) { odd--; //奇数のカウントを1減らす for (int k = j; k < array.length-1; k++) { //その奇数を一番最後に移動 int temp = array[k+1]; array[k+1] = array[k]; array[k] = temp; } } } } return array; } いくつかの例では動くのですが、{3,3,2}の例だと配列0に3が来てしまいます。色々変えてみても結果無理でした・・・ どなたかご教授お願いします。

    • ベストアンサー
    • Java
  • 非常にはずかしい質問ですが 配列の質問です。

    C言語の勉強で時間が経つごとに、肝心の基礎が忘れがちになるのですよね。 それに、配列に対しての説明ってほとんど文字列ばかりで整数はみつからないです。 今回の質問は ・int型配列の要素ひとつずつ代入するにはどうするか? ・同じ数字を代入させないにはどうするか? ・配列中n個の要素を表示させるにはどうするのか? 条件 1、配列の要素はn個 2、同じ数は× 一応かいてみました。 { int buffer[6], i, j, signal ; srand((unsigned int)time(NULL)); for( i = 0 ; i < 6 ; i++){ buffer[i] = rand()%42+1; for( signal = 0 , j = 0 ; j < i ; j++ ){ if(buffer[i] == buffer[j]){signal = 1; break;} } if(signal == 0){break;} } printf("%d\n",buffer);

  • 配列長参照のオーバーヘッド

    for等ループでループ終了条件に配列長を使用する場合、配列長を毎回参照する場合と一旦変数に格納して参照する場合、定数を使用する場合と処理速度の差はありますか? つまり 1、for( int i = 0; i < array.length; i++ ) { ... } 2、for( int i = 0; i < len; i++ ) { ... } *(int len=array.length) 3、for( int i = 0; i < 10; i++ ) { ... } *(int[] array = new int[10]) forループ内の処理のメモリ使用量の多寡は不明で、毎ループで読み取られる全ての変数はコンピュータのキャッシュに残るかどうかは不明だとします。

    • ベストアンサー
    • Java
  • 3次元配列のループによる比較の回数を減らす

    以下は正の整数が入った3次元配列form[30][20][8]で、中身が一致している2カ所に-1を代入してループを抜けるというプログラムの一部分なんですが、無駄なループを減らすにはどういった変更をすればいいでしょうか? form[30][20][8]は変更しない方向でお願いします。 check: for(int i=0;i<30;i++){ for(int j=0;j<20;j++){ for(int k=0;k<8;k++){ for(int l=0;l<30;l++){ for(int m=0;m<20;m++){ for(int n=0;n<8;n++){ if(form[i][j][k]==form[l][m][n]&&!(i==l&&j==m&&k==n)form[i][j][k]!=-1) count++; form[i][j][k]=-1; form[l][m][n]=-1; break check; } } } } } } }

    • ベストアンサー
    • Java
  • 4つの異なる二次配列を関数で表示

    二次配列と関数の問題です。 [日本語訳]displayArray7を呼ぶ関数を書きなさい。その関数は二次配列を一つの引数として受け取り、その内容を画面に表示すべきである。その関数は下のいずれの配列でも動作するようにしなさい。プログラムを書いてその関数を評価しなさい。 4つの配列とも一次の項(?)の数が違うじゃないですか。しかも関数を呼ぶときは配列[5][7]などはいらないですよね? (displayArray7(hours);だけ) だから、各配列の一次の項がどんな数字を持っているのかを関数displayArray7に送ることが出来ず、どのように表示してよいのか分かりません(今は一応最大値50で表示しています)。どのようにすればよいのでしょうか? 教えてください。お願いします。 #include <iostream> using namespace std; void initialize(int array[][7]); void displayArray7(int array[][7]); int main() { int hours[5][7]; int stamps[8][7]; int autos[12][7]; int cats[50][7]; initialize(hours); displayArray7(hours); initialize(stamps); displayArray7(stamps); initialize(autos); displayArray7(autos); initialize(cats); displayArray7(cats); return 0; } void initialize(int array[50][7]) { int i, j; for(i=0; i<50; i++) for(j=0; j<7; j++) array[i][j] = 0; } void displayArray7(int array[][7]) { int i, j; cout << "\t1\t2\t3\t4\t5\t6\t7" << endl << endl; for(i=0; i<50; i++){ cout << i+1 << ":"; for(j=0; j<7; j++){ cout << "\t" << array[i][j]; } cout << endl << endl; } }

  • 要素数が10の配列で、乱数0~9の値が重複しないようにする方法がわからなくて困っています。

    JAVAの練習問題でわからなくて困っています 以下は線形探索のプログラムで、このプログラムを改良して、 要素数が10の配列で、乱数0~9の値が重複しないようにする方法がわからなくて困っています。 以下のような簡単なプログラムでできる方法で行いたいです。 どなたか答えまたはヒントを下さい、お願いします。 ------------------------------------------------------------ import java.util.Random; import java.util.Scanner; public static void main (String[] args) { Random rand = new Random(); Scanner stdIn = new Scanner(System.in); final int n = 10; //要素数 int[] a = new int[n]; //配列を宣言 for (int j = 0; j < n;) a[j] = rand.nextInt(10); System.out.print("配列aの全要素の値\n{ "); for (int j = 0; j < n; j++) System.out.print(a[j] + " "); System.out.println("}"); System.out.print("探す数値 : "); int key = stdIn.nextInt(); int i; for (i = 0; i < n; i++) if (a[i] == key) break; if (i < n) //探索成功 System.out.println("それはa[" + i + "]にあります。"); else //探索失敗 System.out.println("それはありません。"); } }

  • 配列

    String型の配列の中の文字列の文字数を数える方法で困っています。 問題は、int型の変数lenで与えられた数字よりも大きい文字数の文字列はいくつあるか調べます。 例) stringsLongerThan({"a","ab","abc"}, 0) 3つ全ての文字列の文字数は0より大きいので3を返す stringsLongerThan({"a","ab","abc"}, 2) "abc"の文字数が2より大きいので1を返す stringsLongerThan({"a","ab","abc","abcd","abcde","abcdef","abcdefg"}, 3) "abcd","abcde","abcdef","abcdefg"の4つが文字数3より大きいので4を返す 途中まで組んだのですが、配列array[]の中の文字列の文字数を数えるにはどうしたらよいのでしょうか? public int stringsLongerthan(String[] array, int len){       int result=0;      for(int i=0;i<array.length;i++){        //ここで配列array[i]の文字列の文字数を数える       int count=文字数;       if(cont>len)        result++;     }      return result; } 宜しくお願いします。

    • ベストアンサー
    • Java
  • 2次元配列のポインタ

    整数型行2列2の2次元配列の[1][0]は、ポインタでは3になるとおもっているのですが、ちがったでしょうか? 下記のソースでエラーが出ていて困っています。 void main() { int array[2][2] = { { 9, 9 }, { 9, 9 } }; int num=2, j,i; *(array + 3) = 0; for (i = 0; i < num; i++) { for (j = 0; j < num; j++) { printf("%d", array[i][j]); } puts(""); } } 99 09 と表示させたいのですが、どこに間違いがあるのでしょうか?

  • Rubyで配列を使ったfor文の中に条件つきif文

    Rubyで配列を使ったfor文の中に条件付きのif文を入れてループさせたいのですが、基本的な構文が分かりません。 for i in array     if i == 9       array[i] << 'ア'     end end という雰囲気で書きたいのですが、どうしたらよいでしょうか。 i番目のループまで、配列のarrayを走査するにはどうすればよいでしょうか。 基礎的な質問ですみません。よろしくお願いします。

  • 配列とポインタでの書き直し(c++)その1

    2つのサイコロの合計と、回数、確率、エラーを配列を使って表示する課題に取り組んでいます。配列を使っては何とかできましたが、課題では配列とポインターの両方を使ってこれを書かなくてはいけません。ポインターに関しては本を読んでも実際応用できないので困っています。ポインターについてわかる方、ヒントください。  ちょっと長いので2つに分けて掲示します。(みにくくてごめんなさい!) #include<>....省略 int rollDice(void); double getError(double, int, double []); int main(void) { int sum[11]; double error[11]; int throws; double probability; error[0] = 1.0/36.0; error[1] = 2.0/36.0; error[2] = 3.0/36.0; error[3] = 4.0/36.0; error[4] = 5.0/36.0; error[5] = 6.0/36.0; error[6] = 5.0/36.0; error[7] = 4.0/36.0; error[8] = 3.0/36.0; error[9] = 2.0/36.0; error[10] = 1.0/36.0; srand((unsigned) time(NULL)); for (int i=0; i<11; i++) sum[i] = 0; cout << "\n何回サイコロを転がしますか?: "; cin >> throws; for (int j= 0; j<throws; j++) { int roll = rollDice(); switch(roll) { case 2: sum[0]++; break; case 3: sum[1]++; break; case 4: sum[2]++; break; case 5: sum[3]++; break; case 6: sum[4]++; break; case 7: sum[5]++; break; case 8: sum[6]++; break; case 9: sum[7]++; break; case 10: sum[8]++; break; case 11: sum[9]++; break; case 12: sum[10]++; break; } } 配列とポインタでの書き直し(c++)その2 につづく

専門家に質問してみよう