1. 程式人生 > >《演算法設計手冊》面試題解答 第一章:演算法設計簡介

《演算法設計手冊》面試題解答 第一章:演算法設計簡介

目錄

系列簡介:

  《演算法設計手冊》(The Algorithm Design Manual)是本比較經典的演算法書了。如果說《演算法導論》偏向於數學,那麼《演算法設計手冊》更偏向於工程應用(至於《計算機程式設計藝術》,目前我是沒時間通讀,只是偶爾當工具書查查,就不提了)。前者的課後題中的面試題部分挺潮的,如果在google上搜索一下,發現很多都是名企考過的,或許是因為第二版出版時間比較近的緣故?我不大相信是作者自己出的然後被大公司拿去面試的,而是作者收錄的考過的面試題。有了這一層篩選,這些面試題質量有保證啊。

  由於看的是英文版,大部分題都是我翻譯過來的,個人英文水平有限,有的不好理解的地方儘量參照相關解答來理解,並諮詢了在國外留學的朋友,可能仍有些措辭不準確或有誤的地方,懇求諒解並歡迎提出

。同時,有的題目用到的比較冷僻的知識可能會和正文有關係,這種情況會明確註明。

  雖然官方網站上有個wiki answer提供了大多數答案,不過有的不很合適,我寫的和整理的都是比較好的解答。

第1章:

1-28

  不用*和/計算整數除法。請找出最快的方式。

解答:

  雖然初始化一個計數變數,每當被除數減去除數的一次就自增一直到被除數小於除數這個暴力解法可行,但顯然很慢。這是wiki answer答案,但它在很多情況下都不快,比如100/1。其執行的次數正好和相除的結果相同,用m表示除數,n表示被除數,時間複雜度是O(m/n)。

// Note: This only works for positive values!
int divide(int numerator, int denominator) { int quotient = 0; while(numerator >= denominator) { numerator -= denominator; quotient++; } return quotient; }

   下面看看另一種解法。

  一般限制使用*和/時,很容易考慮使用位移運算來替代,因為對於無符號數,左移一位(在不溢位時)相當於乘以2,右移一位相當於除以2。如果在紙上進行除法的筆算,是隻用到了乘法和減法的。但是一般的十進位制整數除法和位運算有什麼關係呢?為了將兩者建立聯絡,必須把十進位制數轉化成二進位制數,觀察除法的進行情況來找規律。比如100/7,寫成二進位制來進行筆算,計算過程如下圖:

  這樣就簡單了,從這個式子可以看出,二進位制除法筆算只涉及了減法和隱含的移位與大小比較,原先的乘法已經被移位所代替。因此,具體的編碼,就是把用筆算除法的過程轉化成程式碼而已。

  不過,一般考慮使用除法的環境,必然要考慮除數是否為0。除數為0時這個除法是非法的,不能繼續進行,需要報錯。

  既然提到了編碼,如果使用C語言來完成,要注意的是:在C標準中,帶符號數右移的結果在C語言裡是實現相關的,具體結果取決於實現,而不一定是用符號位補、用1補或者用0補最高位。為了避免這個陷阱,建議先確定結果——也就是商的符號,然後把被除數和除數都轉化為無符號數,這樣位移時就不會出錯。

  但是,這又涉及了有帶符號數與無符號數的轉換,它們二者的表示範圍的問題是不同的。好在被除數和除數從帶符號數轉化為無符號數時並不會丟失資料,而且商的絕對值必然小於被除數的絕對值(因為除數是整數,為0時報錯,大於等於1時才繼續進行),這時把商轉化迴帶符號數時也不會丟失資料,可以放心的進行。不過這一點最好在面試時告訴面試官你已經注意到了這個問題,肯定會為你的印象加分。

int division(int m,int n) {
    //calculate m/n without * and /
    unsigned int rest,divisor, op,result = 0;
    int flag;
    int bits = 0;
    //bits用於記錄商的1在哪一位
    assert(n!=0);
    if((m<0 && n>0) || ( m>0 && n<0 ))
        flag = -1;
    else
        flag = 1;
    rest = m>0?m:-m;
    divisor = n>0?n:-n;
    if(rest < divisor)
        return 0;

    op = divisor;

    /*            2013.8.30           */
    /*經過部落格園園友infinityu的提醒重寫 */
    while(op<=rest) {
        bits++; 
        op=op<<1;
    }
    op=op>>1;
    bits--;

    while(op>=divisor) {
        if(rest>=op) {
            rest-=op;
            result += 1<<bits;
        }
        op = op>>1;
        bits--;
        
    }
    /*      重寫部分結束         */

    return flag * result;
}

  由於需要把被除數轉化為二進位制進行計算,最多做了其二進位制表示位數次的減法,因此對於被除數m,演算法複雜度為O(logm)。

  稍作修改,把最後的小於除數divisor的result取出就是餘數,這樣就能把除法運算改寫為取模運算%了。如果把引數表修改為傳遞結果地址,同時獲得商和餘數也是可以的。

  可見,這一道面試題考到了演算法優化、除法除數為0這個常見錯誤、將除法從十進位制引申到二進位制、二進位制的位運算、語言特性中的無符號數和帶符號數的位移、無符號數和帶符號數的相互轉換,你還可以更進一步探討演算法複雜度、以及演算法的擴充套件性,確實很能考察被面試者對演算法的掌握情況。

  p.s.經過園友的提示,發現原始碼中有bug,重寫之後已經對1~1000之間所有整數相互相除的測試。為了便於記錄商的1應該在哪一位,使用變數bits來指示。

1-29:

  25匹馬,一次最多5匹馬比賽,如何用最少的比賽次數找到最快的前三匹馬?(假設所有馬的速度在每場比賽的發揮都一樣且各匹馬之間不相同,比賽時無法記錄具體每匹馬跑完全程的時間)

解答:

  老生常談的問題,關鍵是找出每次的正確候選以及儘量利用上次比賽獲得的資訊

  先分5組A、B、C、D、E,組內比賽,假設A1為A組第一。一共5場。

  將A1~E1進行比賽,不妨設第一是A1,那麼最快就是A1。

  第二快只能在A2、B1~E1中出現。同時,這時知道了B1~E1的速度,不妨B1>C1>D1>E1,這樣D1、E1以及整個D組和E組可以被排除出第二和第三的候選。同時,C2必然不可能是第三快。這時候選為A2、A3、B1、B2、C1,比賽一次,前兩名即為第二和第三。

  (注意:這裡分析時沒有"充分"利用所有已知資訊。更進一步利用已知資訊的方式請看擴充套件1。

  綜上,一共比賽了7次。

擴充套件1:

  64匹馬,每次最多8匹比賽,要求用最少場次獲得前4名。其他條件同上題。

 解答:

  按照上題的分析方式並不能得到最少比賽次數,下面看看如何充分利用已知資訊來達到最少比賽次數。

  首先分8組A~H決出各組順序,共需8場,並且組內順序排列為A1>A2>...>A8。

  第一名在A1~H1中決出,不妨設為A1>B1>...>H1,需要1場比賽。

  此時第二名只能是A2和B1其中之一(不同於上題分析,C1~H1其實可以直接拋棄),但決出第二名只用兩個賽道太浪費了。為此進一步分析,如果A2>B1,那麼第3名只能是A3、B1之一;如果B1>A2,那麼第3名只能是A2、B2、C1。這兩種情況都只涉及5匹馬仍然不滿8匹。用這種思路進行全面分析,表示為樹狀並把葉子處需要比較的馬的編號進行標註:

  角逐第2名時A2>B1

    第3名候選A3,B1

    角逐第3名時A3>B1

      第4名候選A4,B1     ————(A2,A3,A4,B1)

    角逐第3名時A3<B1

      第4名候選A3,B2,C1    ————(A2,A3,B1,C1)

  角逐第2名時A2<B1

    第3名候選A2,B2,C1

    角逐第3名時A2>B2>C1

      第4名候選B2,A3     ————(A2,A3,B1,B2,C1)

    角逐第3名時A2>C1>B2

      第4名候選C1,A3————(A2,A3,B1,B2,C1)

    角逐第3名時B2>A2>C1

      第4名候選A2,B3     ————(A2,B1,B2,B3,C1)

    角逐第3名時B2>C1>A2

      第4名候選B3,C1————(A2,B1,B2,B3,C1)

    角逐第3名時C1>A2>B2

      第4名候選A2,C2,D1————(A2,B1,B2,C1,C2,D1)

    角逐第3名時C1>B2>A2

      第4名候選C2,B2,D1————(A2,B1,B2,C1,C2,D1)

  可見,如果能夠一次比賽獲得A2,A3,A4,B1,B2,B3,C1,C2,D1的完整排列次序才能知道前2~4名。很可惜一共是9匹馬,不可能一場比賽必然獲得結果。那麼求最優方案,就是將以上各分支出現最晚出現的馬去掉,即C2或D1,進行一場比賽。運氣好的話這一輪可以決出前2~4,一共比賽10輪,運氣不好的話還需要加賽一輪。而去掉C2或D1能夠保證只比賽10輪的概率最大。

擴充套件2:

  25匹馬,5個賽道,決出前5。

解答:

=============================================================

  1-30~1.34是幾個估算題,當年google確實考過其中的題目。不過這裡不做解答了。

  關於估算題目的思路和解法,可以參考《程式設計珠璣》《程式設計珠璣(續)》和我寫的相關文章:[珠璣之櫝]估算的應用與Little定律

  另外,“不用再去算一輛校車上可以裝多少個高爾夫球了。因為 Google 已承認,那些用於測試求職者的智力題/腦筋急轉彎(全世界有多少鋼琴調音師?為什麼井蓋是圓的?),就無法預測出求職者是否會成為一位好員工。 “現在信賴更常規方法去面試潛在員工”。相關連結

1.30

  世界上有多少個鋼琴調音師?

1.31

  美國有多少個加油站?

1.32

  曲棍球場上的雪有多重?

1.33

  美國公路一共有多長?

1.34

  平均來看,你翻開一本曼哈頓電話簿時,你需要隨機翻開多少次才能找到一個給定的名字?

相關推薦

演算法設計手冊試題解答 第一演算法設計簡介

目錄 系列簡介:   《演算法設計手冊》(The Algorithm Design Manual)是本比較經典的演算法書了。如果說《演算法導論》偏向於數學,那麼《演算法設計手冊》更偏向於工程應用(至於《計算機程式設計藝術》,目前我是沒時間通讀,只是偶爾當工具書查查,就不提了)。前者的課後題中的面試

第一程序設計和C語言

統一 c程序 集合 out 包含 有一個 機器 文件名 部分 一、什麽是計算機程序? 所謂程序就是一組計算機能識別和執行的指令。計算機的一切操作都是由程序控制的,本質是程序的機器,程序和指令是計算機系統最基本的概念。 二、什麽是計算機語言? 人和計算機交流信息要

第一程序設計入門

\n ont 浮點型 表達 math 結果 模板 題目 大表 隨學筆記: 小計: <1>: ACM比賽中不能使用#include<conio.h> 中包含的getch(),clrscr()等函數,不能使用getche(),gotoxy()等函數。

演算法導論 第一演算法在計算中的作用 筆記

文章目錄 演算法 NP完全問題 插入排序和合並排序 演算法 演算法(algorithm) 就是定義良好的計算過程,它取一個或一組值作為輸入, 併產生出一個或一組值作為輸出。也就是說,演算法就是一系列的計算步驟,用來將輸入資料轉換成輸

第一Java設計模式-單例模式

一、單例模式-餓漢模式 package com.xm.designpattern.single; /** * 單例模式-餓漢模式 * 原理: 不管是否使用,類載入時就初始化好 * 缺點: 非執行緒安全,只適合單執行緒使用 * @author ouyangjun

資料庫應用第一SQL Server簡介

一. SQL Server 2008的系統資料庫有哪幾種?功能是什麼? SQL Server 2008的系統資料庫由master、model、msdb、tempdb 和隱藏的Resourc

Node.js學習(第一Node.js簡介

過程 朋友 npm 文件讀寫 擴展 業務 ebp 更新 框架 Node.js是什麽? Node.js 誕生於 2009 年,由 Joyent 的員工 Ryan Dahl 開發而成, 目前官網最新版本已經更新到 12.0.0版本,最新穩定的是10.15.3。Node.js

第一10道C/C++經典試題

面試題 1:變數的宣告和定義有什麼區別 為變數分配地址和儲存空間的稱為定義,不分配地址的稱為宣告。 一個變數可以在多個地方宣告,但是隻在一個地方定義。 加入 extern 修飾的是變數的宣告,說明此變數將在檔案以外或在檔案後面部分定義。 說明:很多時候一個變數,只是宣告不分配記憶體空間,直到具體使用時

演算法設計技巧與分析筆記 第一

1.搜尋:設A【1……n】為一個n個元素的陣列,判定給定元素x是否在A中 線性搜尋:直接掃描A中所有專案,將每個專案與x做比較。 二分搜尋: A【low……high】為有序非空陣列(假定為升序),A【mid】為中間元素 假定x>A【mid】,則丟棄A【low…mid】

演算法與資料機構學習_第一.棧和佇列_1.設計一個有返回棧中最小元素功能的棧

設計一個有getMin功能的棧(返回棧中的最小元素) 演算法要求:實現一個特殊的棧,在實現棧的基本功能的基礎上,新增能夠實現返回棧中最小元素的棧,要求演算法的時間複雜讀為O(1),即在常數時間內實現。 思路:在一個棧中在時間複雜讀度為O(1)返回棧中最小元素

第一 java程序設計概述

.cn 發布 線程 字節 做了 ges 運行時 依賴 images Java 的設計者已經編寫了頗有影響力的“ 白皮書”, 用來解釋設計的初衷以及完成的情況,並且發布了一個簡短的摘要, 這個摘要用下面11 個關鍵術語進行組織:1 ) 簡單性2 ) 面向對象3 ) 分布式4

《數據庫設計入門經典》讀書筆記——第一數據庫建模的過去與現在

port 混合 如果 執行 很好 創建表 規則 什麽 增長 《數據庫設計入門經典》,現在學習的是這本書,雖然以前就看過類似的書,可能由於之前經驗不足,書中說的某些東西只消化了一部分,現在重溫一邊好懂多了。所以說讀第一遍讀不懂不要緊,過個一年半載的再來讀,還是會讀不懂的,哈哈

大話設計模式--第一 簡單工廠設計模式

args bsp color apt col 參數 strong 簡單工廠設計模式 font 簡單工廠設計模式 案例: 寫一個計算器, 實現加減乘除. 第一步: 寫一份簡單的代碼 package com.chapter1; public class Caculator1

java試題之----jdbc中使用的設計模式(橋接模式)

connect @override 操作 tro orb his order ng- return 1.JDBC(JavaDatabase Connectivity) JDBC是以統一方式訪問數據庫的API. 它提供了獨立於平臺的數據庫訪問,也就是說,有了JDB

Java試題02_15(第一階段基礎)

02.15_Java語言基礎(面試題之變數相加和常量相加的區別)(掌握) 面試題:看下面的程式是否有問題,如果有問題,請指出並說明理由。 * byte b1 = 3; * byte b2 = 4; * byte b3 = b1 + b2; //有問題 * 從兩方面去回答這個題 *

第一Python資料結構和演算法

第一章:Python資料結構和演算法 Python 提供了大量的內建資料結構,包括列表,集合以及字典。大多數情況下使用這些資料結構是很簡單的。 但是,我們也會經常碰到到諸如查詢,排序和過濾等等這些普遍存在的問題。 因此,這一章的目的就是討論這些比較常見的問題和演算法。 另外,我們也會

設計資料密集型應用》——第一原文+翻譯(上)

Reliable,Scalable,and Maintainable Applications(可靠,可伸縮,可維護的應用) Many applications today are data-intensive, as opposed to compute-intensive. Raw CPU

C++程式語言設計-第一緒論

第一章 緒論 計算機系統簡介 計算機語言和程式設計方法的發展 計算機語言的發展歷程 程式設計語言的發展歷程 面向物件的基本概念 程式的開發過程 資訊的表示和儲存 計算機中的資訊與儲存單位 計

75道試題解答

hashcode相等兩個類一定相等嗎?equals呢?相反呢? 介紹一下集合框架? hashmap hastable 底層實現什麼區別?hashtable和concurrenthashtable呢? hashmap和treemap什麼區別?低層資料結構是什麼? 執行緒池用過嗎都有什麼

試題總結-資料結構與演算法

排序 氣泡排序-比較交換 快速排序-劃分-比較交換-遞迴 選擇排序-選擇-比較交換 查詢 二分查詢 二叉樹 二叉樹的前序、中序、後序遍歷(遞迴實現) 二叉樹的前序、中序、後序遍歷(非遞迴實現) 判斷一棵樹是否為二叉平衡樹 連結串列 連結串列的翻轉 判斷