練習問題のまとめ(一)


前に出会ったいくつかの比較的良い練習問題を自己総括して整理して、後で続々と追加します.
一.らせん配列
スパイラルマトリクスを印刷し、マトリクス長が5の場合、出力結果を下図に示します
 1  2  3  4  5  16 17 18 19 6  15 24 25 20 7  14 23 22 21 8  13 12 11 10 9
Cプログラマーの面接宝典では、2年前に見たことがあります.
考え方:
右、下、左、上の4つの方向に沿って配列に値を割り当てます.
配列は最上行,最右列,最下行,最左列は0,n−1,n−1,0の順であった.
右方向の付与が終了すると、最上段に1を加算し、
下方向の付与が終了すると、右端の列が1引く、
左方向の付与が終了すると、一番左の列に1を加える、
上方向の付与が終了すると、最下段は1減、
実際には,初期方向の順序を順番に変えて4方向の螺旋行列を出力することができる.
私の解法は以下の通りです(java):
public static void spiralRectPrint(int n){
		if(n < 1){
			System.out.println("       ");
			return;
		}
		final int TOTAL = n * n;
		final int[] DIRECTION = new int[]{0,1,2,3};// , , , 
		final int MAX_LENGTH = String.valueOf(TOTAL).length();//     ,      
		int firstRow = 0,firstCol = 0;
		int lastRow = n - 1,lastCol = n - 1;
		int directionIndex = 0;//      
		int num = 1;
		int[][] printArray = new int[n][n];//       
		while(num <= TOTAL){
			switch (DIRECTION[directionIndex % DIRECTION.length]) {
			case 0:
				for(int i = firstCol;i <= lastCol;++i)
					printArray[firstRow][i] = num++;
				++firstRow;
				break;
			case 1:
				for(int i = firstRow;i <= lastRow;++i)
					printArray[i][lastCol] = num++;
				--lastCol;
				break;
			case 2:
				for(int i = lastCol;i >= firstCol;--i)
					printArray[lastRow][i] = num++;
				--lastRow;
				break;
			case 3:
				for(int i = lastRow;i >= firstRow;--i)
					printArray[i][firstCol] = num++;
				++firstCol;
				break;
			}
			++directionIndex;
		}
		//  
		for(int i = 0;i < n;++i){
			for(int j = 0; j < n;++j){
				int value = printArray[i][j];							
				for(int k = 0; k <= MAX_LENGTH - String.valueOf(value).length();++k)
					System.out.print(" ");
				System.out.print(value);
			}
			System.out.println();
		}
	}

二.配列重複数の問題
与えられたx個の連続整数m−n(m要求:1,2中の時間複雑度はいずれもO(N),1中の空間複雑度はO(N),2中の空間複雑度はO(1)である
1に入力パラメータm,n,出力整形配列arr
2入力パラメータはarrとm、出力は繰返し数k
考え方:1.簡単です.x+1のサイズの配列を作成します.前のxの配列要素はm-nの順で、最後の要素はランダムで、トランプを洗うだけです.
注意:任意の整数[m,n]でランダムな文は:
random.nextInt(n - m + 1) + m
2.k=配列のすべての要素の和-(m~n)すべての数字の和をk=s 1-s 2と記す
ここでs 2はガウス式で計算できる
arr配列の前のx要素を累積するだけなので、結果をarrの最後の要素に置くことができ、スペースを必要としません.
私の解法は以下の通りです(java):
第1問:
public static int[] createArray(int m,int n){
		int[] arr = new int[n - m + 2];
		Random random = new Random();
		for(int i = 0;i < arr.length - 1;++i)arr[i] = m + i;
		//set random display two time number in[m,n]
		arr[arr.length - 1] = random.nextInt(n - m + 1) + m;
		System.out.printf("before find num %d display two times
",arr[arr.length - 1]); //random array for(int i = 0;i < arr.length;++i){ int index = random.nextInt(arr.length); //swap if(i != index){ arr[i] ^= arr[index]; arr[index] ^= arr[i]; arr[i] ^= arr[index]; } } return arr; }

第2問:
	public static int getDisplayTwoTimesNumber(int[] arr,int m){
		for(int i = 0;i < arr.length - 1;++i) arr[arr.length - 1] += arr[i];
		return arr[arr.length - 1] - (m + m + arr.length - 2) * (arr.length - 1) / 2;
	}

三.かくりつもんだい
ある射撃隊員が8,9,10環を撃つ確率はそれぞれa,b,c,a+b+c=1であり、その隊員が10回にわたってk環を撃つ確率を求める.そのうち80<=k<=100入力パラメータ:a,b,c,k出力結果:k環を撃つ確率は、結果として6桁の小数例を保持する.入力:.25,.37,.38,98出力:0.003091
どのプログラマーの面接宝典で似たような問題を見たことがあるようです.
考え方:
理論的には10^10種類あるかもしれませんが、射撃するたびに3種類の結果しか出ないので、総状況数は3^10であるべきです.
3^10の場合をどのように遍歴するかが問題の鍵となっている.射撃のたびにリング数を累積し、それに応じて確率を累積することができ、総リング数がkに等しい場合、現在の確率pを総確率Pに累積する.
再帰的に作ることも考えられます.
しかし、3進制で作ったほうがいいと思います.総状況数をxxxxxxxxxx(3)と見ることができます.xの値は0,1,2で、ちょうど射撃数の配列8,9,10の3つの下標です.
1回目は22,222,222,222,222(3)まで1億円(3)増
したがって、長さ10の整形に伴う配列を追加すればよい.
最後にBigDecimalで四捨五入します.
私の解法は以下の通りです(java)
	public static double calcRatio(double[] parmas,int k)
	{
		final int TOTAL_TIME = 10;
		int[] scoreArr = new int[]{8,9,10};
		int[] timeArr = new int[TOTAL_TIME];
		final int TOTAL_COUNT = (int)Math.pow(scoreArr.length, TOTAL_TIME);
		double ratio = 1,totalRatio = 0;
		for(int i = 0,sum = 0;i < TOTAL_COUNT;++i,sum = 0,ratio = 1){
			int time = i;
			for(int j = 0;j < timeArr.length;++j){				
				timeArr[j] = time % scoreArr.length;
				time /= scoreArr.length;
				sum += scoreArr[timeArr[j]];
				ratio *= parmas[timeArr[j]];
			}
			if(sum == k)totalRatio += ratio;
		}
		BigDecimal result = new BigDecimal(totalRatio).setScale(6,RoundingMode.HALF_UP);
		return result.doubleValue();
	}

四.スタックのようなデータ構造
スタックのようなデータ構造(データ型はIntegerのみ)を実現し、push()、pop()、findMin()の3つの方法を含み、findMin()は現在のデータ構造の最小要素を出力する値である.注意:すべての方法の時間の複雑さはO(1)!!!つまりループループループの方法で最小値を見つけることができません!!
考え方:
問題を出した人は悪いので,push(),pop()に気づくとfindMin()メソッドが正しく呼び出され,時間的複雑度はいずれもO(1)である.
最小値を伴う配列で記録し,問題を解決した.
前に投稿した投稿(最初の質問):
http://topic.csdn.net/u/20110618/21/44742d9b-b9bd-49c7-b754-3270dddc57f7.html
私の解法は以下の通りです(java)
public class MyStack {
    private static final int SIZE = 100;
    private int[] data = new int[SIZE];
    private int topOfArray = -1;
    private int topOfMinData = -1;
    private int size = 0;
    private int min;
    private int[] minData = new int[SIZE];
    
    public MyStack(){
        clear();
    }
    
    public void clear(){
        data = new int[SIZE];
        minData = new int[SIZE];
        topOfArray = -1;
        size = 0;
    }
    
    public void push(int x){
        data[++topOfArray] = x;
        size++;
        if(topOfArray == 0 || data[topOfArray] <= min){            
            min = data[topOfArray];
            minData[++topOfMinData] = data[topOfArray];
        }
    }
    
    public int pop(){
        size--;
        if(data[topOfArray] == min && topOfArray > 0){
            min = minData[--topOfMinData];
        }
        else if(topOfArray == 0){
            clear();
            return 0;
        }
        return data[topOfArray--];
    }
    
    public int findMin(){
        if(topOfArray == -1){
            return Integer.MAX_VALUE * (-1);
        }
        return minData[topOfMinData];
    }
    
}

五.トランプを切る
与えられた数[m,n]内でk個の異なる数をランダムに生成した.または、セット内のいくつかの異なる要素のセットをランダムに取得します.
考え方:
脳randomなしではなく,random後の数が生成された数列にないと判断することはできない.kが大きい場合(n−m+1に近い)は,異なる数に伴う確率が非常に低く,効率に深刻な影響を及ぼすからである.
トランプの方法で、m~nのすべての数を含む配列を一度に生成し、順番を乱して前のk個を取る.
次に私のトランプ類を添付します.その中に含まれているトランプ方法(java).
public class Poker {
	private final static int CARD_COUNT = 52;
	private static String[] CARD_FLOWERS = new String[]{"Spade","Heart","Club","Diamond"};
	private static String[] CARD_VALUES = new String[]{"A","2","3","4","5","6","7","8","9",
		"10","J","Q","K"};
	private static String[] CARD_GHOSTS_FLOWERS = new String[]{"ghost","ghost"};
	private static String[] CARD_GHOSTS_VALUES = new String[]{"Small","Big"};
	
	private String flower;
	private String value;
	private int index;
	
	private static Poker[] _pokers;
	
	public String getFlower() {
		return flower;
	}
		
	public String getValue() {
		return value;
	}
	
	public int getIndex() {
		return index;
	}
	
	public Poker(String flower,String value,int index){
		this.flower = flower;
		this.value = value;
		this.index = index;
	}
	
	private static Poker[] getCardsInstance(){
		if(_pokers != null){
			return _pokers;
		}
		_pokers = new Poker[CARD_COUNT];
		for(int i = 0;i < CARD_FLOWERS.length;++i){
			for(int j = 0;j < CARD_VALUES.length;++j){
				int index = i * CARD_VALUES.length + j;
				_pokers[index] = new Poker(CARD_FLOWERS[i], CARD_VALUES[j], index + 1);
			}
		}
		for(int i = CARD_GHOSTS_FLOWERS.length - 1;i >= 0;--i){
			int index = CARD_COUNT - i;
			_pokers[index - 1] = new Poker(CARD_GHOSTS_FLOWERS[i], CARD_GHOSTS_VALUES[i], index);
		}
		return _pokers;
	}
	
	public static Poker[] shufflingCards(){
		Random random = new Random();
		Poker[] pokers = getCardsInstance();
		for(int i = 0;i < pokers.length;++i){
			int index = random.nextInt(pokers.length);
			if(i != index){
				Poker cardTemp = pokers[i];
				pokers[i] = pokers[index];
				pokers[index] = cardTemp;
			}
		}
		return pokers;
	}
	
	public String toString(){
		return this.flower + this.value;
	}
	
	public static void displayPlayerCards(Poker[] poker){
		final int PLAYERS = 4;
		for(int i = 1;i <= poker.length;++i){
			System.out.print(poker[i - 1].toString() + " ");
			if(i % (poker.length / PLAYERS) == 0)System.out.println();
		}
	}
}

今日はしばらくこれだけ書いて、後で補充します.
2012.8.29