double類型的比較不能用==ios
計算機表示的小數(包括float & double)都有偏差,若是兩個小數的差的絕對值很小,小雨0.0000001(中間爲6個0)就能夠認爲他們相等git
完整的代碼:功能測試,邊界測試,負面測試面試
1.不一樣的返回值表示不一樣的錯誤算法
面試題11:數值的整數次方:編程
注意各類輸入,base爲0.0,exponent爲負數時是錯誤輸入數組
exponent爲負數,取絕對值,求冪後倒數,網絡
注意浮點數的比較相等用差值和0.0000001ide
求冪用遞歸,a的n次方分奇偶考慮,偶數的時候就用a的n/2的平方函數
除以2的時候用位移,體現細節..性能
面試題12:打印1到最大n位數
n位數可能會超出long long的範圍,long long 爲8字節64位
-->用字符串模擬數字的加法
1 2 /*n位數可能會超出long long的範圍,long long 爲8字節64位 3 -->用字符串模擬數字的加法*/ 4 #include <memory> 5 #include <string.h> 6 //C++ 中要使用strlen通常包含<CString> 7 8 //一直進位直到第一次結束纔是一個+1過程的結束 9 bool Increment(char* number) 10 { 11 int length = strlen(number); 12 int takeOver = 0; 13 bool isOverStack = false; 14 15 for(int i = length - 1; i >= 0; ++i) 16 { 17 int sum = number[i] - '0' + takeOver; 18 if(i == length - 1) 19 ++sum; 20 21 if(sum >= 10) 22 { 23 if(i == 0) 24 isOverStack = true; 25 else 26 { 27 sum -= 10; 28 number[i] = sum + '0'; 29 takeOver = 1; 30 } 31 } 32 else 33 { 34 number[i] = sum + '0'; 35 break; 36 } 37 38 } 39 return isOverStack; 40 } 41 42 //不要打印出最前面的0 43 void PrintNumber(char* number) 44 { 45 int length = strlen(number); 46 bool posFlag = false; 47 48 for(int i = 0; i < length; ++i) 49 { 50 if(!posFlag && number[i] != '0') 51 posFlag = true; 52 if(posFlag) 53 printf("%c", number[i]); 54 } 55 return; 56 } 57 58 void PrintToMaxOfNDigits(int n) 59 { 60 if(n <= 0) 61 return; 62 char *number = new char[n + 1]; 63 memset(number, '0', n); 64 number[n] = '\0'; 65 66 while(!Increment(number)) 67 PrintNumber(number); 68 delete []number; 69 } 70 71 //把問題轉換爲數字排列的方法,運用遞歸是程序更加簡單 72 //全排列方法 73 74 void PrintToMaxOfNDigits_1(int n) 75 { 76 char* number = new char[n + 1]; 77 memset(number, '0', n); 78 number[n] = '\0'; 79 for(int i = 0; i < 10; ++i) 80 { 81 number[0] = '0' + i; 82 PrintRecursively(number, n, 0) 83 } 84 delete []number; 85 } 86 87 void PrintRecursively(char* number, int length, int index) 88 { 89 if(index == length - 1) 90 { 91 PrintNumber(number); 92 return; 93 } 94 95 for(int i = 0; i < 10; ++i) 96 { 97 number[index + 1] = '0' + i; 98 PrintRecursively(number, length, index + 1); 99 } 100 }
面試題13:在O(1)時間內刪除鏈表節點
把下一個節點的內容複製到須要刪除的節點上覆蓋原有的內容,再把下一個節點刪除便可。
若刪除的節點位於列表尾部則順序遍歷獲得該節點的前序節點,並完成刪除操做。
若是鏈表中只有一個節點,則在刪除後還須要把鏈表的頭結點設置爲NULL。
//題目已經假設刪除的節點必定在鏈表中
//節點delete以後,要將自己設爲NULL,position自己就是一個節點指針,是有指向的
1 #include <iostream> 2 using namespace std; 3 4 typedef struct ListNode* head; 5 typedef struct ListNode* position; 6 struct ListNode 7 { 8 int m_nValue; 9 ListNode* m_pNext; 10 }; 11 12 void DeleteNode(head pListHead, position pToBeDeleted) 13 { 14 if(!pListHead || !pToBeDeleted) 15 return; 16 position pTemp; 17 if(pToBeDeleted->m_pNext == NULL) 18 { 19 pTemp = pListHead; 20 while(pTemp->m_pNext != pToBeDeleted) 21 pTemp = pTemp->m_pNext; 22 pTemp->m_pNext = pToBeDeleted->m_pNext; 23 delete pToBeDeleted; 24 //注意下面一行 25 pToBeDeleted = NULL; 26 return; 27 } 28 pTemp = pToBeDeleted->m_pNext; 29 pToBeDeleted->m_nValue = pTemp->m_nValue; 30 pToBeDeleted->m_pNext = pTemp->m_pNext; 31 delete pTemp; 32 //注意下面一句 33 pTemp = NULL; 34 return; 35 }
面試題14:調整數組順序使奇數位位於偶數以前
題目:輸入一個整數數組,調整數組中數字的順序,使得全部奇數位於數組的前半部分,全部偶數位於數組的後半部分。要求時間複雜度爲O(n)。
用和快排比較類似的算法,維護兩個指針
一般狀況下位運算符比%要快一些,因此判斷奇偶能夠用data & 0X1 比較好
1 #include<iostream> 2 using namespace std; 3 void ReorderOddEven(int *number, unsigned int length) 4 { 5 //函數初始時基本的判斷參數輸入有沒有錯誤的不要忘了!!! 6 if(number == NULL || length == 0) 7 return; 8 9 int *p1 = number, *p2 = number + (length -1); 10 while(p1 < p2) 11 { 12 while(p1 < p2 && (*p1 & 0x1) == 1) 13 ++p1; 14 while(p1 < p2 && (*p2 & 0x1) == 0) 15 --p2; 16 if(p1 < p2) 17 { 18 int temp = *p1; 19 *p1 = *p2; 20 *p2 = temp; 21 } 22 23 } 24 return; 25 }
能夠利用函數指針把這個算法擴展
1 void Reorder(int* number, unsigned int length, bool (*func)(int)) 2 { 3 //函數初始時基本的判斷參數輸入有沒有錯誤的不要忘了!!! 4 if(number == NULL || length == 0) 5 return; 6 7 int *p1 = number, *p2 = number + (length -1); 8 while(p1 < p2) 9 { 10 while(p1 < p2 && !func(*p1)) 11 ++p1; 12 while(p1 < p2 && func(*p2)) 13 --p2; 14 if(p1 < p2) 15 { 16 int temp = *p1; 17 *p1 = *p2; 18 *p2 = temp; 19 } 20 21 } 22 return; 23 } 24 25 bool isEven(int n) 26 { 27 return (n & 0x1) == 0; 28 } 29 void ReorderOddEven2(int* number, unsigned int length) 30 { 31 Reorder(number, length, isEven); 32 }
代碼的魯棒性:
容錯性是代碼魯棒性的一個重要體現
1.輸入錯誤的用戶名
2.試圖打開不存在的文件
3.網絡不能鏈接
4......
-->預防性編程
題目:輸入一個單向鏈表,輸出該鏈表中倒數第k個結點。鏈表的倒數第0個結點爲鏈表的尾指針。鏈表結點定義以下:
記尾節點是倒數第一個節點,
用unsigned int 來表示length比較合理,此時0 - 1獲得一個巨大的數
1 #include <iostream> 2 using namespace std; 3 typedef struct ListNode* phead; 4 typedef struct ListNode* position; 5 struct ListNode 6 { 7 int m_nValue; 8 ListNode* m_pNext; 9 }; 10 11 position FindKthNode(phead listHead, unsigned int k) 12 { 13 if(listHead == NULL || k == 0) 14 return NULL; 15 position temp1 = listHead, temp2 = listHead; 16 17 for(unsigned int i = 0; i < k - 1; ++i) 18 { 19 if(temp1->m_pNext != NULL) 20 temp1 = temp1->m_pNext; 21 else 22 return NULL; 23 } 24 while(temp1->m_pNext != NULL) 25 { 26 temp1 = temp1->m_pNext; 27 temp2 = temp2->m_pNext; 28 } 29 return temp2; 30 }
要注意K=0,listHead指向空,list長度小於K
1.求鏈表的中間節點:
若鏈表總數爲奇數,返回中間節點,不然返回中間節點2箇中的任意一個
定義兩個指針都從鏈表頭結點出發,一個一次走一步,一個一次走兩步,走的快的到末尾時,走的啊,慢的恰好在鏈表的中間
2.判斷一個鏈表是否構成環形;
同上,定義兩個指針都從鏈表頭結點出發,一個一次走一步,一個一次走兩步,走的快若是能追上走的慢的那麼就是環形鏈表,若是到鏈表末尾尚未追上走的慢的則不是環形鏈表
當咱們使用一個指針遍歷鏈表不能解決問題的時候,能夠嘗試用兩個指針來遍歷,兩個指針遍歷的速度或者前後不一樣。
面試題16:反轉鏈表
輸入的鏈表指針爲NULL或者整個鏈表只有一個節點
反轉後頭結點是否是鏈表的原先的尾節點
1 #include<iostream> 2 using namespace std; 3 typedef struct ListNode* pHead; 4 typedef struct ListNode* position; 5 6 struct ListNode 7 { 8 int m_nValue; 9 ListNode* m_pNext; 10 }; 11 12 pHead ReverseList(pHead listHead) 13 { 14 pHead pReversedHead = NULL; 15 position pNode = listHead; 16 position pPrev = NULL; 17 18 //這種形式中頭結點不是啞元,反轉後頭結點爲的下一個爲NULL 19 //因此初始的pPrev設爲NULL 20 21 while(pNode != NULL) 22 { 23 position pNext = pNode->m_pNext; 24 if(pNext == NULL) 25 pReversedHead = pNode; 26 27 pNode->m_pNext = pPrev; 28 pPrev = pNode; 29 pNode = pNext; 30 } 31 return pReversedHead; 32 }
遞歸實現注意頭結點的6,7,8行是最後實現的
1 Node * resverselinkRecursion(Node *head) 2 { 3 if(head==NULL || head->next==NULL) 4 return head; 5 Node *n = resverselinkRecursion(head->next); 6 head->next->next = head; 7 head->next=NULL; 8 return n; 9 }
面試題18:樹的子結構
判斷二叉樹B是否是A的子結構
1 #include<iostream> 2 using namespace std; 3 4 typedef struct BinaryTreeNode* position; 5 typedef struct BinaryTreeNode* root; 6 struct BinaryTreeNode 7 { 8 int m_nValue; 9 position m_pLeft; 10 position m_pRight; 11 }; 12 13 bool HasSubTree(root pRoot1, root pRoot2) 14 { 15 bool result = false; 16 if(pRoot1 != NULL && pRoot2 != NULL) 17 { 18 if(pRoot1->m_nValue == pRoot2->m_nValue) 19 result = DoesTree1HaveTree2(pRoot1, pRoot2); 20 if(!result) 21 result = HasSubTree(pRoot1->m_pLeft, pRoot2); 22 if(!result) 23 result = HasSubTree(pRoot1->m_pRight, pRoot2); 24 } 25 return result; 26 } 27 28 bool DoesTree1HaveTree2(root pRoot1, root pRoot2) 29 { 30 if(pRoot2 == NULL) 31 return true; 32 if(pRoot1 == NULL) 33 return false; 34 if(pRoot1->m_nValue != pRoot2->m_nValue) 35 return false; 36 return DoesTree1HaveTree2(pRoot1->m_pLeft, pRoot2->m_pLeft) && 37 DoesTree1HaveTree2(pRoot1->m_pRight, pRoot2->m_pRight); 38 }
樹的操做都伴隨着大量的指針,尤爲要考慮清楚是否爲NULL的狀況。