要求:不僅僅能實(shí)現(xiàn)相應(yīng)的功能,還需要保證代碼的魯棒性,并且能夠分析代碼的空間復(fù)雜度和時(shí)間復(fù)雜度。
二維數(shù)組中的查找
題目要求: 在一個(gè)二維數(shù)組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序,請(qǐng)按照遞增的順序排序。請(qǐng)完成一個(gè)函數(shù),輸入這樣一個(gè)二維數(shù)組和一個(gè)整數(shù),判斷數(shù)組中是否含有該整數(shù)。
解題思路:首先選取數(shù)組中右上角的數(shù)字,如果該數(shù)字等于要查找的數(shù)字,查找過程結(jié)束;如果數(shù)字中的數(shù)字大于要查找的數(shù)字,剔除這個(gè)數(shù)字所在的列,如果該數(shù)字小于要查找的數(shù)字,剔除該數(shù)字所在的行。也就是說如果要查找的數(shù)字不再數(shù)組的右上角,則每次都在數(shù)組查找范圍中刪除一行或者一列,這樣每一步都可以縮小查找的范圍,知道找到要查找的數(shù)字,或者查找范圍為空。
注意:邊界值。查找的數(shù)字恰好是最大值或者最小值。查找的數(shù)字大于數(shù)組中的最大值,或者小于數(shù)組中的最小值,在最大值和最小值之間,但是數(shù)組中沒有這個(gè)數(shù)。輸入空指針。
構(gòu)建乘積數(shù)組
題目要求:給定一個(gè)數(shù)組A[0,1,…,n-1],請(qǐng)構(gòu)建一個(gè)數(shù)組B[0,1,…,n-1], 其中B中的元素
B[i] = A[0]* A[1]…A[i-1]…A[i+1]…A[n-1]。要求不能使用乘法。
解題思路:將B[i]的 乘數(shù)分為兩部分,前者為A[0]*A[1]*A[2]*…*A[i-1]
,后者為A[i+1]*A[i+2]*…*A[n]
。因此數(shù)組B可以用一個(gè)矩陣來創(chuàng)建,如圖所示,B[i]為矩陣中第i行所有元素的乘積。
定義Ci = A[0]*A[1]*A[2]*…*A[i-1]
,D[i] = A[i+1]*A[i+2]*…*A[n]
。C[i]可以用自上而下的順序打印出來,即C[i] = C[i-1] * A[i-1]。 D[i]
可以用自下而上的順序計(jì)算出來。
順時(shí)針打印數(shù)組: 劍指offer 面試題20
題目要求: 輸入一個(gè)矩陣,按照從外向里以順時(shí)針的順序依次打印出每一個(gè)數(shù)字。
解題思路:以右上和左下兩個(gè)元素標(biāo)記整個(gè)矩陣一圈,實(shí)現(xiàn)從左向右,從上向下,從右向左,從下向上,依次打印一圈。再將右上元素朝左下移動(dòng),將左下元素向右上移動(dòng),標(biāo)記內(nèi)圈,依次打印即可。這樣逐層向內(nèi)打印即可。
注意:最后最后一圈可能退化成只有一行或者一列,或者只有一個(gè)數(shù)字。
替換空格: 劍指offer 面試題4
題目要求:請(qǐng)實(shí)現(xiàn)一個(gè)函數(shù),把字符串中的每一個(gè)空格替換成
”%20”
, 例如輸入“We are happy”
,則輸出“We%20are%20happy”
。
解題思路:我們先遍歷一遍字符串,統(tǒng)計(jì)出字符串中空格的總數(shù),并可以由此計(jì)算出替換之后的字符串的總長(zhǎng)度。每替換一個(gè)空格,長(zhǎng)度增加2。因此替換以后的字符串的長(zhǎng)度等于原來的長(zhǎng)度加上2乘以空格數(shù)目。我們可以考慮從字符串的尾部開始替換和賦值,根據(jù)前面空格的個(gè)數(shù),可以計(jì)算出字符需要移動(dòng)到的位置。如此,我們就可以對(duì)每一個(gè)字符移動(dòng)一次。從而使算法的復(fù)雜度降為O(n)。
注意:合并連個(gè)數(shù)組,包括字符串時(shí),如果從前往后復(fù)制每個(gè)數(shù)字需要移動(dòng)數(shù)字多次,那么我們可以考慮從前向后復(fù)制,這樣可以減少移動(dòng)的次數(shù),從而提高效率。
旋轉(zhuǎn)數(shù)組中的最小數(shù)字:
題目要求:把一個(gè)數(shù)組最開始的若干個(gè)元素搬到數(shù)組的末尾,我們稱之為數(shù)組的旋轉(zhuǎn)。輸入一個(gè)遞增排序的數(shù)組的一個(gè)旋轉(zhuǎn),輸出旋轉(zhuǎn)數(shù)組的最小元素。例如數(shù)組
{3,4,5,1,2}
為{1,2,3,4,5}
的一個(gè)旋轉(zhuǎn),該數(shù)組的最小值為1。
解題思路:和二分查找一樣,我們left和right分別指向數(shù)組的第一個(gè)元素和最后一個(gè)元素。如果中間元素大于第一個(gè)元素,那么最小值應(yīng)該在后一部分,我們left = mid
。如果中間元素小于最后一個(gè)元素,那么最小值應(yīng)該在前一部分,我們right = mid
。以此查找最小元素。
注意:需要注意一種特殊的情況是,原本的排序就是有序的。我們令初始的中間指針mid指向第一個(gè)元素。
另外還有一種情況就是,當(dāng)三個(gè)指針 right
, left
和 mid
均相同時(shí),如下圖所示,我們無法斷定前后那一部分包含最小值,此時(shí)只能用順序查找算法。
數(shù)組中重復(fù)的數(shù)字
題目要求: 在一個(gè)長(zhǎng)度為n 的數(shù)組里的所有數(shù)字都在
0
和n - 1
的范圍內(nèi)。數(shù)組中的某些數(shù)字是重復(fù)的,但是不知道有幾個(gè)數(shù)字是重復(fù)了,也不知道每個(gè)數(shù)字重復(fù)了幾次。請(qǐng)找出數(shù)組中任意一個(gè)重復(fù)的數(shù)字。例如輸入長(zhǎng)度為7 的數(shù)組{2,3,1,0,2,5,3}
, 那么對(duì)應(yīng)的輸出是重復(fù)的數(shù)字2或者3。
解題思路:(根據(jù)數(shù)組的特點(diǎn):數(shù)字都在0到n - 1 的范圍內(nèi),如果這個(gè)數(shù)組總沒有重復(fù)的數(shù)字,那么數(shù)排序后的數(shù)字i將出現(xiàn)在下標(biāo)為i的位置。由于有重復(fù)的數(shù)字,有些位置可能存在多個(gè)數(shù)字,也有可能沒有數(shù)字,依次可用于設(shè)計(jì)算法)從頭到未依次掃描這個(gè)數(shù)組中的每一個(gè)數(shù)字。當(dāng)掃描到下標(biāo)為i 的數(shù)字時(shí), 首先比較這個(gè)數(shù)字是不是等于i。如果是,接著掃描下一個(gè)數(shù)字(用m表示)。如果不是,再拿它和第m個(gè)數(shù)字進(jìn)行比較。如果它和第m個(gè)數(shù)字相等,就找到了一個(gè)重復(fù)數(shù)字,如果它和第m個(gè)數(shù)字不相等,就把第i個(gè)數(shù)字和第m個(gè)數(shù)字交換。把m放到屬于它的位置。接下來重復(fù)這個(gè)比較,交換的過程,知道發(fā)現(xiàn)一個(gè)重復(fù)的數(shù)字。
斐波那契數(shù)列:
傳統(tǒng)遞歸方法實(shí)現(xiàn)斐波那契數(shù)列的缺點(diǎn):
遞歸由于是韓式調(diào)用自身,而函數(shù)調(diào)用時(shí)有時(shí)間和空間的消耗的:每次函數(shù)調(diào)用,都需要在內(nèi)存棧中分配空間以保存參數(shù),返回地址和臨時(shí)變量,而且往棧里壓入數(shù)據(jù)和彈出數(shù)據(jù)是需要時(shí)間的
遞歸有可能有很多的計(jì)算都是重復(fù)的,對(duì)性能帶來很大的影響。遞歸的本質(zhì)是把一個(gè)問題分解成兩個(gè)或者多個(gè)小問題。如果多個(gè)小問題之間存在重疊的額部分,那么久會(huì)存在重復(fù)計(jì)算。
遞歸還分引起一個(gè)問題,調(diào)用棧溢出。
題目要求:寫出一個(gè)數(shù),輸入n, 求斐波那契數(shù)列的第n項(xiàng)。要求時(shí)間復(fù)雜度為O(n)。
解題思路:
int Fibonacci(int n) {
if(n == 1 || n == 2)
return 1;
int firstNum = 1;
int secondNum = 1;
int sumNum = 0;
for(int i = 3; i <= n ;++i){
sumNum = firstNum + secondNum;
firstNum = secondNum;
secondNum = sumNum;
}
return sumNum;
}
二進(jìn)制中1的個(gè)數(shù):
題目要求: 請(qǐng)實(shí)現(xiàn)一個(gè)函數(shù),輸入一個(gè)整數(shù),輸出該數(shù)的二進(jìn)制表示中1的個(gè)數(shù)。
解題思路: 把一個(gè)整數(shù)減去1之后再和原來的整數(shù)做位與運(yùn)算,得到的結(jié)果相當(dāng)于把整數(shù)的二進(jìn)制表示中的最右邊的一個(gè)1 變成0。
int count = 0;
while(n){
n = n & (n-1);
++count;
}