前言
博客停止更新一個多月了,之前還下定決心說每週一篇面試題相關的博客的,不過 16 年 12 月到 現在 17 年 3 月過得還是挺充實的,而且也從中學習到了很多;特別在沒更新博客這一段時間了,試過了三天只睡了 12 個小時,只爲心裏的那份信仰。好了,不扯淡了,之後繼續更新博客,現在(2017年3月19日00:13:32) 12 點了,看了一些面試題,最終選了 2016 美團研發工程師筆試題的其中一道題來寫這篇博客。
題目
從2到5中選兩個數,第一個數較大,將兩數之和告訴甲,兩數之差告訴乙,兩個人根據自己手上的數都算不出來答案,求這兩個數分別是多少?
A. 4,3
B. 5,3
C. 5,2
D. 4,2
解題
看到這題,第一個想法就是排除法來解了,那麼,我們一個一個答案來分析:
- A 選項中,甲得到的兩數之和爲 7 , 乙得到的兩數之差爲 1 ,因此甲從 2 到 5 這四個數中,能組成兩數之和爲 7 的組合有 (5 , 2) 和 (4 , 3) ,乙組成兩數之差爲 1 的組合有 (3 , 2) , (4 , 3) 和 (5 , 4) ,因此兩個人都算不出答案
- B 選項,兩數爲 5 和 3,因此兩數之和爲 8 ,甲得到數爲 8 ,可以猜到的組合就只有 (5 , 3)了,因爲題目是說明甲乙兩個人都算不出答案,因此排除 B 選項
- C 選項中,兩數爲 5 和 2 ,因此兩數之差爲 3 ,乙得到的數爲 3 ,從 2 到 5 中的組合就只有(5 , 2),因此排除 C
- D 選項中,兩數和爲 6,組合只有 (4 , 2) , 所以排除 D
拓展
上面的題目是不是挺簡單的,那麼來拓展一下,看一道類似的經典題目【鬼谷子問徒】
孫臏,龐涓都是鬼谷子的徒弟。一天鬼谷子出了這道題目:
他從 2 到 99 中選出兩個不同的整數,把積告訴孫臏,把和告訴龐涓;
龐涓說:我雖然不能確定這兩個數是什麼,但是我肯定你也不知道這兩個數是什麼。
孫臏說:我本來的確不知道,但是聽你這麼一說,我現在能夠確定這兩個數字了。
龐涓說:既然你這麼說,我現在也知道這兩個數字是什麼了。
請問這兩個數字是什麼?爲什麼?
這道題目一定要看,用上面的方法解決太麻煩了吧,先直接寫個窮舉來看下答案吧
package com.liangdianshui;
/**
* <p>鬼谷子問徒[經典] 孫臏,龐涓都是鬼谷子的徒弟。一天鬼谷子出了這道題目: 他從2到99中選出兩個不同的整數,把積告訴孫臏,把和告訴龐涓;
* 龐涓說:我雖然不能確定這兩個數是什麼,但是我肯定你也不知道這兩個數是什麼。
* 孫臏說:我本來的確不知道,但是聽你這麼一說,我現在能夠確定這兩個數字了。
* 龐涓說:既然你這麼說,我現在也知道這兩個數字是什麼了。 請問這兩個數字是什麼?爲什麼?
* </p>
*
* @author Administrator
*
*/
public class DigitalProblem {
public static void main(String[] args) {
for (int n = 6; n < 200; ++n) // 窮舉和的可能,最大不超過200
{
// 其和能同時滿足條件1和3者即爲結果
if (p1(n) && p3(n)) {
// 找出對應解
for (int t = 2; t * 2 < n; ++t) {
if (p2(t * (n - t))) // 分拆結果符合條件2就輸出
System.out.println("(" + t + "," + (n - t) + ")");
}
}
}
}
/**
* 是否是唯一分解
*
* @param n
* @param nMax
* 最大值爲100
* @return
*/
public static boolean isOnlySolve(int n, int nMax) {
int nRet = 0; // 記錄滿足本條件數
for (int i = 2; i * i < n; ++i) {
if (n % i == 0 && n / i < nMax)
if (++nRet > 1) {
return false;
}
}
return true;
}
/**
* sum的任意和的分拆之積不可能有唯一分解,否則對方可能猜出
* <p>
* 我雖然不能確定這兩個數是什麼,但是我肯定你也不知道這兩個數是什麼。
* </p>
*
* @param sum
* @return
*/
public static boolean p1(int sum) {
if (sum < 6)
return false;
for (int t = (sum - 1) / 2; t > 1; --t) {
if (isOnlySolve(t * (sum - t), 100))
return false;
}
return true;
}
/**
* 只有一種積的分拆滿足 p1
* <p>
* 我本來的確不知道,但是聽你這麼一說,我現在能夠確定這兩個數字了
* </p>
*
* @param times2
* @return
*/
public static boolean p2(int times2) {
int nRet = 0; // 記錄滿足本條件數
for (int nd = 2; nd * nd < times2; ++nd) {
if (times2 % nd == 0 && p1(nd + times2 / nd))
if (++nRet > 1)
return false;
}
return true;
}
/**
* 只有一種和的分拆滿足 p2
* <p>
* 既然你這麼說,我現在也知道這兩個數字是什麼了
* </p>
*
* @param sum
* @return
*/
public static boolean p3(int sum) {
int nRet = 0; // 記錄滿足本條件數
for (int t = (sum - 1) / 2; t > 1; --t) {
if (p2(t * (sum - t)))
if (++nRet > 1)
return false;
}
return true;
}
}
運行的結果爲:
有人直接邏輯推理出來的嗎?在評論那裏寫下可好,讓我學習學習