日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

剑指 offer 编程题 C++ 版总结(上)

發布時間:2024/2/28 c/c++ 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 剑指 offer 编程题 C++ 版总结(上) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

解題思路:(1) 最簡單的方法是從后往前遍歷(需要兩層循環),但是這樣時間復雜度太高了,力扣上不能全過。(2) 由題可知,數值范圍為0~n-1,所以可以創建一個輔助數組,讓原始序列通過取余操作映射到輔助數組上,當輔助數據記錄兩次同一個元素時,表明該數字是重復的,直接返回就可以了。

int findRepeatNumber(vector<int>& nums) {int temp, size = nums.size();vector<int> a(size, 0);for(int i = 0; i < size; i++){temp = nums[i]%size;a[temp]++;if(a[temp] >= 2)break;}return temp; }int findRepeatNumber(vector<int>& nums) {unordered_map<int, bool> map;for(int num : nums) {if(map[num]) return num;map[num] = true;}return -1; }

?

?

解題思路:題中說明每一行和每一列都是按照遞增順序排序的。所以在找 target 的時候,可以從數組的右上角開始。若 matrix[rows][columns] > target,因為列是從上往下遞增的,所以這一列就不用再考慮了,令 columns--。若?matrix[rows][columns] <?target,因為行是從左往右遞增的,所以這一行就不用再考慮了,令 rows++。如果能找到 target 則返回 true,反之返回 false。

class Solution { public:bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {if(matrix.size() == 0) return false;int columns = matrix[0].size() - 1, rows = 0;//先計算行和列,循環條件是列大于0,行不超過二維數組的行數while(columns >= 0 && rows < matrix.size()){if(matrix[rows][columns] > target) columns--;else if(matrix[rows][columns] < target) rows++;else return true;}return false;} };

?

?

解題思路:先計算出空格的數量,再做一個擴容的操作,然后就是從后往前復制元素的工作。

string replaceSpace(string s) {if(s.empty()) return s;int spaceCount = 0, i = s.size() - 1;for(char c : s){ //計算空格的數量if(c == ' ') spaceCount ++;}s.resize(s.size() + spaceCount * 2); //擴容int j = s.size() - 1; while(i != j) //i是擴容前的最后一個元素下標,j是擴容后的最后一個元素的下標{ //從后往前替換空格if(s[i] != ' '){s[j--] = s[i--];}else{s[j--] = '0';s[j--] = '2';s[j--] = '%';i--;}}return s; }

?

?

解題思路:(1) 用棧先進后出的性質。(2) 使用數組復制鏈表的值,然后做一個反轉操作。 (3) 遞歸的過程中,將值 push 到 vector 中。

/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/用棧 vector<int> reversePrint(ListNode* head) {vector<int> res;stack<int> s;ListNode *p = head;while(p){s.push(p->val);p = p->next;}while(!s.empty()){res.push_back(s.top());s.pop();}return res; }用數組 vector<int> reversePrint(ListNode* head) {vector<int> res;ListNode *p = head;while(p){res.push_back(p->val);p = p->next;}reverse(res.begin(),res.end());return res; }遞歸過程中添加到 vector vector<int> asd; void reversePrint(ListNode* head) {if(head != NULL){if(head->next != NULL)reversePrint(head->next);}asd.push_back(head->value); }

?

?

解題思路:因為棧是先進后出的,所以當一個序列進入一個棧后出棧得到的序列再進入另一個棧后出棧,得到的序列和原序列一樣。兩個棧實現隊列,其中 stack1 用于添加數據,即入隊操作。stack2 用于刪除數據,即出隊操作。入隊時,將元素 push 到 stack1 中。出隊時,pop 出 stack2 中的元素即可。如若 stack2 此時為空,需要從 stack1 中的所有元素遷移到 stack2 后再完成 pop 操作。

class CQueue {stack<int> stack1, stack2; //stack1用來添加數據 stack2用來刪除數據 public:CQueue() {while (!stack1.empty()) {stack1.pop();}while (!stack2.empty()) {stack2.pop();}}void appendTail(int value) {stack1.push(value);}int deleteHead() {//如果第二個棧為空,此時還要出隊,就要把第一個棧的元素push到第二個棧中if (stack2.empty()) {while (!stack1.empty()) {stack2.push(stack1.top());stack1.pop();}} if (stack2.empty()) {return -1;} else {int deleteItem = stack2.top();stack2.pop();return deleteItem;}} };

?

?

解題思路:斐波那契數列的規律:f(n+1) = f(n) + f(n?1)。

class Solution { public:int fib(int n) {int result[2] = {0,1};if(n < 2)return result[n];long long fibone = 1;long long fibtwo = 0;long long fib = 0;//性質 f(n+1)=f(n)+f(n?1) for(unsigned int i = 2; i <= n; ++i){fib = (fibone + fibtwo)%(1000000007);fibtwo = fibone;fibone = fib;}return fib;} };

?

?

解題思路:青蛙跳臺階的規律:f(n) = f(n-1) + f(n-2) 。本題可轉化為 求斐波那契數列第 n 項的值,與斐波那契數列等價,唯一的不同在于起始數字不同。

斐波那契數列問題: f(0) = 0, f(1) = 1, f(2) = 1。

青蛙跳臺階問題: f(0) = 1, f(1) = 1, f(2) = 2。

class Solution { public:int numWays(int n) {if(n == 0 || n == 1) return 1;int N = 0, One = 1, Two = 1;while(n >= 2){// f(n) = f(n-1) + f(n-2);// 采取從下往上的方法,把計算過的中間項保存起來,避免重復計算導致遞歸調用棧溢出N = (One + Two) % 1000000007;Two = One;One = N;n--;}return N;} };

?

?

解題思路:該題最簡單的方式是遍歷數組找最小值,但是如果真的出該題,一般都會對時間復雜度做出要求。由于這是一個遞增的數組旋轉后的結果,所以當下標為 mid 的元素小于下標為 high 的元素時,最小的元素一定在 mid 的左側(包括 mid,所以令 high = mid)。而當下標為 mid 的元素大于下標為 high 的元素時,最小的元素一定在 mid 的右側(此時不包括 mid,所以令 low = mid + 1)。

class Solution { public:int minArray(vector<int>& numbers) {int low = 0;int high = numbers.size() - 1;while (low < high) {int mid = low + (high - low) / 2;if (numbers[mid] < numbers[high]) {high = mid;}else if (numbers[mid] > numbers[high]) {low = mid + 1;}else {high -= 1;}}return numbers[low];} };

有一些二分法的題解寫的是 low + (high - low) / 2 而不是 (high + low) / 2。因為 low+high 在 low 和 ?high 特別大的時候可能會造成溢出,使用減法能避免溢出的發生。

?

?

解題思路:使用 DFS 解題,從左到右,從上到下遍歷。遇到第一個與字符串第一個值相等的位置時,以該位置為起點,進行深度優先搜索。當行列值不滿足矩陣的范圍時,直接返回 false,反之,繼續進行搜索。注意,當搜索到一個位置的時候,需要將這個元素替換成 '\0',表明當前元素暫時不參與比較。

class Solution { public:bool exist(vector<vector<char>>& board, string word) {if(word.empty()) return false;for(int i = 0; i < board.size(); ++i){for(int j = 0; j < board[0].size(); ++j){ if(dfs(board, word, i, j, 0)) return true;}}return false;}bool dfs(vector<vector<char>>& board, string& word, int i, int j, int index){if(i<0 || i>=board.size() || j<0 || j>=board[0].size() || board[i][j]!=word[index]) return false;if(index == word.length() - 1) return true;char temp = board[i][j];board[i][j] = '\0'; // 將當前元素標記為'\0',表明當前元素不可再參與比較if(dfs(board,word,i-1,j,index+1) || dfs(board,word,i+1,j,index+1) || dfs(board,word,i,j-1,index+1) || dfs(board,word,i,j+1,index+1)){// 當前元素的上下左右,如果有匹配到的,返回truereturn true;}board[i][j] = temp; // 將當前元素恢復回其本身值return false;} };

?

?

解題思路:該題整體思路與矩陣中的路徑一樣。不同的是,該題需要一個 bool 型數組記錄走過的方塊,防止重復計數。

class Solution { public:int getsum(int n){int sum = 0;while( n > 0 ){sum += n%10;n /= 10;}return sum;}bool check(int t, int rows, int cols, int row, int col, bool* visited){if(row >= 0 && row < rows && col >= 0 && col < cols&& getsum(row) + getsum(col) <= t&& !visited[row*cols + col])return true;return false;}int movingcountCore(int t, int rows, int cols, int row, int col, bool* visited){int count = 0;if(check(t, rows, cols, row, col, visited)){visited[row*cols + col] = true;count = 1 + movingcountCore(t, rows, cols, row-1, col, visited) +movingcountCore(t, rows, cols, row+1, col, visited) +movingcountCore(t, rows, cols, row, col-1, visited) +movingcountCore(t, rows, cols, row, col+1, visited);}return count;}int movingCount(int m, int n, int k) { //m是行,n是列,k是閾值。if(k < 0 || m <= 0 || n <= 0)return 0;// movingCount 完成基本的判斷,調用 movingcountCore 完成工作// visited 用來記錄訪問過的單元bool* visited = new bool[m*n];for(int i = 0; i < m*n; ++i)visited[i] = false;int count = movingcountCore(k, m, n, 0, 0, visited);delete []visited;return count;} };

?

?

解題思路:(1) 動態規劃剪繩子的性質:f(n) = max( f(i) * f(n-i) ),特殊處理:使用一個res數組是做記憶化處理用的。如果某個長度的繩子,剪了一下之后,其中一段的長度在 [0,3] 的區間內,就不要再剪這一段了。因為剪了之后,乘積會變小,而 res[i] 是長度為 i 的繩子剪成若干段后能獲得的最大乘積,所以 res[0] 到 res[3] 要單獨處理。當長度大于等于 4 時,利用 f(n) = max( f(i) * f(n-i) ) 記錄繩子的最大乘積。

(2) 該題最簡單的解法是使用貪心算法。當 n 大于等于 5 時,可以推導出,n 的組合中剪出 3 的繩子的段數越多,相應的乘積越大。所以為了得到最優解,應該盡可能地多剪長度為 3 的繩子。當問題規模 n 變大時,需要根據題目需求取模。

class Solution { public:int cuttingRope(int n) {//動態規劃剪繩子: f(n) = max( f(i)*f(n-i) );if(n <= 3) return n - 1; // 當繩子的總長度<=3時,做特殊情況處理vector<int> res(n + 1, 0); // res[i]表示長度為i的繩子剪成若干段之后,乘積的最大值//特殊處理:如果某個長度的繩子,剪了一下之后,其中一段的長度在[0,3]的區間內,就不要再剪這一段了//因為剪了之后,乘積會變小,而res[i]是長度為i的繩子剪成若干段后能獲得的最大乘積//所以[res[0],res[3]]要單獨處理(如下)res[0] = 0;res[1] = 1;res[2] = 2;res[3] = 3; //比如3再剪的話最大值就是2,比原來還小,所以不剪了int maxProduct = 0;for(int i = 4; i <= n; ++i){maxProduct = 0;for(int j = 1; j <= i/2; ++j){//循環體中寫i/2是為了減少計算次數(因為比如1x3和3x1值是一樣的,計算一次即可)int temp = res[j] * res[i-j];maxProduct = max(maxProduct, temp);res[i] = maxProduct; // res數組是做記憶化處理用的}}return res[n];} }; class Solution { public:int cuttingRope(int n) {if(n <= 3) return n-1;int res = 1;while(n > 4){n = n - 3; //盡可能地多剪長度為3的繩子res = res * 3; }return res * n;} };

?

?

解題思路:通過左移和與操作計算一個數字的二進制形式中 1 的個數。

class Solution { public:int hammingWeight(uint32_t n) {int count = 0;unsigned int flag = 1;while(flag){if(n & flag)count++;flag = flag << 1;}return count;} };

?

?

解題思路:需要用到快速冪的思想。其核心相當于將問題做了一個轉換,例如:2^(4) 轉換成 ( 2^(2) )^(2),即 4^(2)。所以下面的代碼中 x *= x; 和 exp >>= 1; 是成對出現的。

class Solution { public:double myPow(double x, int n) {if(n == 0 || x == 1.0) return 1;if(x == 0.0 && n < 0) return x; // 當x是0而n是負數的時候,特殊情況double res = 1.0;long exp = n; // 必須是long,否則如果n=INT_MIN,-n會越界if(exp < 0){x = 1 / x;exp = -exp;}while(exp) // 核心{// 快速冪方法(位運算)// 假如n=9,9寫成二進制就是1001// 每當exp & 1 = 1的時候,就執行乘方運算if(exp & 1) res *= x;x *= x;exp >>= 1;}return res;} };

?

?

解題思路:直接 for 循環打印也是可以的,但是這種題不應該只是這種難度。面試的時候可能會把它作為一道大數問題來考。作為大數問題,首先要考慮到當n很大的時候(比如100),打印出來的數很有可能是超過了 INT_MAX 的范圍的,所以需要用字符串來表示每個數。在這一題中,由于返回的是一個 int 型的數組,所以是不可能超過 INT_MAX 的,但是一般大數問題都不會要求返回 int 數組來保存每一位數,而是循環輸出每一位數。

class Solution { public:vector<int> output;vector<int> printNumbers(int n) {// 假設 n = 3if(n <= 0) return vector<int>(0);string s(n, '0'); // s最大會等于999,即s的長度為nwhile(!overflow(s)) inputNumbers(s);return output;}bool overflow(string& s){// 本函數用于模擬數字的累加過程,并判斷是否越界(即 999 + 1 = 1000,就是越界情況)bool isOverFlow = false;int carry = 0; // carry表示進位for(int i = s.length()-1; i>=0; --i){int current = s[i] - '0' + carry; // current表示當前這次的操作if(i == s.length() - 1) current++; // 如果i此時在個位,current執行 +1 操作if(current >= 10){// 假如i已經在最大的那一位了,而current++之后>=10,說明循環到頭了,即999 + 1 = 1000if(i == 0) isOverFlow = true;else{// 只是普通進位,比如current從10變成11carry = 1;s[i] = current - 10 + '0'; }}else{// 如果沒有進位,更新s[i]的值,然后直接跳出循環,這樣就可以回去執行inputNumbers函數了,即往output里添加元素s[i] = current + '0';break;}}return isOverFlow;}void inputNumbers(string s){// 本函數用于循環往output中添加符合傳統閱讀習慣的元素。比如001,我們會添加1而不是001。bool isUnwantedZero = true; // 判斷是否是不需要添加的0,比如001前面的兩個0string temp = "";for(int i = 0; i < s.length(); ++i){if(isUnwantedZero && s[i] != '0') isUnwantedZero = false;if(!isUnwantedZero) temp += s[i];}output.push_back(stoi(temp));} };

?

?

解題思路:該題提示不需要 free 或 delete 相應結點。若刪除的是頭結點,則返回頭結點后面的結點即可。若刪除的不是頭結點,遍歷過程中找到刪除結點的前一個結點后,讓其 next 指針指向被刪除結點后即可。

/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:ListNode* deleteNode(ListNode* head, int val) {if(head == NULL) return NULL;if(head->val == val) return head->next;ListNode *p = head;while(p->next){if(p->next->val == val){p->next = p->next->next;break;}p = p->next;}return head;} };

?

?

解題思路:主要是用四個變量區分狀態:hasNum,hasOp,hasE,hasDot,分別代表擁有數字、正負號、e 和小數點。從前往后逐個字符進行判斷,比較好理解的是當遇到 "." 時,如果 hasDot 為真的時候,返回 false,因為一個數字里不能有兩個 "."。如果遇到了正負號,而此時 hasOp,hasNum,hasDot 其中有一項為真,則說明該正負號不是開頭的符號,所以返回 false(如果有 e 的情況,相應的判斷語句會重置其他三個值)。

class Solution { public:bool isNumber(string s) {int n = s.size();int index = -1;bool hasDot = false,hasE = false,hasOp = false,hasNum = false;while(index<n && s[++index]==' ');while(index<n){if('0'<=s[index] && s[index]<='9'){hasNum = true;}else if(s[index]=='e' || s[index]=='E'){if(hasE || !hasNum) return false;hasE = true;hasOp = false;hasDot = false;hasNum = false;}else if(s[index]=='+' || s[index]=='-'){if(hasOp || hasNum || hasDot) return false;hasOp = true;}else if(s[index]=='.'){if(hasDot || hasE) return false;hasDot = true;}else if(s[index]==' '){break;}else{return false;}++index;}while(index<n && s[++index]==' ');return hasNum && index==n;} };

?

?

解題思路:從前往后找偶數,從后往前找奇數。若下標滿足條件,則交換兩者的值。

class Solution { public:vector<int> exchange(vector<int>& nums) {int size = nums.size();if(size == 0)return nums;int low = 0, high = size-1;while(low < high){if(nums[low] % 2 == 1 && low < size) {low++; continue;}if(nums[high] % 2 == 0 && high > 0) {high--; continue;}if(low < high)swap(nums[low++], nums[high--]);}return nums;} };

?

?

解題思路:計算出鏈表長度,然后從前往后走 len-k 步即可。

/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:ListNode* getKthFromEnd(ListNode* head, int k) {if(head == NULL)return NULL;ListNode* p = head;int count = 0;while(p != NULL){count++;p = p->next;}int nodelen = count - k;p = head;while(nodelen--){p = p->next;}return p;} };

?

?

解題思路:使用 3 個指針變量,pre 指向的原序列中當前結點之前的結點,pcur 開始指向頭結點,Rp 用于記錄反轉后的序列的頭結點。在反轉過程中,先使用 pnext 指向 pcur 的下一個結點,作為一個記錄。然后 pcur->next?指向 pre,此時已經讓當前結點的 next 指向原序列的 pre 了。接下來讓 pre 指向 pcur 后再讓 pcur 指向 pnext 即可完成相應的工作。

/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:ListNode* reverseList(ListNode* head) {ListNode* pre = NULL, *pcur = head, *Rp = NULL;while(pcur != NULL){ListNode* pnext = pcur->next;if(pnext == NULL)Rp = pcur;pcur->next = pre;pre = pcur;pcur = pnext;}return Rp;} };

?

?

解題思路:遞歸法和迭代法的思路都比較簡單,這里不再贅述。

/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ 迭代法 class Solution { public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {if(!l1) return l2;if(!l2) return l1;ListNode *dummy = new ListNode(INT_MAX);ListNode *res = dummy;while(l1 && l2){if(l1 -> val < l2 -> val){res -> next = l1;l1 = l1 -> next;}else{res -> next = l2;l2 = l2 -> next;}res = res -> next;}res -> next = l1 ? l1 : l2; // 當有一條鏈表遍歷到頭,while循環退出之后,pos->next應指向尚未遍歷完的那條鏈表return dummy -> next;} };遞歸法 class Solution { public:ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {if(!l1) return l2;if(!l2) return l1;if(l1 -> val < l2 -> val){l1 -> next = mergeTwoLists(l1 -> next, l2);return l1;}else{l2 -> next = mergeTwoLists(l1, l2 -> next);return l2;}} };

?

?

解題思路:進行深度遍歷,只有當兩者的值相等的時候才判斷 A 是否包含 B。

/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/ class Solution { public:bool isSubStructure(TreeNode* A, TreeNode* B) {bool result = false;if (A != nullptr && B != nullptr) {if (A->val == B->val) { //值相等才判斷A是否包含Bresult = isTreeAHaveTreeB(A, B);}if (!result) {result = isSubStructure(A->left, B);}if (!result) {result = isSubStructure(A->right, B);}}return result;}bool isTreeAHaveTreeB(TreeNode* A, TreeNode* B) {if (B == nullptr) {return true; //B已經對比完了,所以返回true}if (A == nullptr) { //此時B有值,而A卻為空,返回falsereturn false;}if (A->val != B->val) {return false;}return isTreeAHaveTreeB(A->left, B->left) && isTreeAHaveTreeB(A->right, B->right);} };

?

?

解題思路:從根開始,交換左右指針。

/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode(int x) : val(x), left(NULL), right(NULL) {}* };*/ class Solution { public:TreeNode* mirrorTree(TreeNode* root) {if (root == NULL) {return NULL;}swap(root->left, root->right);mirrorTree(root->left);mirrorTree(root->right);return root;} };

?

總結

以上是生活随笔為你收集整理的剑指 offer 编程题 C++ 版总结(上)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。