魔法數字
題目:
一天,牛妹找牛牛做一個游戲,牛妹給牛牛寫了一個數字n,然后又給自己寫了一個數字m,她希望牛牛能執行最少的操作將他的數字轉化成自己的。
操作共有三種,如下:
1.在當前數字的基礎上加一,如:4轉化為5
2.在當前數字的基礎上減一,如:4轉化為3
3.將當前數字變成它的平方,如:4轉化為16
你能幫牛牛解決這個問題嗎?
給定n,m,分別表示牛牛和牛妹的數字。
分析:
我自己的解決策略:
使用兩個集合分別表示當前元素集和下一次的元素集,然后交叉使用。當元素集中出現m元素時終止計算。
本質上屬于窮舉策略,并且會進行過多的重復計算,導致時間復雜度不滿足題目要求。
code:
1 /** 2 * 解決策略:使用當兩個集合 3 * 集合1:存放上一步運算出的元素 4 * 集合2:存放集合1運算出的元素 5 * 兩個集合交替使用,當運算出m時終止。 6 * 本質上屬于窮舉策略,且會進行大量的重復運算。 7 * 8 *v1版本:運行時超時 9 * @param n 10 * @param m 11 * @return 12 */ 13 public static int solve (int n, int m) { 14 // write code here 15 Set<Integer>[] sets = new Set[2]; 16 sets[0] = new HashSet<>(); 17 sets[1] = new HashSet<>(); 18 int count=0; 19 int i,j; 20 sets[0].add(n); 21 boolean flag = false; 22 23 while(!flag) { 24 i = count % 2; 25 j = (count + 1) % 2; 26 Iterator<Integer> iterators = sets[i].iterator(); 27 while (!flag && iterators.hasNext()) { 28 Integer v = iterators.next(); 29 int v1 = v + 1; 30 int v2 = v - 1; 31 int v3 = v * v; 32 if (v1 == m || v1 == m || v3 == m) { 33 flag = true; 34 } else { 35 sets[j].add(v1); 36 sets[j].add(v2); 37 sets[j].add(v3); 38 } 39 } 40 sets[i].clear(); 41 count++; 42 } 43 return count; 44 }
分析的大佬的代碼:
使用遞歸策略,逐步縮小問題。
1、當m<=n,直接結束,返回n-m。
2、當m>n。開始遞歸。
對m開平方,且自動向下取整獲得k。
1.分別獲得m與k平方的差值v1和m與k+1的平方的差值v2。
2.比較v1和v2,如果v1>v2則k自增。然后將確定的k作為下一次迭代的m。
code:
/** * 分析的別人的代碼: * * 返回最后要輸出的答案 * @param n int整型 表示牛牛的數字 * @param m int整型 表示牛妹的數字 * @return int整型 * 策略解讀: * 1、m<=n * result = n-m * 2、m>n * m開平方,自動向下取整得到k * 1.計算m與k平方的差值v1 * 2.計算m與k+1平方的差值v2 * 差值采用加或減的策略 * 3、比較v1和v2,確定k的真正取值。將k作為新的m進行迭代運算。 * * */ public static int solve (int n, int m) { // write code here if (m <= n) return n - m; int k = (int) Math.sqrt((double) m); if (m - k * k > (k + 1) * (k + 1) - m) k++;//如果k平方與m的差值大于k+1平方與m的差值,則迭代計算n,k+1的操作數 return Math.min(m - n, solve(n, k) + 1 + Math.abs(m - k * k)); //1表示k的平方操作 }

浙公網安備 33010602011771號