有時候面試官往往會問我們一些簡單,但又刁難的問題,主要是看看你對問題的處理思路。如果你沒接觸過這些問題,可能一時之間還真不知道怎么處理才比較好,這種題更重要的是一種思維的散發吧,今天就來分享幾道題面試中遇到的算法題(當然,不是我自己遇到過,是別人遇到過,我挑選出來的)
案例1
題目描述:求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。
我去,求和居然不讓用乘除法,也不准我們用循環,如果單獨這兩個限制的話還好,我們還可以用地遞歸,例如:
int f(int n){
if(n == 0){
return n;
}else{
return f(n-1) + n;
}
}
然后 if, else, case 等各種關鍵字也不給用,想着那我用三元運算符(A?B:C),然后這種具有判斷語句的三元運算符也不給用,我去,這也太刁難了吧(當然,大佬直接秒殺的可以飄過)。
這道題肯定是必須用遞歸來解決的,而這遞歸的核心就是需要判斷一下遞歸條件是否結束了,然而題目不准我們使用條件判斷語句。那我們該怎么辦呢?大家可以散發思維想一下哦。
其實我們可以下面這樣的語句來代替 A?B:C 這樣具有判斷能力的三元運算符
n != 0 && (f(n-1) + n) != 0;
這個 && 邏輯判斷符的作用就是:如果 n != 0 成立的話,那么邏輯判斷符后面的判斷語句 (f(n-1) + n ) != 0 也會執行,如果 n != 0 不成立的話,那么后面的判斷語句 ((f(n-1) + n)) != 0 就不會執行,通過這種方法,就可以達到我們遞歸結束條件判斷的目的了。
這里說明一下,(f(n-1) + n) != 0 這條判斷語句是沒有任意其他含義的,我們的目的是為了執行 f(n-1)+n,之所以加上個 != 0 的判斷,是因為邏輯判斷符號 && 只支持 boolean 類型,不支持 int 類型。
最后的代碼如下
public int f(int n) {
int sum = n;
boolean t = (n != 0) && (sum += f(n - 1))!= 0;
return sum;
}
如果你做過這種類型的題,可能就會覺得很簡單了,如果沒做過,可能就需要思考一下,不過,往后你就可以直接秒殺了。
案例 2
題目描述:寫一個函數,求兩個整數之和,要求在函數體內不得使用+、-、*、/四則運算符號。
我去,求和不准加減乘除!面試官,能不能別這么任性,好好的加減乘除居然不給用。
不過我相信大家第一時間都能想到用位運算來解決,可能在大學期間學過電路相關知識的一下就能把代碼寫出來了,不過有些人也能可能是一個位一個位來處理的。例如我先處理第一個位(這里指的是二進制位哈),看看有沒進位,然后處理第二個位,如果第一個位有進位就加到第二個位來,然后處理第三個位.....
如果你是這種方法處理的,那么恭喜你,看完這道題你能有所收獲。實際上上面那種解法也可以,只是太復雜了,可能各種判斷。其實這道題可以這樣解:這里為了方便講解,我先給出代碼,再給出具體的講解,你看完代碼再來看講解可能更好理解
public int Add(int num1,int num2) {
int tmp = 0;
while(num1 != 0){
tmp = num1 ^ num2;
num1 = (num1 & num2) << 1;
num2 = tmp;
}
return num2;
}
大家想一個問題,如果我們把兩個數進行異或,例如num1 = 101, num2 = 001,做異或運算:tmp = num1 ^ num2,結果是 tmp = 100。那么此時得到的結果 tmp 其實就是兩個數(num1,num2)各個二進制位上相加,不算進位的結果。而 num1 = (num1 & num2) << 1 的結果就是兩個數相加時那些需要進位的二進制位。例如 (101 & 001)<< 1 = 010,那么兩個數第一位相加需要進位,我們需要把進的那一位最后加到第二位上去。
好像有點繞,,大家可以動手試一下哈,說白就是 a + b = a ^ b + (a & b) << 1。
代碼中,如果 num1 == 0 的話,代表沒有進位了,此時就可以退出循環了。
對於很少用位運算的人來說可能有點懵,那么我建議可以多看幾遍,然后一遍動手模擬哈。以后遇到這種題就可以直接秒殺了。
案例3
在這里我先聲明一下,案例3 也不算一道刁難題,只是我來考考你們而已,大家看到題目之后可以自己想一下哈,看了答案不能打我哈。
題目描述:實現兩個整數的相乘,不能使用乘法運算符和循環
各位老哥可以想一下哈。
這道題可能很多人都想到用遞歸了,好像我說的大部分算法題,都會用到遞歸,所以說你不懂遞歸的話,看我的公眾號就行了,不懂也得變懂了是不是。代碼如下:
int mul(int a, int b){
if (a == 0 || b == 0)
return 0;
if (b == 1)
return a;
if (a == 1)
return b;
return a + mul(a, b - 1);
}
int mult(int a,int b){
// 這里我們取 b 的絕對值
int sum = mul(a, abs(b));
return (b<0)?(-sum):sum;
}
你是不是這樣做的呢?其實,我們還有更好的方法哦,如下
我去,不能使用乘法,又沒說不能使用除法,那我用除法來代替乘法就得了,例如 a 乘以 b 就相當於 a 除以 b 分之一。代碼如下:
int mult2 (int a,int b){
return b != 0 ? (int)(a / (1.0 / b) + 0.99 ): 0;
}
這里需要 int 進行轉化類型,並且除法可能會導致后面尾數的丟失,所以我補了個 0.99。注意,進行 int 類型轉化時,不是四舍五入的哈,二手小於 1 就行當做 0 處理。當然,我這里用的是 Java 語言,其他語言自己看情況處理。
總結
今天的幾道題,更多的是一種投機取巧吧,不過看你看到一到陌生的題目時,你會如何處理,點子多不多,這個還是挺重要滴,而多看一些點子,慢慢着你的點子也會變多了。
如果你覺得這篇內容對你挺有啟發,為了讓更多的人看到這篇文章:不妨
1、點贊,讓更多的人也能看到這篇內容(收藏不點贊,都是耍流氓 -_-)
2、關注我和專欄,讓我們成為長期關系
3、關注公眾號「苦逼的碼農」,主要寫算法、計算機基礎之類的文章,里面已有100多篇原創文章
大部分的數據結構與算法文章被各種公眾號轉載相信一定能讓你有所收獲
我也分享了很多視頻、書籍的資源,以及開發工具,歡迎各位的關注我的公眾號:苦逼的碼農,第一時間閱讀我的文章。