從求數組Top N個數開始說起的求數組的若干問題筆記

隨便百度看到有博客關於求數組的最大N個數的問題的文章,想起好像在編程之美上有這麼一道題,好多天沒有練練數據結構的題目,就從求數組的最大K個數說起。

關於這道題目編程之美提供了很多種算法,此處受插入排序的啓發,提供一種改進的插入排序算法如下,最壞時間複雜度爲O(n * m),空間複雜度爲1.提供實現代碼如下:

void GetMaxList(int[] m,int n){//此算法爲插入排序的啓發
	   if(m == null || m.length < n) 
		   return ;
	   for(int i = 1;i<m.length;i++){
		   int j;
		   if(i < n){ //此處判斷的目的一直保證前N個數字有序
			    j = i-1;
		   }else{ 
			    j = n-1;
		   }
		   int temp = m[i];
		   while(j >= 0 && m[j] < temp){
			    m[j+1] = m[j];
			    j--;
		   }
		   if(j != i-1)
			   m[j+1] = temp;
	   }
	   for(int i = 0;i<n;i++ ){
		   System.out.print(m[i] + "\t");
	   }
	}	

以上解法自我感覺運用了點小技巧,通過插入排序的啓發,此處對數組m中前n個元素進行插入排序,n個元素之後只需要維護前n個元素最大有序就行,則插入排序完成後,取前n個元素就是最大的n個元素。翻看編程之美的多種解法,最後百度的時候看到CSDN的v_JULY_v大神的一篇文章程序員編程藝術:第三章續、Top K算法問題的實現 對求數組的最大K個數的深入解讀,深刻感受大牛到底厲害在哪裏,大牛對待編程藝術的嚴謹和深入,在此,對v_JULY_v大神的系列博客膜拜一次。

求完數組的最大N個數後,我也來一次舉一反三,那取數組的任意N個數情況該怎麼處理,以下針對求數組{1,3,4,6,7,2}的任意3個數的所有組合給出自己不成熟的解答,此處的實現思路如下:

我們可以設定數組{1,3,4,6,7,2}取出的元素按數組的索引從小到大去取,因此,我們第一個數取1的話,取第二個數只能從{3,4,6,7,2} 取,取完第二個數,第三個數只能從剩下的去取。我們知道,我們取第一個數可以取{1,3,4,6},實際在取數組的時候對從索引0 到 數組長度 length -n +1取。

Q2:求數組{1,3,4,6,7,2}的3個數的所有組合, 代碼實現如下:

	public static void main(String[] args) {
	    int[] numArr = {1,3,4,6,7,2};
	    int n = 3;
	    getMaxNList(numArr,n);

	}
	
	static void getMaxNList(int[] numArr,int n){
		 int[] result = new int[n];
		 for(int i =0;i< numArr.length - n+1;i++){
			 result[0] = numArr[i];
		     for(int j = i+1;j<numArr.length - n +2;j++){
		    	 result[1] = numArr[j];
		    	 for(int k = j+1;k<numArr.length-n+3;k++){
		    		 result[2] = numArr[k];
		    		 print(result);
		    	 }
		      }
		  }
	}

	static void print(int[] result){
		for(int num : result){
			System.out.print(num);
			System.out.print(" ");
		}
		System.out.println();
	}
輸出結果如下:

1 3 4 
1 3 6 
1 3 7 
1 3 2 
1 4 6 
1 4 7 
1 4 2 
1 6 7 
1 6 2 
1 7 2 
3 4 6 
3 4 7 
3 4 2 
3 6 7 
3 6 2 
3 7 2 
4 6 7 
4 6 2 
4 7 2 
6 7 2

針對以上解法,我們發現當我們隨機取的N比較大的時候,我們的for循環有N此之多,可知以上算法不可取,針對每次循環的規律和for,我想大家會馬上想到,for循環改成遞歸調用,代碼量就會小不少。

Q2改進: 遞歸求數組的任意N個數的所有組合,代碼實現如下:

public static void main(String[] args) {
	    int[] numArr = {1,3,4,6,7,2};
	    int n = 3;
	    getMaxNList(numArr,n);
	}

	static void  getMaxNList(int[] numArr,int n){
		int[] result = new int[n];
		loopMaxNList(numArr,0,0,n,result);
	}
	
	static void loopMaxNList(int[] numArr,int startIndex,
			int curIndex,final int num,int[] result){
		 if(curIndex < num ){ //遞歸結束條件,當前result給元素賦值索引等於result的長度
			 for(int i = startIndex;i < numArr.length - num + curIndex + 1;i++){
				   result[curIndex] = numArr[i];
				   loopMaxNList(numArr,i+1,curIndex+1,num,result);  
			 }
		 }else{ //最內層遞歸結束時,讀出所有元素
			 print(result);
		 }
	}
	
	static void print(int[] result){
		for(int num : result){
			System.out.print(num);
			System.out.print(" ");
		}
		System.out.println();
	}

以上求完數組{1,3,4,6,7,2}的3個數的實現,我們再來舉一反三,再來變化下題目的條件,我們來求n個數組任意選取一個元素的所有組合,針對以上的遞歸解法,我們發現求n個數組任意選取一個元素的所有組合變的很簡單,實現思路如下:

我們遞歸的最外層,我們取第一個數組,我們可以循環遍歷取任何一個元素,然後我們遞歸時候 取第二個數組,我們再次循環遍歷取任意一個元素,依次循環下去,當我們循環取到數組集合的最後一個數組時,我們的最內層循環結束。此時,讀出我們每一層循環的數組就是所有的情況。以下給出代碼實現如下:

Q3: n個數組任意選取一個元素的所有組合,代碼實現如下:

public static void main(String[] args) {
		List<int[]> arrList= new ArrayList<int[]>();
        arrList.add(new int[]{1,5,9});
        arrList.add(new int[]{2,4});
        arrList.add(new int[]{6,8,3});
        getResult(arrList);
	}
	
	static void  getResult(List<int[]> arrList){
		int n = arrList.size();
		int[] result = new int[n];
	    getNum(arrList,result,n,0);
		
	}
	
	static void getNum(List<int[]> arrList,int[] result,int n,int curIndex){
		if(curIndex < n){ //遞歸結束條件,當前已經在每一個數組都已經取了一個元素
			int[] arr = arrList.get(curIndex);
			for(int i = 0;i<arr.length;i++){
				 result[curIndex] = arr[i];
				 getNum(arrList,result,n,curIndex+1);
			}
		}else{ //遞歸結束時候打印出數組
			print(result);
		}
	}
	
	static void print(int[] result){
		for(int num : result){
			System.out.print(num+"\t");
		}
		System.out.println();
	}
我們可知我們的輸出所有組合應該是3*2*3 = 18種。我們的輸出如下:

1	2	6	
1	2	8	
1	2	3	
1	4	6	
1	4	8	
1	4	3	
5	2	6	
5	2	8	
5	2	3	
5	4	6	
5	4	8	
5	4	3	
9	2	6	
9	2	8	
9	2	3	
9	4	6	
9	4	8	
9	4	3









發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章