[算法] 两个质数的乘积是707829217,求解该质数
記錄一次有趣的算法題。
土生土長的北京妞兒,在胡同里長大,房不多,就一個四合院和近郊的別墅。不算美如天仙但還算標致,在清華讀的經管,現在在做基金經理(不想被人肉,就不暴露單位啦) ,個人擅長基本面分析,價值投資。現在只想找個聰明靠譜的IT男。硬性要求是年齡,不要超過88年,還有不要特別矮或胖。我對智商的要求比較高,下面就出個題測試下。
我的微信ID是大寫字母NY后面跟著兩個質數,大的在前,小的在后,乘積是707829217,可直接搜索添加,另外還有個附加題目,在剛剛微信ID的數字中,從1開始到這個數字的奇數序列里,一共出現了多少個3,如果私信我正確的答案,我將直接邀你見面!期待緣分降臨~
問題1 求解微信號
// 兩個質數的乘積是707829217,求質數int num = 707829217;int i = 1;while (i <= num) {i += 2;if (num % i == 0) {System.out.println("發現: " + num + " / " + i + " = " + (num / i));}}打印結果:
發現: 707829217 / 8171 = 86627 發現: 707829217 / 86627 = 8171 發現: 707829217 / 707829217 = 1Process finished with exit code 0所以我們得到第一問的答案:NY866278171
問題2 求解奇數序列中,3出現的次數
我們看到這個數值866278171,為8億多,去掉偶數,只看奇數,也有4億多。
問這4億個數中3出現了多少次,這個問題有點費解。
方式一 暴力破解
所謂暴力破解,就是遍歷每一個數值,統計3出現的次數。下面的各個版本僅供參考:
該方案耗時:2m 52s 139ms
// 奇數序列中,一共出現了多少次3int number = 866278171;int sum = 0;for (int i = 1; i <= number; i = i + 2) {sum += String.valueOf(i).replace("3", "_#_").split("#").length - 1;}// 總數: 441684627System.out.println("總數: " + sum);該方案耗時:1m 41s 259ms
// 奇數序列中,一共出現了多少次3int number = 866278171;int sum = 0;for (int i = 1; i <= number; i = i + 2) {String str = String.valueOf(i);if (str.contains("3")) {sum += str.length() - str.replace("3", "").length();}}// 總數: 441684627System.out.println("總數: " + sum);該方案耗時:22s 942ms
// 奇數序列中,一共出現了多少次3int number = 866278171;int sum = 0;for (int i = 1; i <= number; i = i + 2) {String str = String.valueOf(i);for (int j = 0; j < str.length(); j++) {if (str.charAt(j) == '3') {sum++;}}}// 總數: 441684627System.out.println("總數: " + sum);該方案耗時:6s 669ms
// 奇數序列中,一共出現了多少次3int number = 866278171;int sum = 0;for (int i = 1; i <= number; i = i + 2) {int k = i;while (k > 1) {if (k % 10 == 3) {sum++;}k /= 10;}}// 總數: 441684627System.out.println("總數: " + sum);我們看到,走了好多的彎路,String類中的replace和contains都是重量級方法。當我們使用有限次數時,并不會感覺到慢。但是當我們需要重復執行上億次時,就很慢了。
方式二 公式法
規律總結
- 對于1位數
- 對于2位數:
- 對于3位數:
- 對于4位數:
好像有點規律了。。
對于任意N位數,3出現的次數為 n * 10^(n-1)
翻譯成代碼:
/*** 任意N位數,3出現的次數*/public double anyN(int n) {if (n < 1)return 0;return n * Math.pow(10, n - 1);}問題來了,對于一個有限度的N位數,3出現了多少次?
比如: 0 ~ 2918,3出現了多少次?拆分下: 0 ~ 2000區間段, 可以理解為2個1000,也就是2個任意3位數,所以 :2 * 300 + 0 (對于任意3位數3出現的次數為300,不包含3000~3999 整個以3開頭的千位數) 2000 ~ 2900區間段, 可以理解為9個100,也就是9個任意2位數,所以:9 * 20 + 100( 任意2位數3出現的次數為20,包含300-399 整個以3開頭的百位數) 2900 ~ 2910區間段, 可以理解為1個10,也就是1個任意1位數,所以:1 * 1 + 0( 任意1位數3出現的次數為1,不包含30-39 整個以3開頭的十位數) 2910 ~ 2918區間段, 只看個位數,0 ~ 8,包含一個3,所以: 1 綜合起來就是: (2 * 300 + 0)+(9 * 20 + 100) + (1 * 1 + 0) + (1)= 600+280+1+1 = 882我們拆開翻譯,
- 步驟1
對于0 ~ n * 10^w 的數,3出現了多少次。
比如0~100,0~4000,0~800000000
- 步驟2
對于任意0 ~ N, 3出現了多少次
/*** 計算0~N的數中,3出現的次數*/public int anyNumCount3(int anyN) {double sum = 0;int number = anyN;int count0 = 0;while (number > 1) {int n = number % 10;sum += count3(n, count0);if (n == 3) {// 如果該位為3,需要將低位數再加一遍。// 比如 389,[300,389]共89+1=90個sum += (anyN % Math.pow(10, count0)) + 1;}number /= 10;count0++;}return (int) sum;}該方案耗時:1ms ?
至此,我們通過找規律,發現了對于[0~N]中3出現的次數的公式。
只看奇數序列
針對本題的只看奇數序列,我們總結下規律:
奇數,也就是限定了個位數只能是1、3、5、7、9共5種選擇,而更高位可以是0-9共十種選擇。
對于任意N位奇數
- 對于1位數
- 對于2位數:
- 對于3位數:
- 對于4位數:
規律:對于任意N位數,只看奇數,3出現的次數為1*10^(n-1) + (n-1)*5*10^(n-2)
翻譯成代碼:
/*** 任意N位奇數,3出現的次數* e.g: 9999 n = 4*/public int anySingleN(int n) {// 1*10^3 + 3*5*10^2if (n < 1) return 0;double sum = Math.pow(10, n - 1);if (n >= 2) {sum += (n - 1) * 5 * Math.pow(10, n - 2);}return (int) sum;}對于有限制的N位奇數,3出現的次數
- 比如:4000以內的奇數
4個任意三位奇數 + 3開頭的,任意4位奇數。即4*anySingleN(3) + 10*10*5
翻譯成代碼:
/*** 計算一個 [ 0 , n*10^w ) 的奇數中,3出現的次數* <p>* e.g: 4000 n = 4 , w = 3** @param n 數值* @param w 0的個數* @return*/public int countSingle3(int n, int w) {// 4 * anySingleN(3) + 5*10^2if (w < 1)// 個位數return (n >= 3) ? 1 : 0;double sum = n * anySingleN(w);if (n > 3) {sum += 5 * Math.pow(10, w - 1);}return (int) sum;}- 對于0~N的任意奇數中,3出現的次數
該方案耗時:1ms ?
至此,我們通過找規律,發現了對于[0,N]奇數序列中3出現的次數的公式。
總結
我們通過 方案一 暴力破解 和 方案二 公式法 來解決了這個問題。
速度對比那就更不用說了
總結
以上是生活随笔為你收集整理的[算法] 两个质数的乘积是707829217,求解该质数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ECE220生存指南[02] MP7:
- 下一篇: Excel里面方框打勾