LeetCode详解C++版
打算把LeetCode上面的題都實現一遍,每日兩題
LeetCode目錄
- 1. 兩數之和
- 2. 兩數相加
- 11. 盛最多水的容器
- 15.三數之和
- 33.搜索旋轉排序數組
- 34. 在排序數組中查找元素的第一個和最后一個位置
- 35.搜索插入位置
- 53.最大子數組和
- 64. 最小路徑和
- 70.爬樓梯
- 74.搜索二維矩陣
- 82. 刪除排序鏈表中的重復元素 II
- 88. 合并兩個有序數組
- 153. 尋找旋轉排序數組中的最小值
- 162. 尋找峰值
- 167. 兩數之和 II - 輸入有序數組
- 189.輪轉數組
- 217.存在重復元素
- 278.第一個錯誤的版本
- 283. 移動零
- 344. 反轉字符串
- 557. 反轉字符串中的單詞 III
- 704. 二分查找
- 844. 比較含退格的字符串
- 977. 有序數組的平方
- 986. 區間列表的交集
- 劍指 Offer 05. 替換空格
- 劍指 Offer 06. 從尾到頭打印鏈表
- 劍指 Offer 09.用兩個棧實現隊列
- 劍指 Offer 24. 反轉鏈表
- 劍指 Offer 30.包含min函數的棧
1. 兩數之和
給定一個整數數組 nums 和一個整數目標值 target,請你在該數組中找出 和為目標值 target 的那 兩個 整數,并返回它們的數組下標。
你可以假設每種輸入只會對應一個答案。但是,數組中同一個元素在答案里不能重復出現。
你可以按任意順序返回答案。
思路
巧用map結構
代碼
2. 兩數相加
給你兩個 非空 的鏈表,表示兩個非負的整數。它們每位數字都是按照 逆序 的方式存儲的,并且每個節點只能存儲 一位 數字。
請你將兩個數相加,并以相同形式返回一個表示和的鏈表。
你可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。
思路
代碼
class Solution { public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode* sumnode = new ListNode(-1);ListNode* head = sumnode;int sum=0;bool carry=false;while(l1!=NULL || l2!=NULL){sum = 0;if(l1!=NULL){sum += l1->val;l1 = l1->next;}if(l2!=NULL){sum += l2->val;l2 = l2->next;}if(carry){sum++;}head->next = new ListNode(sum%10);head = head->next;if(sum >= 10){carry = true;}else{carry = false;}}if(sum >= 10){head->next = new ListNode(1);}return sumnode->next;} };改進版
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/ class Solution { public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode* re = new ListNode(0);ListNode* r = re;int carry=0;while(l1!=NULL || l2!=NULL){int x = 0;int y = 0;if(l1!=NULL){x = l1->val; }else{x = 0;}if(l2!=NULL){y = l2->val; }else{y = 0;}int s = carry + x + y;carry = s/10;r->next = new ListNode(s%10);r = r->next;if(l1!=NULL){l1 = l1->next;}if(l2!=NULL){l2 = l2->next;} }if(carry > 0){r->next = new ListNode(1);}return re->next;} };11. 盛最多水的容器
給定一個長度為 n 的整數數組 height 。有 n 條垂線,第 i 條線的兩個端點是 (i, 0) 和 (i, height[i]) 。
找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。
返回容器可以儲存的最大水量。
說明:你不能傾斜容器。
思路
使用雙指針 注意!我們每次只要移動高度小的一邊,因為移動小的那一邊可能會增大,但是移動大的一邊一定會減小
代碼
15.三數之和
給你一個包含 n 個整數的數組 nums,判斷 nums 中是否存在三個元素 a,b,c ,使得 a + b + c = 0 ?請你找出所有和為 0 且不重復的三元組。
注意:答案中不可以包含重復的三元組。
思路
可以使用雙指針,先排序(時間復雜度nlogn),然后令L = i+1 ,R = n - 1,我們遍歷i,如果值大了我們就R–,小了就L++
代碼
33.搜索旋轉排序數組
整數數組 nums 按升序排列,數組中的值 互不相同 。
在傳遞給函數之前,nums 在預先未知的某個下標 k(0 <= k < nums.length)上進行了 旋轉,使數組變為 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下標 從 0 開始 計數)。例如, [0,1,2,4,5,6,7] 在下標 3 處經旋轉后可能變為 [4,5,6,7,0,1,2] 。
給你 旋轉后 的數組 nums 和一個整數 target ,如果 nums 中存在這個目標值 target ,則返回它的下標,否則返回 -1 。
思路
二分查找題,先用二分查找找到k,然后找到目標值
代碼
34. 在排序數組中查找元素的第一個和最后一個位置
給定一個按照升序排列的整數數組 nums,和一個目標值 target。找出給定目標值在數組中的開始位置和結束位置。
如果數組中不存在目標值 target,返回 [-1, -1]。
進階:
你可以設計并實現時間復雜度為 O(log n) 的算法解決此問題嗎?
思路
兩分查找,先找開始的位置,在找結束的位置。
代碼
35.搜索插入位置
給定一個排序數組和一個目標值,在數組中找到目標值,并返回其索引。如果目標值不存在于數組中,返回它將會被按順序插入的位置。
請必須使用時間復雜度為 O(log n) 的算法。
思路
代碼
class Solution { public:int searchInsert(vector<int>& nums, int target) {int left = 0;int right = nums.size() - 1;while(left <= right){int mid = left + (right - left)/2;if(nums[mid] < target){left = mid + 1;}else {right = mid - 1;}}return left;} };53.最大子數組和
給你一個整數數組 nums ,請你找出一個具有最大和的連續子數組(子數組最少包含一個元素),返回其最大和。
子數組 是數組中的一個連續部分。
思路
可以使用動態規劃的方法,如下代碼,f_n表示前n個之和最大值
代碼
64. 最小路徑和
給定一個包含非負整數的 m x n 網格 grid ,請找出一條從左上角到右下角的路徑,使得路徑上的數字總和為最小。
說明:每次只能向下或者向右移動一步。
思路
代碼
class Solution { public:int minPathSum(vector<vector<int>>& grid) {int m = grid.size();int n = grid[0].size();if(m <= 0 || n <= 0){return 0;}int dp[m][n];dp[0][0] = grid[0][0];for(int i = 1;i < m;i++){dp[i][0] = grid[i][0] + dp[i-1][0];}for(int i = 1;i < n;i++){dp[0][i] = grid[0][i] + dp[0][i-1]; }for(int i = 1;i < m;i++){for(int j = 1;j < n;j++){dp[i][j] = min(dp[i-1][j],dp[i][j-1]) + grid[i][j];}}return dp[m-1][n-1];} };70.爬樓梯
假設你正在爬樓梯。需要 n 階你才能到達樓頂。
每次你可以爬 1 或 2 個臺階。你有多少種不同的方法可以爬到樓頂呢?
注意:給定 n 是一個正整數。
思路
代碼
class Solution { public:int climbStairs(int n) {int a[n+1];if(n <= 2){return n;}a[0] = 0;a[1] = 1;a[2] = 2;for(int i = 3;i <= n;i++){a[i] = a[i-1] + a[i-2];}return a[n];} };74.搜索二維矩陣
編寫一個高效的算法來判斷 m x n 矩陣中,是否存在一個目標值。該矩陣具有如下特性:
每行中的整數從左到右按升序排列。
每行的第一個整數大于前一行的最后一個整數。
思路
將二維排序成一維來做,繼續用二分查找
代碼
82. 刪除排序鏈表中的重復元素 II
給定一個已排序的鏈表的頭 head , 刪除原始鏈表中所有重復數字的節點,只留下不同的數字 。返回 已排序的鏈表 。
思路
很容易的題,主要是第一個值的話怎么刪,我們可以新建一個next 為列表的頭head
代碼
88. 合并兩個有序數組
給你兩個按 非遞減順序 排列的整數數組 nums1 和 nums2,另有兩個整數 m 和 n ,分別表示 nums1 和 nums2 中的元素數目。
請你 合并 nums2 到 nums1 中,使合并后的數組同樣按 非遞減順序 排列。
注意:最終,合并后數組不應由函數返回,而是存儲在數組 nums1 中。為了應對這種情況,nums1 的初始長度為 m + n,其中前 m 個元素表示應合并的元素,后 n 個元素為 0 ,應忽略。nums2 的長度為 n 。
思路
我們巧用nums1的結構,把從大到小排序放進去
代碼
153. 尋找旋轉排序數組中的最小值
已知一個長度為 n 的數組,預先按照升序排列,經由 1 到 n 次 旋轉 后,得到輸入數組。例如,原數組 nums = [0,1,2,4,5,6,7] 在變化后可能得到:
若旋轉 4 次,則可以得到 [4,5,6,7,0,1,2]
若旋轉 7 次,則可以得到 [0,1,2,4,5,6,7]
注意,數組 [a[0], a[1], a[2], …, a[n-1]] 旋轉一次 的結果為數組 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
給你一個元素值 互不相同 的數組 nums ,它原來是一個升序排列的數組,并按上述情形進行了多次旋轉。請你找出并返回數組中的 最小元素 。
你必須設計一個時間復雜度為 O(log n) 的算法解決此問題。
思路
查找旋轉次數就好了
代碼
162. 尋找峰值
峰值元素是指其值嚴格大于左右相鄰值的元素。
給你一個整數數組 nums,找到峰值元素并返回其索引。數組可能包含多個峰值,在這種情況下,返回 任何一個峰值 所在位置即可。
你可以假設 nums[-1] = nums[n] = -∞ 。
你必須實現時間復雜度為 O(log n) 的算法來解決此問題。
思路
二分法,只需要判斷nums[m] > nums[m+1],因為大的值一定有解
代碼
167. 兩數之和 II - 輸入有序數組
給定一個已按照 非遞減順序排列 的整數數組 numbers ,請你從數組中找出兩個數滿足相加之和等于目標數 target 。
函數應該以長度為 2 的整數數組的形式返回這兩個數的下標值。numbers 的下標 從 1 開始計數 ,所以答案數組應當滿足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假設每個輸入 只對應唯一的答案 ,而且你 不可以 重復使用相同的元素。
思路
代碼
class Solution { public:vector<int> twoSum(vector<int>& numbers, int target) {int l = 0;int r = numbers.size() - 1;while(l<r){if(numbers[l]+numbers[r]>target){r--;}else if(numbers[l]+numbers[r]<target){l++;}else{return {l+1,r+1};}}return {l+1,r+1};} };189.輪轉數組
給你一個數組,將數組中的元素向右輪轉 k 個位置,其中 k 是非負數。
示例 1: 輸入: nums = [1,2,3,4,5,6,7], k = 3 輸出: [5,6,7,1,2,3,4] 解釋: 向右輪轉 1 步: [7,1,2,3,4,5,6] 向右輪轉 2 步: [6,7,1,2,3,4,5] 向右輪轉 3 步: [5,6,7,1,2,3,4]示例 2: 輸入:nums = [-1,-100,3,99], k = 2 輸出:[3,99,-1,-100] 解釋: 向右輪轉 1 步: [99,-1,-100,3] 向右輪轉 2 步: [3,99,-1,-100]思路
代碼
class Solution { public:void rotate(vector<int>& nums, int k) {int n = nums.size();k = k % n;int count = gcd(k, n);for (int start = 0; start < count; ++start) {int current = start;int prev = nums[start];do {int next = (current + k) % n;swap(nums[next], prev);current = next;} while (start != current);}} };217.存在重復元素
給你一個整數數組 nums 。如果任一值在數組中出現 至少兩次 ,返回 true ;如果數組中每個元素互不相同,返回 false 。
示例 1: 輸入:nums = [1,2,3,1] 輸出:true 示例 2: 輸入:nums = [1,2,3,4] 輸出:false 示例 3: 輸入:nums = [1,1,1,3,3,4,3,2,4,2] 輸出:true思路
利用集合的唯一性來做。(暴力窮舉算法復雜度太大了O(n2)O(n^2)O(n2))
代碼
278.第一個錯誤的版本
你是產品經理,目前正在帶領一個團隊開發新的產品。不幸的是,你的產品的最新版本沒有通過質量檢測。由于每個版本都是基于之前的版本開發的,所以錯誤的版本之后的所有版本都是錯的。
假設你有 n 個版本 [1, 2, …, n],你想找出導致之后所有版本出錯的第一個錯誤的版本。
你可以通過調用 bool isBadVersion(version) 接口來判斷版本號 version 是否在單元測試中出錯。實現一個函數來查找第一個錯誤的版本。你應該盡量減少對調用 API 的次數。
思路
代碼
class Solution { public:int firstBadVersion(int n) {int l = 1, r = n, m = 0; while (l<r){m = l + ((r - l) >> 1);if(isBadVersion(m))r = m;elsel = m + 1;} return l;} };283. 移動零
給定一個數組 nums,編寫一個函數將所有 0 移動到數組的末尾,同時保持非零元素的相對順序。
示例: 輸入: [0,1,0,3,12] 輸出: [1,3,12,0,0]思路
代碼
class Solution { public:void moveZeroes(vector<int>& nums) {int m = nums.size(),j = 0;for(int i = 0;i < m;i++){if(nums[i]!=0){nums[j++] = nums[i];}}for(int i = j;j < m;j++){nums[j] = 0;}} };344. 反轉字符串
編寫一個函數,其作用是將輸入的字符串反轉過來。輸入字符串以字符數組 s 的形式給出。
不要給另外的數組分配額外的空間,你必須原地修改輸入數組、使用 O(1) 的額外空間解決這一問題。
思路
代碼
class Solution { public:void reverseString(vector<char>& s) { int r = s.size();int l = r;for(int i = 0; i<r/2;i++){l--;char tmp = s[i];s[i] = s[l];s[l] = tmp;}} };一行實現
class Solution { public:void reverseString(vector<char>& s) { s.reverse()} };557. 反轉字符串中的單詞 III
給定一個字符串,你需要反轉字符串中每個單詞的字符順序,同時仍保留空格和單詞的初始順序。
示例: 輸入:"Let's take LeetCode contest" 輸出:"s'teL ekat edoCteeL tsetnoc"思路
代碼
class Solution { public:string reverseWords(string s) {int n=s.size();int begin=0,end;for(int i=0;i<n+1;i++){if(s[i]==' '||s[i]=='\0'){for(end=i-1;begin<end;begin++,end--){swap(s[begin],s[end]);}begin=i+1;}}return s;} };704. 二分查找
給定一個 n 個元素有序的(升序)整型數組 nums 和一個目標值 target ,寫一個函數搜索 nums 中的 target,如果目標值存在返回下標,否則返回 -1。
示例 1: 輸入: nums = [-1,0,3,5,9,12], target = 9 輸出: 4 解釋: 9 出現在 nums 中并且下標為 4示例 2: 輸入: nums = [-1,0,3,5,9,12], target = 2 輸出: -1 解釋: 2 不存在 nums 中因此返回 -1思路
代碼
class Solution { public:int search(vector<int>& nums, int target) {int left = 0;int right = nums.size() - 1;while(left <= right){int mid = left + (right - left)/2;if(nums[mid] < target){left = mid + 1;}else if(nums[mid] > target){right = mid - 1;}else{return mid;} }return -1;} };844. 比較含退格的字符串
給定 s 和 t 兩個字符串,當它們分別被輸入到空白的文本編輯器后,如果兩者相等,返回 true 。# 代表退格字符。
注意:如果對空文本輸入退格字符,文本繼續為空。
思路
如果暴力的話肯定不行的,要占用新的內存,且要比較。我們可以使用雙指針,從后往前讀,比較每一個字符。有不符號返回flase
代碼
977. 有序數組的平方
給你一個按 非遞減順序 排序的整數數組 nums,返回每個數字的平方 組成的新數組,要求也按非遞減順序排序。
示例 1:輸入:nums = [-4,-1,0,3,10] 輸出:[0,1,9,16,100] 解釋:平方后,數組變為 [16,1,0,9,100] 排序后,數組變為 [0,1,9,16,100]示例 2: 輸入:nums = [-7,-3,2,3,11] 輸出:[4,9,9,49,121]提示: 1 <= nums.length <= 104 -104 <= nums[i] <= 104 nums 已按 非遞減順序 排序進階: 請你設計時間復雜度為 O(n) 的算法解決本問題思路
代碼
class Solution { public:vector<int> sortedSquares(vector<int>& nums) {for(int i=0;i<nums.size();i++){nums[i] = nums[i]*nums[i];}sort(nums.begin(),nums.end());return nums;} };986. 區間列表的交集
給定兩個由一些 閉區間 組成的列表,firstList 和 secondList ,其中 firstList[i] = [starti, endi] 而 secondList[j] = [startj, endj] 。每個區間列表都是成對 不相交 的,并且 已經排序 。
返回這 兩個區間列表的交集 。
形式上,閉區間 [a, b](其中 a <= b)表示實數 x 的集合,而 a <= x <= b 。
兩個閉區間的 交集 是一組實數,要么為空集,要么為閉區間。例如,[1, 3] 和 [2, 4] 的交集為 [2, 3] 。
思路
使用雙指針,一個指向其中一個數組,對每一個內部數組進行比較。
代碼
劍指 Offer 05. 替換空格
請實現一個函數,把字符串 s 中的每個空格替換成"%20"。
示例 1: 輸入:s = "We are happy." 輸出:"We%20are%20happy."思路
代碼
class Solution { public:string replaceSpace(string s) {int count = 0; // 統計空格的個數int sOldSize = s.size();for (int i = 0; i < s.size(); i++) {if (s[i] == ' ') {count++;}}// 擴充字符串s的大小,也就是每個空格替換成"%20"之后的大小s.resize(s.size() + count * 2);int sNewSize = s.size();// 從后先前將空格替換為"%20"for (int i = sNewSize - 1, j = sOldSize - 1; j < i; i--, j--) {if (s[j] != ' ') {s[i] = s[j];} else {s[i] = '0';s[i - 1] = '2';s[i - 2] = '%';i -= 2;}}return s;} };劍指 Offer 06. 從尾到頭打印鏈表
輸入一個鏈表的頭節點,從尾到頭反過來返回每個節點的值(用數組返回)。
示例 1: 輸入:head = [1,3,2] 輸出:[2,3,1]思路
代碼
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { public:vector<int> reversePrint(ListNode* head) {vector<int> res;while(head){res.push_back(head->val);head=head->next;}reverse(res.begin(),res.end());return res;} };劍指 Offer 09.用兩個棧實現隊列
用兩個棧實現一個隊列。隊列的聲明如下,請實現它的兩個函數 appendTail 和 deleteHead ,分別完成在隊列尾部插入整數和在隊列頭部刪除整數的功能。(若隊列中沒有元素,deleteHead 操作返回 -1 )
思路
代碼
class CQueue { public:stack<int>s1;stack<int>s2;CQueue() {}void appendTail(int value) {s1.push(value);}int deleteHead() {if(s1.empty() && s2.empty()){return -1;}if(!s1.empty() && s2.empty()){while(!s1.empty()){s2.push(s1.top());s1.pop();}int temp = s2.top();s2.pop();return temp;}if(!s2.empty()){int temp = s2.top();s2.pop();return temp;}return -1;} };/*** Your CQueue object will be instantiated and called as such:* CQueue* obj = new CQueue();* obj->appendTail(value);* int param_2 = obj->deleteHead();*/劍指 Offer 24. 反轉鏈表
定義一個函數,輸入一個鏈表的頭節點,反轉該鏈表并輸出反轉后鏈表的頭節點。
示例: 輸入: 1->2->3->4->5->NULL 輸出: 5->4->3->2->1->NULL思路
代碼
/*** 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) {vector<int> res;ListNode *p= head;ListNode *q = head; while(p){res.push_back(p->val);p=p->next;}reverse(res.begin(),res.end());for(int i = 0;i < res.size();i++){ q->val = res[i];q = q->next; }return head;} };劍指 Offer 30.包含min函數的棧
定義棧的數據結構,請在該類型中實現一個能夠得到棧的最小元素的 min 函數在該棧中,調用 min、push 及 pop 的時間復雜度都是 O(1)。
思路
代碼
class MinStack { public:/** initialize your data structure here. */int Min=inf;stack<int> st;MinStack() {}void push(int x) {st.push(Min);if(x<Min) Min=x;st.push(x);}void pop() {st.pop();Min = st.top();st.pop();}int top() {return st.top();}int min() {return Min;} };/*** Your MinStack object will be instantiated and called as such:* MinStack* obj = new MinStack();* obj->push(x);* obj->pop();* int param_3 = obj->top();* int param_4 = obj->min();*/總結
以上是生活随笔為你收集整理的LeetCode详解C++版的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android底部导航栏实现(一)之Bo
- 下一篇: springmvc 组合注解