1.二維數組中的查找
/* 題目:在一個二維數組中,沒一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。 請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。 */ #include<stdio.h> #include<string.h> // 從右上角開始比較 bool Find(int *matrix, int rows, int columns, int number) { bool found = false; if (matrix != NULL && rows > 0 && columns > 0) { int row = 0; int column = columns - 1; while (row < rows&&column >= 0) { if (matrix[row*columns + column] == number) { found = true; break; } else if (matrix[row*columns + column ]> number) column--; else row++; } } return found; } // 從左下角開始比較 bool Find_2(int *arr, int rows, int columns, int number) { bool find = false; if (arr != NULL&&rows > 0 && columns > 0) { int row = rows - 1; int column = 0; while (row >=0 && column <= columns - 1) { if (arr[row*columns + column] == number) { find = true; break; } else if (arr[row*columns+column] < number) column++; else row--; } } return find; } int main() { int arr [4][4]= { {1, 2, 8, 9}, {2,4 ,9 ,12}, {4, 7, 10, 13}, {6, 8, 11, 15} }; Find_2(*arr, 4, 4, 7); return 0; }
2.字符串
C/C++中的每一個字符串都以’\0’結尾。爲了節省空間,C/C++常常把常量字符串放到一個單獨的內存區域。當幾個指針賦值給相同的常量字符串時,它們實際會指向相同的地址空間。例如:node
#include<stdio.h> int main() { char str1[] = "Hello World"; char str2[] = "Hello world"; char *str3 = "Hello world"; char *str4 = "Hello world"; if (str1 == str2) printf("str1 and str2 are same. \n"); else printf("str1 and str2 are not same.\n"); if (str3 == str4) printf("str3 and str4 are same.\n"); else printf("str3 and str4 are not same.\n"); return 0; }
輸出以下:ios
str1 and str2 are not same. str3 and str4 are same.
題目:請實現一個函數,把字符串中的每一個空格替換成」%20」。例如輸入「We are happy.」,則輸出爲」We%20are%20%20happy.」。實現代碼以下:數組
#include<stdio.h> // lenght 爲字符數組string的總容量 void ReplaceSpace(char string[], int length) { if (string == NULL&&length <= 0) return; // originalLenght爲字符串string的實際長度 int originalLenght = 0; int numOfBlank = 0; int i = 0; while (string[i] != '\0') { originalLenght++; if (string[i] == ' ') numOfBlank++; i++; } int newLenght = originalLenght + numOfBlank * 2; if (newLenght <= originalLenght) return; int indexOfOriginal = originalLenght; int indexOfNew = newLenght; while (indexOfOriginal >= 0 && indexOfNew > indexOfOriginal) { if (string[indexOfOriginal] == ' ') { string[indexOfNew--] = '0'; string[indexOfNew--] = '2'; string[indexOfNew--] = '%'; } else string[indexOfNew--] = string[indexOfOriginal]; indexOfOriginal--; } } int main() { char string[] = "We are happy."; int lenght = sizeof(string) / sizeof(char); ReplaceSpace(string, lenght); int j = 0; while (string[j] != '\0') { printf("%c", string[j]); j++; } printf("\n"); return 0; }
輸出結果:app
We%20are%20happy.
相關題目:有兩個排序的數組A1和A2,內存在A1末尾有足夠的空餘空間容納A2。請實現一個函數,把A2中的全部數字插入到A1中而且全部的數字是排序的。實現代碼以下:函數
#include<stdio.h> // len1爲數組arr1的有效數字的長度 void unionArray(int arr1[], int len1, int arr2[], int len2) { // arr1_all是啊讓人整個數組的空間長度 int arr1_all = len1 + len2; if (len2 ==0) return; int index_1 = len1-1; int index_2 = arr1_all-1; int index_3 = len2-1; while (index_2 > index_1) { if (arr1[index_1] > arr2[index_3]) { arr1[index_2--] = arr1[index_1]; index_1--; } else { arr1[index_2--] = arr2[index_3]; index_3--; } } } int main() { int arr1[9] = { 1,2,3,4 }; int arr2[5] = { 5,6,7,8,9 }; unionArray(arr1, 4, arr2, 5); int len = sizeof(arr1) / sizeof(int); int i = 0; while (i < len) { printf("%d", arr1[i]); ++i; } printf("\n"); return 0; }
輸出結果:測試
123456789
3.鏈表
// 單向鏈表的節點定義 struct ListNode { int m_nValue; ListNode *m_pNext; }; // 往鏈表的末尾添加一個節點 void AddToTail(ListNode** pHead, int value) { ListNode* pNew = new ListNode(); // 定義一個新節點指針併爲它分配內存 pNew->m_nValue = value; pNew->m_pNext = NULL; // 若是鏈表爲空,則新添加的節點爲頭節點,使頭指針pHead指向該節點 if (pHead == NULL) { pHead = &pNew; } else { ListNode* pNode = *pHead; while (pNode->m_pNext != NULL) pNode = pNode->m_pNext; pNode->m_pNext = pNew; } } // 刪除節點函數 void RemoveNode(ListNode** pHead, int value) { if (pHead == NULL || *pHead == NULL) { return; } ListNode *pToBeDeleted = NULL; if ((*pHead)->m_nValue == value) { pToBeDeleted = *pHead; *pHead = (*pHead)->m_pNext; } else { ListNode* pNode = *pHead; while (pNode->m_pNext != NULL&&pNode->m_pNext->m_nValue!=value) pNode = pNode->m_pNext; if (pNode->m_pNext != NULL&&pNode->m_pNext->m_nValue == value) { pToBeDeleted = pNode->m_pNext; pNode->m_pNext = pNode->m_pNext->m_pNext; } if (pToBeDeleted != NULL) { delete pToBeDeleted; pToBeDeleted = NULL; } } }
題目:輸入一個鏈表的頭節點,從尾到頭打印出每一個節點的值。spa
// 題目:輸入一個鏈表的頭節點,從尾到頭打印出每一個節點的值。 // 方法一:從頭至尾遍歷鏈表,把節點依次放進一個棧中,當遍歷完整個鏈表後,再從棧頂開始輸出節點的值 void PrintListReversingly_Interatively(ListNode *pHead) { std::stack<ListNode*> nodes; ListNode *pNode = pHead; while (pNode != NULL) { nodes.push(pNode); pNode = pNode->m_pNext; } while (!nodes.empty()) { pNode = nodes.top(); printf("%d\n", pNode->m_nValue); nodes.pop(); } } // 方法二:利用遞歸。每次訪問一個節點時,先輸出它後面的節點 void PrintListReversingly_Recursively(ListNode* pHead) { if (pHead != NULL) { if (pHead->m_pNext != NULL) { PrintListReversingly_Recursively(pHead->m_pNext); } printf("%d\n", pHead->m_nValue); } } void haha(ListNode** pHead) { while ((*pHead)->m_pNext != NULL) { printf("%d\n", (*pHead)->m_nValue); (*pHead) = (*pHead)->m_pNext; } }
4.樹
題目:輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果都不含重複的數字。指針
#include<stdio.h> #include<iostream> // 二叉樹結點定義 struct BinaryTreeNode { int m_nvalue; BinaryTreeNode* m_pLeft; BinaryTreeNode* m_pRight; }; // 函數聲明 BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder); // 用遞歸的方法構建左右子樹和根節點 BinaryTreeNode* Construct(int *preorder, int *inorder, int length) { if (preorder == NULL || inorder == NULL || length <= 0) { return NULL; } return ConstructCore(preorder,preorder+length-1,inorder,inorder+length-1); } BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder) { // 前序遍歷第一個數字即爲根節點的值 int rootValue = startPreorder[0]; BinaryTreeNode* root = new BinaryTreeNode(); root->m_nvalue = rootValue; root->m_pLeft = NULL; root->m_pRight = NULL; if (startPreorder == endPreorder) { if (startInorder == endInorder&&*startPreorder == *startPreorder) return root; else throw std::exception("Invalid input"); } // 在中序遍歷中找到根節點的值 int* rootInorder = startPreorder; while (*rootInorder != rootValue && rootInorder <= endInorder) { ++rootInorder; } if (*rootInorder != rootValue&&rootInorder == endInorder) throw std::exception("Invalid input"); int leftLength = rootInorder - startInorder; int* leftPreorderEnd = startInorder + leftLength; if (leftLength > 0) { // 構建左子樹 root->m_pLeft = ConstructCore(startPreorder + 1, endPreorder, startInorder, leftPreorderEnd - 1); } if (leftLength < endInorder - startInorder) { // 構建右子樹 root->m_pRight = ConstructCore(leftPreorderEnd+1,endPreorder, rootInorder+1,endInorder); } }
5.棧和隊列
題目:用兩個棧實現一個隊列。隊列的聲明以下,請實現它的兩個函數appendTail和deleteHead,分別完成在隊列尾部插入節點和在隊列頭部刪除節點的功能。code
// 隊列的聲明 template <typename T> class CQueue { public: CQueue(void); ~CQueue(void); // 在隊列末尾添加一個結點 void appendTail(const T& node); // 刪除隊列的頭結點 T deleteHead(); private: stack<T> stack1; stack<T> stack2; }; template <typename T> CQueue<T>::CQueue(void) { } template <typename T> CQueue<T>::~CQueue(void) { }
接下來定義兩個函數:blog
// 往第一個棧中插入元素 template<typename T> void CQueue<T>::appendTail(const T& element) { stack1.push(element); } // 刪除最早插入的元素 template<typename T> T CQueue<T>::deleteHead() { // 若是第二個棧爲空,把棧一的元素依次彈出插入棧二 if (stack2.size() <= 0) { while (stack1.size()>0) { T& data = stack1.top(); stack1.pop(); stack2.push(data); } } if (stack2.size() == 0) throw new exception("queue is empty"); // 依次彈出並返回棧二棧頂元素 T head = stack2.top(); stack2.pop(); return head; }
6.查找和排序
題目:把一個數組最開始的若干個元素搬到數組的末尾,咱們稱之爲數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如數組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲1。
// 利用二分查找法 #include<stdio.h> #include<exception> int MinInOrder(int* numbers, int index1, int index2); int Min(int* numbers, int length) { if (numbers == NULL || length <= 0) throw new std::exception("Invalid parameters"); int index1 = 0; int index2 = length - 1; int indexMid = index1; while (numbers[index1] >= numbers[index2]) { // 若是index1和index2指向相鄰的兩個數, // 則index1指向第一個遞增子數組的最後一個數字, // index2指向第二個子數組的第一個數字,也就是數組中的最小數字 if (index2 - index1 == 1) { indexMid = index2; break; } // 若是下標爲index一、index2和indexMid指向的三個數字相等, // 則只能順序查找 indexMid = (index1 + index2) / 2; if (numbers[index1] == numbers[index2] && numbers[indexMid] == numbers[index1]) return MinInOrder(numbers, index1, index2); // 縮小查找範圍 if (numbers[indexMid] >= numbers[index1]) index1 = indexMid; else if (numbers[indexMid] <= numbers[index2]) index2 = indexMid; } return numbers[indexMid]; } int MinInOrder(int* numbers, int index1, int index2) { int result = numbers[index1]; for (int i = index1 + 1; i <= index2; ++i) { if (result > numbers[i]) result = numbers[i]; } return result; } // ====================測試代碼==================== void Test(int* numbers, int length, int expected) { int result = 0; try { result = Min(numbers, length); for (int i = 0; i < length; ++i) printf("%d ", numbers[i]); if (result == expected) printf("\tpassed\n"); else printf("\tfailed\n"); } catch (...) { if (numbers == NULL) printf("Test passed.\n"); else printf("Test failed.\n"); } } int main() { // 典型輸入,單調升序的數組的一個旋轉 int array1[] = { 3, 4, 5, 1, 2 }; Test(array1, sizeof(array1) / sizeof(int), 1); // 有重複數字,而且重複的數字恰好的最小的數字 int array2[] = { 3, 4, 5, 1, 1, 2 }; Test(array2, sizeof(array2) / sizeof(int), 1); // 有重複數字,但重複的數字不是第一個數字和最後一個數字 int array3[] = { 3, 4, 5, 1, 2, 2 }; Test(array3, sizeof(array3) / sizeof(int), 1); // 有重複的數字,而且重複的數字恰好是第一個數字和最後一個數字 int array4[] = { 1, 0, 1, 1, 1 }; Test(array4, sizeof(array4) / sizeof(int), 0); // 單調升序數組,旋轉0個元素,也就是單調升序數組自己 int array5[] = { 1, 2, 3, 4, 5 }; Test(array5, sizeof(array5) / sizeof(int), 1); // 數組中只有一個數字 int array6[] = { 2 }; Test(array6, sizeof(array6) / sizeof(int), 2); // 輸入NULL Test(NULL, 0, 0); return 0; }
7.遞歸和循環
遞歸雖然有簡潔的優勢,可是缺點也是顯著的。因爲遞歸式函數調用自身,而函數的調用是由空間和時間消耗的,因此遞歸的效率不如循環。
題目一:寫一個函數,輸入n,求斐波那契(Fibonacci)數列的第n項。斐波那契數列定義以下:
F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2)(n>=2)
解答代碼:
#include<stdio.h> #include <cassert> // ====================方法1:遞歸==================== // 時間複雜度以n的指數方式遞增 long long Fibonacci_Solution1(unsigned int n) { if (n <= 0) return 0; if (n == 1) return 1; return Fibonacci_Solution1(n - 1) + Fibonacci_Solution1(n - 2); } // ====================方法2:循環==================== // 時間複雜度爲O(n) long long Fibonacci_Solution2(unsigned n) { int result[2] = { 0, 1 }; if (n < 2) return result[n]; long long fibNMinusOne = 1; long long fibNMinusTwo = 0; long long fibN = 0; for (unsigned int i = 2; i <= n; ++i) { fibN = fibNMinusOne + fibNMinusTwo; fibNMinusTwo = fibNMinusOne; fibNMinusOne = fibN; } return fibN; } // ====================方法3:基於矩陣乘法==================== // 時間複雜度爲O(logn) struct Matrix2By2 { Matrix2By2 ( long long m00 = 0, long long m01 = 0, long long m10 = 0, long long m11 = 0 ) :m_00(m00), m_01(m01), m_10(m10), m_11(m11) { } long long m_00; long long m_01; long long m_10; long long m_11; }; Matrix2By2 MatrixMultiply ( const Matrix2By2& matrix1, const Matrix2By2& matrix2 ) { return Matrix2By2( matrix1.m_00 * matrix2.m_00 + matrix1.m_01 * matrix2.m_10, matrix1.m_00 * matrix2.m_01 + matrix1.m_01 * matrix2.m_11, matrix1.m_10 * matrix2.m_00 + matrix1.m_11 * matrix2.m_10, matrix1.m_10 * matrix2.m_01 + matrix1.m_11 * matrix2.m_11); } Matrix2By2 MatrixPower(unsigned int n) { assert(n > 0); Matrix2By2 matrix; if (n == 1) { matrix = Matrix2By2(1, 1, 1, 0); } else if (n % 2 == 0) { matrix = MatrixPower(n / 2); matrix = MatrixMultiply(matrix, matrix); } else if (n % 2 == 1) { matrix = MatrixPower((n - 1) / 2); matrix = MatrixMultiply(matrix, matrix); matrix = MatrixMultiply(matrix, Matrix2By2(1, 1, 1, 0)); } return matrix; } long long Fibonacci_Solution3(unsigned int n) { int result[2] = { 0, 1 }; if (n < 2) return result[n]; Matrix2By2 PowerNMinus2 = MatrixPower(n - 1); return PowerNMinus2.m_00; } // ====================測試代碼==================== void Test(int n, int expected) { if (Fibonacci_Solution1(n) == expected) printf("Test for %d in solution1 passed.\n", n); else printf("Test for %d in solution1 failed.\n", n); if (Fibonacci_Solution2(n) == expected) printf("Test for %d in solution2 passed.\n", n); else printf("Test for %d in solution2 failed.\n", n); if (Fibonacci_Solution3(n) == expected) printf("Test for %d in solution3 passed.\n", n); else printf("Test for %d in solution3 failed.\n", n); } int main() { Test(0, 0); Test(1, 1); Test(2, 1); Test(3, 2); Test(4, 3); Test(5, 5); Test(6, 8); Test(7, 13); Test(8, 21); Test(9, 34); Test(10, 55); Test(40, 102334155); return 0; }
題目二:一隻青蛙一次能夠跳上1級臺階,也能夠跳上2級.求該青蛙跳上一個n級臺階有多少種跳法。
其實這道題的解答就是求上面的斐波那契數列。
8.位計算
位運算是把數字用二進制表示以後,對每一位上0或者1的運算。
題目:請實現一個函數,輸入一個整數,輸出該數二進制表示中1的個數。例如把9表示成二進制是1001,有2位是1.所以若是輸入爲9,輸出爲2.
/*考慮到有負數的狀況,若是隻是對輸入進行簡單的右移,那麼負數的高位會自動的添加1則可能會進入死循環*/ /*常規解法: 不進行右移,先把輸入與標誌位進行與判斷最低位是否是1,再把標誌位進行左移判斷次低位是否是1 依次類推直到最高位,便可計算出1的個數 */ int NumberOf1(int n){ int count=0; unsigned int flag=1; while(flag){ if(n&flag) count++; flag<<1; } return count; } /*進階解法: 可進行論證把一個數減去1,再和原來數作與運算,會把該整數最右邊一個1變成0。例如1100,減去1後爲1011,兩數與後爲1000。 */ int NumberOf2(int n){ int count=0; while(n){ ++count; n=(n-1)&n; } return count; }