JAva-Google面接問題-中数を抽出しやすいデータ構造を設計

11285 ワード

ネット上でこの問題の解答を探したが、すべて構想を提供し、具体的な実現を提供しなかった.その中で大きさの山を使うという考え方は簡単そうに見えますが、実現するには多くのことを考えなければなりません.
以下は、ソート配列とサイズスタックでそれぞれ実現します.
サイズヒープの使用:

import java.util.Arrays;

public class MedianInHeap {
	/**
	 *   :             
	 *         ,        ,1.      ,2.    。        。
	 * 1.         。
	 *      , O(logn)           , O(n)                    。
	 *      , O(1)        。 
	 * 2.            。
	 *               ,              。
	 *      , O(logn)                ,                  (   1)。
	 *      , O(1)       。       ,     :         ,         ,     2.
	 *          (  1),            ,    。
	 * 3.       --how?
	 */
	
	private MaxHeap maxHeap;
	private MinHeap minHeap;

	public static void main(String[] args) {
		
		MedianInHeap n = new MedianInHeap();
		int[] data={7,9,5,3,1};
		for(int each:data){
			n.add(each);
			System.out.println("median:"+n.median());
			System.out.println("===============");
		}
	}

	public MedianInHeap(){
		maxHeap=new MaxHeap();
		minHeap=new MinHeap();
	}
	
	/*
	 * add an element into 'MedianInHeap'.
	 * However,you need some skill.
	 * Consider [3,5,7,9].The data size is even.Median is (5+7)/2=6.
	 * How do we get '5' and '7'?
	 * Of course we get them from the roots of 'maxHeap' and 'minHeap'.That is fastest.
	 * The problem is ,which is the root of 'maxHeap'?That is,
	 * maxHeap:	7	minHeap:  5		# or maxHeap:	5	minHeap:  7	
	 * 		   /             /		#			   /             /
	 * 		  3             9		#		      3             9
	 * The answer is:'5' is the root of 'maxHeap'.
	 * We use 'maxHeap' to store the smaller part of the data;'minHeap' the bigger.
	 * You are gonna find it yourself.
	 * So,add '1' into 'maxHeap';'6'(or '10') into 'minHeap'.
	 */
	public void add(int item) {
		int sizeMax = maxHeap.size;
		int sizeMin = minHeap.size;
		int rootMax = maxHeap.root();
		int rootMin = minHeap.root();
		if (sizeMax == 0) {
			maxHeap.insert(item);
		} else if (sizeMin == 0) {
			minHeap.insert(item);
		} else {
			if(sizeMax==1&&sizeMin==1&&rootMax>rootMin){//swap to make 'rootMax'<'rootMin'
				int tmp=maxHeap.data[0];
				maxHeap.data[0]=minHeap.data[0];
				minHeap.data[0]=tmp;
			}
			if (item < rootMax) {//insert into 'maxHeap'
				maxHeap.insert(item);
				if (maxHeap.size - minHeap.size > 1) {
					int immigrant = maxHeap.root();
					minHeap.insert(immigrant);
					maxHeap.deleteRoot();
				}
			} else{//insert into 'minHeap'
				minHeap.insert(item);
				if(minHeap.size-maxHeap.size>1){
					int immigrant=minHeap.root();
					maxHeap.insert(immigrant);
					minHeap.deleteRoot();
				}
			}
		}
		System.out.print("max heap:");
		maxHeap.print();
		System.out.print("min heap:");
		minHeap.print();
		//after inserting,size is changed.So update it.
		sizeMax=maxHeap.size;
		sizeMin=minHeap.size;
		int[] allData=new int[sizeMax+sizeMin];
		System.arraycopy(maxHeap.data, 0, allData, 0, sizeMax);//maxHeap.data,not maxHeap,or it will cause "java.lang.ArrayStoreException"
		System.arraycopy(minHeap.data, 0, allData, sizeMax, sizeMin);
		Arrays.sort(allData);
		System.out.println(Arrays.toString(allData));
	}

	public double median() {
		int sizeMax = maxHeap.size;
		int sizeMin = minHeap.size;
		int rootMax = maxHeap.root();
		int rootMin = minHeap.root();
		if(sizeMax==sizeMin){
			return (rootMax+rootMin)/2.0;
		}else{
			return sizeMax>sizeMin?rootMax:rootMin;
		}
	}
	
	class MinHeap {

		int[] data;//maybe we could use ArrayList.
		int size = 0;

		MinHeap() {
			this(10);
		}

		MinHeap(int capacity) {
			data = new int[capacity];
		}

		void print(){
			for(int i=0;i<size;i++){
				System.out.print(data[i]+" ");
			}
			System.out.println();
		}
		
		int root() {
			return data[0];
		}

		void deleteRoot(){
			if(size>1){
				data[0]=data[size-1];
				reheapFromTop(0,size-2);
				size--;
			}
		}
		
		void insert(int item) {
			if (size == 0) {
				data[0] = item;
				size++;
				return;
			}
			if (size == data.length) {
				data = expandHeap(data);
			}
			data[size]=item;
			reheapFromBottom(0,size);
			size++;
		}

		//we use 'int[]' to store heap's data.When you add an element in the end,you should 'reheapFreomBottom'.
		void reheapFromBottom(int begin,int end) {
			int orphan=data[end];
			boolean done = false;
			int curIndex=end;
			int rootIndex = getParent(curIndex);
			while (!done && rootIndex >= 0) {
				if (orphan < data[rootIndex]) {
					data[curIndex] = data[rootIndex];
					curIndex = rootIndex;
					rootIndex = getParent(curIndex);
				} else {
					done = true;
				}
			}
			data[curIndex] = orphan;
		}

		//when you delete the heap's root,you should 'reheapFromTop'.
		void reheapFromTop(int begin,int end) {
			int orphan=data[begin];
			boolean done=false;
			int rootIndex=begin;
			while(!done&&rootIndex<=end){
				int leftIndex=rootIndex*2+1;
				if(leftIndex>end)break;
				int smallIndex=leftIndex;
				int rightIndex=leftIndex+1;
				if(rightIndex<=end&&data[rightIndex]<data[smallIndex]){
					smallIndex=rightIndex;
				}
				if(data[smallIndex]<orphan){
					data[rootIndex]=data[smallIndex];
					rootIndex=smallIndex;
				}else{
					done=true;
				}
			}
			data[rootIndex]=orphan;
		}
	}

	class MaxHeap {

		int[] data;//maybe we could use ArrayList.
		int size = 0;

		MaxHeap() {
			this(10);
		}

		MaxHeap(int capacity) {
			data = new int[capacity];
		}

		int root() {
			return data[0];
		}

		void print(){
			for(int i=0;i<size;i++){
				System.out.print(data[i]+" ");
			}
			System.out.println();
		}
		
		void deleteRoot(){
			if(size>1){
				data[0]=data[size-1];
				reheapFromTop(0,size-2);
				size--;
			}
		}
		void insert(int item) {
			if (size == 0) {
				data[0] = item;
				size++;
				return;
			}
			if (size == data.length) {
				data = expandHeap(data);
			}
			data[size]=item;
			reheapFromBottom(0,size);
			size++;
		}

		void reheapFromBottom(int begin,int end) {
			int orphan=data[end];
			boolean done = false;
			int curIndex=end;
			int rootIndex = getParent(curIndex);
			while (!done && rootIndex >= 0) {
				if (orphan > data[rootIndex]) {
					data[curIndex] = data[rootIndex];
					curIndex = rootIndex;
					rootIndex = getParent(curIndex);
				} else {
					done = true;
				}
			}
			data[curIndex] = orphan;
		}

		void reheapFromTop(int begin,int end) {
			int orphan=data[begin];
			boolean done=false;
			int rootIndex=begin;
			while(!done&&rootIndex<=end){
				int leftIndex=rootIndex*2+1;
				if(leftIndex>end)break;
				int largerIndex=leftIndex;
				int rightIndex=leftIndex+1;
				if(rightIndex<=end&&data[rightIndex]>data[largerIndex]){
					largerIndex=rightIndex;
				}
				if(data[largerIndex]>orphan){
					data[rootIndex]=data[largerIndex];
					rootIndex=largerIndex;
				}else{
					done=true;
				}
			}
			data[rootIndex]=orphan;
		}
	}

	
	//get root's index from a child's index
	int getParent(int curIndex) {
		return (curIndex % 2 == 0) ? (curIndex / 2 - 1) : (curIndex / 2);
	}

	//int[n]-->int[2*n]
	int[] expandHeap(int[] data) {
		int size = data.length;
		int[] newArray = new int[data.length * 2];
		for (int i = 0; i < size; i++) {
			newArray[i] = data[i];
		}
		return newArray;

	}
}


ソート配列を使用するには:


public class MedianInSortedArray {

	/**
	 *   :             
	 *         ,        ,1.      ,2.    。        。
	 * 1.         。
	 *      , O(logn)           , O(n)                    。
	 *      , O(1)        。 
	 * 2.            。
	 *               ,              。
	 *      , O(logn)                ,                  (   1)。
	 *      , O(1)       。       ,     :         ,         ,     2.
	 *          (  1),            ,    。
	 * 3.       --how?
	 */
	public static void main(String[] args) {
		//1.Median implemented by sorted array
		MedianInArray m=new MedianInArray();
		for(int i=0;i<12;i++){
			m.insert(i);
			m.print();
			System.out.println(" median is "+m.getMedian());
		}
		
	}

	private static class MedianInArray{
		int[] data;
		int size=0;//record the number of elements
		
		MedianInArray(){
			this(10);
		}
		MedianInArray(int capacity){
			data=new int[capacity];
		}
		
		//like "Insertion Sort"
		void insert(int item){
			if(size==0){
				data[size]=item;
				size++;
			}else{
				if(size+1>data.length){
					expandArray();
				}
				int index=size-1;
				while(index>=0&&data[index]>item){//move backward for insertion
						data[index+1]=data[index];
						index--;
				}
				data[index+1]=item;
				size++;
			}
		}
		
		double getMedian(){
			int mid=size/2;
			if((size &(0x01))==1){
				return data[mid];
			}else{
				return (data[mid]+data[mid-1])/2.0;
			}
			
		}
		
		void expandArray(){
			int capacity=data.length*2;
			int[] newArray=new int[capacity];
			for(int i=0;i<size;i++){//"System.arraycopy" also works
				newArray[i]=data[i];
			}
			data=newArray;
		}
		
		void print(){
			for(int i=0;i<size;i++){
				System.out.print(data[i]+" ");
			}
		}
	}
}