摘要:有效三角形的個數雙指針最暴力的方法應該是三重循環枚舉三個數字。總結本題和三數之和很像,都是三個數加和為某一個值。所以我們可以使用歸并排序來解決這個問題。注意因為歸并排序需要遞歸,所以空間復雜度為
本題其實就是層序遍歷一個二叉樹的升級版,我們需要要將二叉樹層序遍歷的結果放入答案中,然后將偶數層的節點結果逆置一遍即可。
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */class Solution {public: vector<vector<int>> zigzagLevelOrder(TreeNode* root) { if (!root) return {}; vector<vector<int>> ans; queue<TreeNode*> q; q.push(root); int step = 1; while (!q.empty()) { int size = q.size(); vector<int> path; while (size --) { auto top = q.front(); q.pop(); path.push_back(top->val); if (top->left) q.push(top->left); if (top->right) q.push(top->right); } if (step % 2 == 0) reverse(path.begin(), path.end()); ans.push_back(path); step ++; } return ans; }};
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */class Solution {public: vector<vector<int>> zigzagLevelOrder(TreeNode* root) { vector<vector<int>> ans; if (!root) return ans; stack<TreeNode*> odd; stack<TreeNode*> even; odd.push(root); int flag = 1; while (!odd.empty() || !even.empty()) { vector<int> path; if (flag > 0) { while (!odd.empty()) { auto top = odd.top(); odd.pop(); path.push_back(top->val); if (top->left) even.push(top->left); if (top->right) even.push(top->right); } } else { while (!even.empty()) { auto top = even.top(); even.pop(); path.push_back(top->val); if (top->right) odd.push(top->right); if (top->left) odd.push(top->left); } } flag *= -1; ans.push_back(path); } return ans; }};
本題因為數組是有序數組拆分而成,所以數組局部還是具有單調性的。
如果一個數組沒有被拆分成兩個數組的話,那么直接返回這個有序數組的開頭即可。
如果一個數組被拆分成了兩個數組的話,那么被拆分后的數組的左右兩邊都是是一段有序的數組,并且左邊一段數組都>nums.back()
,右邊一段數組都<=nums.back()
。
根據這個特點就可以二分答案了,我們需要從左向右找出第一個
注意:因為有可能會有重復數字出現在數組中,所以被拆分的左邊數組的前端和右邊數組的后端可能會是重復的元素。但是這就不滿足左數組中的數字都>nums.back()
了,所以我們需要將右邊數組后半段重復的數字去掉,這樣就可以使得nums.back()
都小于左邊數組中的所有數組了。
class Solution {public: int minArray(vector<int>& nums) { int n = nums.size(); if (nums[0] < nums.back()) return nums[0]; int l = 0, r = n - 1; while (l < r && nums[0] == nums[r]) r --; int target = nums[r]; while (l < r) { int mid = l + (r - l) / 2; if (nums[mid] <= target) r = mid; else l = mid + 1; } return nums[l]; }};
最暴力的方法應該是三重循環枚舉三個數字。但是這樣會超時。
經過觀察可以發現,如果數組經過排序,那么從前往后判斷三角形是否有效就可以利用最小的兩條邊相加是否大于最大的一條邊來判斷。
而且如果我們先枚舉最大的一個數字nums[i]
的話,那么nums[j] + nums[k]
的和一定需要大于nums[i]
,而且因為數組是有序的,所以如果nums[j]
減小的話,那么nums[k]
就需要增大,這樣才可以使得nums[j] + nums[k] > nums[i]
,因此可以利用這個單調性的原則使得我們可以使用雙指針算法來解決本題。
class Solution {public: int triangleNumber(vector<int>& nums) { int n = nums.size(); sort(nums.begin(), nums.end()); int ans = 0; for (int i = 2; i < n; i ++) { for (int j = i - 1, k = 0; k < j; j --) { while (k < j && nums[k] + nums[j] <= nums[i]) k ++; ans += j - k; } } return ans; }};
總結:本題和「三數之和」很像,都是三個數加和為某一個值。然后我們可以通過排序過后,只用枚舉其中一個數字和利用雙指針就可以通過。
這么做的原因是因為已經有了排序和三個數的關系,所以只需要枚舉一個數字,那么另兩個數字的總和會是一個相對固定的值。利用總和不變和數組有序的原理,所以可以利用雙指針解決這個問題。
其實本題就是一個偏移量的問題,我們需要數組轉動起來,這可以使用偏移量數組來解決。利用int xd[4] = {0, 1, 0, -1}, yd[4] = {1, 0, -1, 0};
使得數組可以順時針旋轉起來。除非越界或者已經被訪問過了,否則按照原來的方向繼續前進,否則的話,我們就需要手動的將轉動的方向調整一下。
class Solution {public: const int INF = 0x3f3f3f3f; vector<int> spiralOrder(vector<vector<int>>& matrix) { if (matrix.empty()) return {}; int n = matrix.size(), m = matrix[0].size(); vector<int> ans; int x = 0, y = 0, d = 0; int xd[4] = {0, 1, 0, -1}, yd[4] = {1, 0, -1, 0}; vector<vector<bool>> vis(n, vector<bool>(m)); for (int i = 0; i < n * m; i ++) { ans.push_back(matrix[x][y]); vis[x][y] = true; int a = x + xd[d], b = y + yd[d]; if (a < 0 || b < 0 || a >= n || b >= m || vis[a][b]) { d = (d + 1) % 4; a = x + xd[d], b = y + yd[d]; } x = a, y = b; } return ans; }};
我們提取出每一層的最后一個節點,所以我們只需要使用層序遍歷找到每一層的最后一個節點,然后放入ans
中即可。
class Solution {public: vector<int> rightSideView(TreeNode* root) { vector<int> ans; if (!root) return ans; queue<TreeNode*> q; q.push(root); while (!q.empty()) { int size = q.size(); while (size --) { TreeNode* top = q.front(); q.pop(); if (!size) ans.push_back(top->val); if (top->left) q.push(top->left); if (top->right) q.push(top->right); } } return ans; }};
class Solution {public: vector<int> ans; void dfs(TreeNode* root, int depth) { if (!root) return ; if (depth == ans.size()) { ans.push_back(root->val); } depth ++; dfs(root->right, depth); dfs(root->left, depth); } vector<int> rightSideView(TreeNode* root) { if (!root) return ans; dfs(root, 0); return ans; }};
class Solution {public: const int INF = 0x3f3f3f3f; ListNode* Sort(ListNode* head) { if (!head->next) return head; ListNode* newHead = Sort(head->next); ListNode* dummy = new ListNode(INF); dummy->next = newHead; ListNode* cur = newHead, *prev = dummy; while (cur && cur->val < head->val) { prev = cur; cur = cur->next; } head->next = cur; prev->next = head; ListNode* ans = dummy->next; delete dummy; return ans; } ListNode* sortList(ListNode* head) { if (!head) return nullptr; return Sort(head); }};
如果想要實現nlogn
的時間復雜度的話,就必須使用二分的策略。所以我們可以使用歸并排序來解決這個問題。
歸并排序的核心思想就是合并兩個一半的鏈表,所以我們先將鏈表從中間分割開來,然后將分割后的兩個鏈表二路歸并起來就可以了。
核心步驟:
1.利用快慢指針將鏈表從中間分成兩半,并且兩個鏈表需要成為獨立的鏈表(尾指針都指向空)。
2.二路歸并,每次都挑選出兩個鏈表中較小節點作為鏈表的下一個節點。
注意:因為歸并排序需要遞歸,所以空間復雜度為logn
class Solution {public: ListNode* sortList(ListNode* head) { if (!head || !head->next) return head;
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/123347.html
摘要:值得一提的是每篇文章都是我用心整理的,編者一貫堅持使用通俗形象的語言給我的讀者朋友們講解機器學習深度學習的各個知識點。今天,紅色石頭特此將以前所有的原創文章整理出來,組成一個比較合理完整的機器學習深度學習的學習路線圖,希望能夠幫助到大家。 一年多來,公眾號【AI有道】已經發布了 140+ 的原創文章了。內容涉及林軒田機器學習課程筆記、吳恩達 deeplearning.ai 課程筆記、機...
摘要:每天會折騰一道及以上題目,并將其解題思路記錄成文章,發布到和微信公眾號上。三匯總返回目錄在月日月日這半個月中,做了匯總了數組知識點。或者拉到本文最下面,添加的微信等會根據題解以及留言內容,進行補充,并添加上提供題解的小伙伴的昵稱和地址。 LeetCode 匯總 - 2019/08/15 Create by jsliang on 2019-08-12 19:39:34 Recently...
摘要:月下半旬攻略道題,目前已攻略題。目前簡單難度攻略已經到題,所以后面會調整自己,在刷算法與數據結構的同時,攻略中等難度的題目。 Create by jsliang on 2019-07-30 16:15:37 Recently revised in 2019-07-30 17:04:20 7 月下半旬攻略 45 道題,目前已攻略 100 題。 一 目錄 不折騰的前端,和咸魚有什么區別...
摘要:經過半年的沉淀,加上對,和分布式這塊的補齊,終于開始重拾面試信心,再次出征。面試官提示沒有提到線程的有內核態的切換,程只在用戶態調度。三面綜合技術面這面面的是陣腳大亂,面試官采用刨根問底的方式提問,終究是面試經驗不夠,導致面試的節奏有點亂。 經過半年的沉淀,加上對MySQL,redis和分布式這塊的補齊,終于開始重拾面試信心,再次出征。 鵝廠 面試職位:go后端開發工程師,接受從Jav...
閱讀 2189·2021-11-15 11:38
閱讀 1151·2021-09-06 15:02
閱讀 3380·2021-08-27 13:12
閱讀 1353·2019-08-30 14:20
閱讀 2389·2019-08-29 15:08
閱讀 636·2019-08-29 14:08
閱讀 1723·2019-08-29 13:43
閱讀 1464·2019-08-26 12:11