1. 程式人生 > >劍指Offer面試題34:醜數 Java實現

劍指Offer面試題34:醜數 Java實現

題目:醜數     我們把包含因子2,3,和5的數稱作醜數(Ugly Number)。求按從小到大的順序的第1500個醜數。例如6,8都是醜數,但14不是,因為它包含因子7.習慣上,我們把1當做第一個醜數。
演算法分析: 1.所謂一個數m是另一個數n的因子,是指n能被m整除。也就是n%m==0. 根據醜數的定義,醜數只能被2,3,5整除。也就是說如果一個數能被2整除,那麼我們就連續除以2;如果能被3整除,就連續除以3;如果能夠被5整除,就連續除以5.如果最後我們能得到1,那個這個數就是醜數,否則不是。該演算法非常直觀,程式碼也很簡潔,但最大的問題是每個整數都需要計算。即使一個數字不是醜數,我們還是需要對它做求餘和除法運算,因此該演算法的時間效率不高。 2.接下來找一種只要計算醜數的方法。 根據醜數的定義,醜數應該是另一個醜數乘以2,3,5的結果。因此我們可以建立一個數組,裡面數字是排好序的醜數,每一個醜數都是前面乘以2,3或者5得到。這種速錄的關鍵在於怎樣確保數組裡面的醜數是拍好序的。假設陣列中已經有若干個醜數排好序後放在陣列中,並且把已有最大的醜數記做M,我們接下來分析如何生成下一個醜數。該醜數肯定是前面某一個醜數乘以2,3或者5的結果,所以我們首先考慮把已有的每個醜數乘以2.在乘以2的時候,能得到若干個小於等於M的結果。由於是按照順序生成的,小於或者等於M肯定已經在陣列中了,我們不需要再次考慮;還會得到若干個大於M的結果,但我們只需要第一個大於M的結果,因為我們希望醜數是按照從小到大的順序生成的,其他的更大的結果以後再說。我們報得到的第一個乘以2後大於M的結果即為M2,同樣,我們把已有的每一個醜數乘以3和5,能得到第一個大於M的結果M3和M5。那麼下一個醜數應該是M2,M3和M5這3個數的最小者。 前面分析的時候,提到把已有的每個醜數分別都乘以2,3,5.事實上這不是必須的,因為已有的醜數都是按順序存放在陣列中的。對乘以2而言,肯定存在某一個醜數T2,排在它之前的每一個醜數乘以2得到的結果都會小於已有的最大丑數,在它之後的每一個醜數乘以2得到的結果都會太大。我們只需記下這個醜數的位置,同時每次生成新的醜數的時候,去更新這個T2.對乘以3和5而言,也存在這同樣的T3和T5. 演算法1源程式:
/**************************************************************      
* Copyright (c) 2016, 
* All rights reserved.                   
* 版 本 號:v1.0                   
* 題目描述:醜數
* 		   	我們把包含因子2,3,和5的數稱作醜數(Ugly Number)。求按從小到大的順序的第1500個醜數。
* 			例如6,8都是醜數,但14不是,因為它包含因子7.習慣上,我們把1當做第一個醜數。 
* 輸入描述:請輸入醜數的順序:
			1500
* 程式輸出:第1500個醜數是:859963392
* 問題分析: 無
* 演算法描述:所謂一個數m是另一個數n的因子,是指n能被m整除。也就是n%m==0. 根據醜數的定義,
* *			醜數只能被2,3,5整除。也就是說如果一個數能被2整除,那麼我們就連續除以2;如果能被3整除,
* *			就連續除以3;如果能夠被5整除,就連續除以5.如果最後我們能得到1,那個這個數就是醜數,否則不是。
* 完成日期:2016-09-21
***************************************************************/

package org.marsguo.offerproject34;

import java.util.Scanner;

class TheNumberIsUgly{
	public int IsUglyFunction(int number){
		
		if(number <= 0)
			return 0;
		int sum = 0;
		int uglynum = 0;
		while(uglynum < number){
			sum++;
			if(UglyNumberFunction(sum)){
				uglynum++;
			}
		}
		return sum;
	}
	private boolean UglyNumberFunction(int number){
//		boolean flag = false;
		while(number%2 == 0){
			number /= 2;
//			flag = true;
		}
		while(number%3 == 0){
			number /= 3;
//			flag = true;
		}
			
		while(number%5 ==0){
			number /= 5;
//			flag = true;
		}
		return (number == 1)? true:false;
	}
}
public class IsUgly {
	public static void main(String[] args){
		Scanner scanner = new Scanner(System.in);
		System.out.println("請輸入醜數的順序:");
		int num = scanner.nextInt();
		System.out.println("num = " + num);
		scanner.close();
		TheNumberIsUgly thenumberisugly = new TheNumberIsUgly();
		System.out.println("第" + num +"個醜數是:" + thenumberisugly.IsUglyFunction(num));
	}
}


演算法2源程式:
/**************************************************************      
* Copyright (c) 2016, 
* All rights reserved.                   
* 版 本 號:v1.0                   
* 題目描述:醜數
* 		   	我們把包含因子2,3,和5的數稱作醜數(Ugly Number)。求按從小到大的順序的第1500個醜數。
* 			例如6,8都是醜數,但14不是,因為它包含因子7.習慣上,我們把1當做第一個醜數。 
* 輸入描述:請輸入醜數的順序:
			1500
* 程式輸出:第1500個醜數是:859963392
* 問題分析: 無
* 演算法描述:所謂一個數m是另一個數n的因子,是指n能被m整除。也就是n%m==0. 根據醜數的定義,
* *			醜數只能被2,3,5整除。也就是說如果一個數能被2整除,那麼我們就連續除以2;如果能被3整除,
* *			就連續除以3;如果能夠被5整除,就連續除以5.如果最後我們能得到1,那個這個數就是醜數,否則不是。
* *			詳見筆記演算法描述
* 完成日期:2016-09-21
***************************************************************/

package org.marsguo.offerproject34;

import java.util.Scanner;

class GetUglyNumber_Method2{
	public int GetUlyNumberFun(int index){
		if(index <= 0){
			return 0;
		}
		int[] uglyNumbers = new int[index];
		uglyNumbers[0] = 1;
		//int nextUglyIndex = 1;
		int i2=0;
		int i3=0;
		int i5=0;
		
		//while(nextUglyIndex < index){
		for(int i = 1; i < index; i++){
			int min = Min(uglyNumbers[i2]*2,uglyNumbers[i3]*3,uglyNumbers[i5]*5);
			System.out.println("min = " + min);
			uglyNumbers[i] = min;				//把min值每次都先輸入到陣列uglyNumbers中,這樣在比較前陣列中就有值了。
			while(uglyNumbers[i2] * 2 <= uglyNumbers[i])
				i2++;
			while(uglyNumbers[i3] * 3 <= uglyNumbers[i])
				i3++;
			while(uglyNumbers[i5] * 5 <= uglyNumbers[i])
				i5++;
			//++nextUglyIndex;
		}
		int ugly = uglyNumbers[index-1];
		return ugly;
	}
	
	private int Min(int number1,int number2,int number3){
		int min = (number1 < number2)? number1:number2;
		min = (min < number3)? min : number3;
		return min;
	}
}

public class UseSpaceChangeTime {
	public static void main(String[] args){
		Scanner scanner = new Scanner(System.in);
		System.out.println("請輸入醜數的順序:");
		int num = scanner.nextInt();
		System.out.println("num = " + num);
		scanner.close();
		
		GetUglyNumber_Method2 getugly = new GetUglyNumber_Method2();
		System.out.println("第" + num +"個醜數是:" + getugly.GetUlyNumberFun(num));
	}
}


相關推薦

Offer試題34 Java實現

題目:醜數     我們把包含因子2,3,和5的數稱作醜數(Ugly Number)。求按從小到大的順序的第1500個醜數。例如6,8都是醜數,但14不是,因為它包含因子7.習慣上,我們把1當做第一個醜數。 演算法分析: 1.所謂一個數m是另一個數n的因子,是指n能

offer 試題49

 題目:把只包含質因子2、3和5的數稱作醜數(Ugly Number)。例如6、8都是醜數,但14不是,因為它包含質因子7。 習慣上我們把1當做是第一個醜數。求按從小到大的順序的第N個醜數。 思路:用一個數組,三個指標,index2,index3和index5,給每個元素乘以2,3,5

Offer 試題34二叉樹中和為某一值的路徑 Java程式碼實現

題目:輸入一棵二叉樹和整數,打印出二叉樹中節點值得和為輸入整數的所有路徑。從樹的根節點開始往下一直到葉節點所經過的節點形成一條路徑。 解題思路:路徑從根節點開始,應該用類似於前序遍歷的方式訪問樹節點。

offer--試題28:字串的排列--Java實現

題目描述: 輸入一個字串,打印出該字串中字元的所有排列。例如輸入字串abc,則打印出由字元a、b、c所能排列出來的所有字串abc、acb、bac、bca、cab和cba。 解題思路: 我們求整個字串的排列,可以看成兩步,首先求可能出現在第一個位置上的字元,

leetcode 240. 搜尋二維矩陣 II【陣列】【Medium】&&Offer試題4二維陣列中的查詢

題目: 編寫一個高效的演算法來搜尋 m x n 矩陣 matrix 中的一個目標值 target。該矩陣具有以下特性: 每行的元素從左到右升序排列。 每列的元素從上到下升序排列。 示例: 現有矩陣 matrix 如下: [

offer 試題50字元流中第一個只出現一次的字元

題目描述:請實現一個函式用來找出字元流中第一個只出現一次的字元。例如,當從字元流中只讀出前兩個字元"go"時,第一個只出現一次的字元是"g"。當從該字元流中讀出前六個字元“google"時,第一個只出現一次的字元是"l"。 解法: 使用雜湊表occurance[256] ;  初始化o

offer 試題19正則表示式匹配

請實現一個函式用來匹配包括'.'和'*'的正則表示式。模式中的字元'.'表示任意一個字元,而'*'表示它前面的字元可以出現任意次(包含0次)。 在本題中,匹配是指字串的所有字元匹配整個模式。例如,字串"aaa"與模式"a.a"和"ab*ac*a"匹配,但是與"aa.a"和"ab*a"均不匹配 c

offer 試題20表示數值的字串

請實現一個函式用來判斷字串是否表示數值(包括整數和小數)。例如,字串"+100","5e2","-123","3.1416"和"-1E-16"都表示數值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。 可以用A[.[B]][e|EC]或者.B[e|EC

offer 試題28對稱的二叉樹 c++

題目:請實現一個函式,用來判斷一顆二叉樹是不是對稱的。注意,如果一個二叉樹同此二叉樹的映象是同樣的,定義其為對稱的。(要想象一下他的結構) 思路:遞迴判斷,左子樹的左子樹和右子樹的右子樹比較,左子樹的右子樹和右子樹的左子樹比較,若相等則是,否則不是。 class Solution { pub

offer 試題57刪除連結串列中的重複節點 c++

本題有兩種 第一題:在一個排序的連結串列中,存在重複的結點,請刪除該連結串列中重複的結點,重複的結點不保留,返回連結串列頭指標。 例如,連結串列1->2->3->3->4->4->5 處理後為 1->2->3->4->5  

offer 試題8二叉樹的下一個節點 c++

題目:給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點並且返回。注意,樹中的結點不僅包含左右子結點,同時包含指向父結點的指標。 解析:三種情況:1.若節點有右子樹,中序下一個就是 右子樹最左孩子節點  2.若無右子樹,且當前節點是父節點的左子節點,下一個就是父節點 &nb

offer-試題1賦值運算子函式

如下為型別CMyString的宣告,請為該型別新增賦值運算子函式。 解析:給一個類進行運算子過載。 關鍵部分程式碼: CMyString& CMyString::operator =(const CMyString &str) { if(this == &str)

offer 試題42左旋轉字串vs翻轉單詞順序 c++

題目:組合語言中有一種移位指令叫做迴圈左移(ROL),現在有個簡單的任務,就是用字串模擬這個指令的運算結果。對於一個給定的字元序列S,請你把其迴圈左移K位後的序列輸出。例如,字元序列S=”abcXYZdef”,要求輸出迴圈左移3位後的結果,即“XYZdefabc”。是不是很簡單?OK,搞定它!

offer 試題41和為s的兩個數字vs和為s的連續正數序列 c++

題目:輸入一個遞增排序的陣列和一個數字S,在陣列中查詢兩個數,使得他們的和正好是S,如果有多對數字的和等於S,輸出兩個數的乘積最小的。 思路:兩個 指標,start從前往後遍歷,end從後往前遍歷,如果當前前後之和大於s,end--,如果當前前後之和小於s,start++,這樣能找出乘積最小的和

offer 試題41資料流中的中位數 c++

題目:如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。 思路:資料流的中位數最好使用兩個堆,這樣可以動態維護插入和獲得中位數的過程。可以使用一個大頂堆和一個小

offer{試題32求從1到n的整數中1出現的次數}

思路:map.get獲得出現次數 import java.util.HashMap; public class Solution { public int FirstNotRepeatingChar(String str) { int len = str.length(); if(len =

offer{試題31連續子陣列的最大和}

思路: public class test31 { public int findMaxSum(int[] arr) { if(arr.length==0) return 0; int cur = arr[0];

offer{試題25二叉樹中和為某一值的路徑}

思路:這道題比較有意思,類似的題我在面試裡經常遇到過,圍繞著樹的深度遍歷和廣度遍歷做文章,針對這種型別的題,大家更多考慮的解決方案是遞迴,說白了二叉樹就是一群小二叉樹,上次做寶寶樹的筆試題的時候,出的演算法題就是求任意兩個節點之間的最遠距離,說白了還是遍歷的問題,回到這道題  &n

offer{試題24二叉搜尋樹的後序遍歷序列}

這個題似曾相識,之前劍指offer有一道題是判斷該子樹是否是樹的一部分,有異曲同工之妙,看到這種題,上倆就應該想遞迴。 public class Solution { public boolean VerifySquenceOfBST(int [] sequence) {

offer{試題23從上往下列印二叉樹}

簡單的二叉樹層序遍歷,利用佇列的先進先出結構 關於層序遍歷層序遍歷 貼程式碼 public class Test23 { /** * 二叉樹的樹結點 */ public static class BinaryTreeNode { int