1. 程式人生 > >面試官,求求你不要問我這麼簡單但又刁難的演算法題了

面試官,求求你不要問我這麼簡單但又刁難的演算法題了

有時候面試官往往會問我們一些簡單,但又刁難的問題,主要是看看你對問題的處理思路。如果你沒接觸過這些問題,可能一時之間還真不知道怎麼處理才比較好,這種題更重要的是一種思維的散發吧,今天就來分享幾道題面試中遇到的演算法題(當然,不是我自己遇到過,是別人遇到過,我挑選出來的)

案例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多篇原創文章


大部分的資料結構與演算法文章被各種公眾號轉載相信一定能讓你有所收穫

我也分享了很多視訊、書籍的資源,以及開發工具,歡迎各位的關注我的公眾號:苦逼的碼農,第一時間閱讀我的文章。