摘要:有效三角形的個(gè)數(shù)雙指針最暴力的方法應(yīng)該是三重循環(huán)枚舉三個(gè)數(shù)字??偨Y(jié)本題和三數(shù)之和很像,都是三個(gè)數(shù)加和為某一個(gè)值。所以我們可以使用歸并排序來解決這個(gè)問題。注意因?yàn)闅w并排序需要遞歸,所以空間復(fù)雜度為
本題其實(shí)就是層序遍歷一個(gè)二叉樹的升級(jí)版,我們需要要將二叉樹層序遍歷的結(jié)果放入答案中,然后將偶數(shù)層的節(jié)點(diǎn)結(jié)果逆置一遍即可。
/** * 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; }};
本題因?yàn)閿?shù)組是有序數(shù)組拆分而成,所以數(shù)組局部還是具有單調(diào)性的。
如果一個(gè)數(shù)組沒有被拆分成兩個(gè)數(shù)組的話,那么直接返回這個(gè)有序數(shù)組的開頭即可。
如果一個(gè)數(shù)組被拆分成了兩個(gè)數(shù)組的話,那么被拆分后的數(shù)組的左右兩邊都是是一段有序的數(shù)組,并且左邊一段數(shù)組都>nums.back()
,右邊一段數(shù)組都<=nums.back()
。
根據(jù)這個(gè)特點(diǎn)就可以二分答案了,我們需要從左向右找出第一個(gè)
注意:因?yàn)橛锌赡軙?huì)有重復(fù)數(shù)字出現(xiàn)在數(shù)組中,所以被拆分的左邊數(shù)組的前端和右邊數(shù)組的后端可能會(huì)是重復(fù)的元素。但是這就不滿足左數(shù)組中的數(shù)字都>nums.back()
了,所以我們需要將右邊數(shù)組后半段重復(fù)的數(shù)字去掉,這樣就可以使得nums.back()
都小于左邊數(shù)組中的所有數(shù)組了。
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]; }};
最暴力的方法應(yīng)該是三重循環(huán)枚舉三個(gè)數(shù)字。但是這樣會(huì)超時(shí)。
經(jīng)過觀察可以發(fā)現(xiàn),如果數(shù)組經(jīng)過排序,那么從前往后判斷三角形是否有效就可以利用最小的兩條邊相加是否大于最大的一條邊來判斷。
而且如果我們先枚舉最大的一個(gè)數(shù)字nums[i]
的話,那么nums[j] + nums[k]
的和一定需要大于nums[i]
,而且因?yàn)閿?shù)組是有序的,所以如果nums[j]
減小的話,那么nums[k]
就需要增大,這樣才可以使得nums[j] + nums[k] > nums[i]
,因此可以利用這個(gè)單調(diào)性的原則使得我們可以使用雙指針?biāo)惴▉斫鉀Q本題。
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; }};
總結(jié):本題和「三數(shù)之和」很像,都是三個(gè)數(shù)加和為某一個(gè)值。然后我們可以通過排序過后,只用枚舉其中一個(gè)數(shù)字和利用雙指針就可以通過。
這么做的原因是因?yàn)橐呀?jīng)有了排序和三個(gè)數(shù)的關(guān)系,所以只需要枚舉一個(gè)數(shù)字,那么另兩個(gè)數(shù)字的總和會(huì)是一個(gè)相對(duì)固定的值。利用總和不變和數(shù)組有序的原理,所以可以利用雙指針解決這個(gè)問題。
其實(shí)本題就是一個(gè)偏移量的問題,我們需要數(shù)組轉(zhuǎn)動(dòng)起來,這可以使用偏移量數(shù)組來解決。利用int xd[4] = {0, 1, 0, -1}, yd[4] = {1, 0, -1, 0};
使得數(shù)組可以順時(shí)針旋轉(zhuǎn)起來。除非越界或者已經(jīng)被訪問過了,否則按照原來的方向繼續(xù)前進(jìn),否則的話,我們就需要手動(dòng)的將轉(zhuǎn)動(dòng)的方向調(diào)整一下。
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; }};
我們提取出每一層的最后一個(gè)節(jié)點(diǎn),所以我們只需要使用層序遍歷找到每一層的最后一個(gè)節(jié)點(diǎn),然后放入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); }};
如果想要實(shí)現(xiàn)nlogn
的時(shí)間復(fù)雜度的話,就必須使用二分的策略。所以我們可以使用歸并排序來解決這個(gè)問題。
歸并排序的核心思想就是合并兩個(gè)一半的鏈表,所以我們先將鏈表從中間分割開來,然后將分割后的兩個(gè)鏈表二路歸并起來就可以了。
核心步驟:
1.利用快慢指針將鏈表從中間分成兩半,并且兩個(gè)鏈表需要成為獨(dú)立的鏈表(尾指針都指向空)。
2.二路歸并,每次都挑選出兩個(gè)鏈表中較小節(jié)點(diǎn)作為鏈表的下一個(gè)節(jié)點(diǎn)。
注意:因?yàn)闅w并排序需要遞歸,所以空間復(fù)雜度為logn
class Solution {public: ListNode* sortList(ListNode* head) { if (!head || !head->next) return head;
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/123347.html
摘要:值得一提的是每篇文章都是我用心整理的,編者一貫堅(jiān)持使用通俗形象的語言給我的讀者朋友們講解機(jī)器學(xué)習(xí)深度學(xué)習(xí)的各個(gè)知識(shí)點(diǎn)。今天,紅色石頭特此將以前所有的原創(chuàng)文章整理出來,組成一個(gè)比較合理完整的機(jī)器學(xué)習(xí)深度學(xué)習(xí)的學(xué)習(xí)路線圖,希望能夠幫助到大家。 一年多來,公眾號(hào)【AI有道】已經(jīng)發(fā)布了 140+ 的原創(chuàng)文章了。內(nèi)容涉及林軒田機(jī)器學(xué)習(xí)課程筆記、吳恩達(dá) deeplearning.ai 課程筆記、機(jī)...
摘要:每天會(huì)折騰一道及以上題目,并將其解題思路記錄成文章,發(fā)布到和微信公眾號(hào)上。三匯總返回目錄在月日月日這半個(gè)月中,做了匯總了數(shù)組知識(shí)點(diǎn)?;蛘呃奖疚淖钕旅?,添加的微信等會(huì)根據(jù)題解以及留言內(nèi)容,進(jìn)行補(bǔ)充,并添加上提供題解的小伙伴的昵稱和地址。 LeetCode 匯總 - 2019/08/15 Create by jsliang on 2019-08-12 19:39:34 Recently...
摘要:月下半旬攻略道題,目前已攻略題。目前簡單難度攻略已經(jīng)到題,所以后面會(huì)調(diào)整自己,在刷算法與數(shù)據(jù)結(jié)構(gòu)的同時(shí),攻略中等難度的題目。 Create by jsliang on 2019-07-30 16:15:37 Recently revised in 2019-07-30 17:04:20 7 月下半旬攻略 45 道題,目前已攻略 100 題。 一 目錄 不折騰的前端,和咸魚有什么區(qū)別...
摘要:經(jīng)過半年的沉淀,加上對(duì),和分布式這塊的補(bǔ)齊,終于開始重拾面試信心,再次出征。面試官提示沒有提到線程的有內(nèi)核態(tài)的切換,程只在用戶態(tài)調(diào)度。三面綜合技術(shù)面這面面的是陣腳大亂,面試官采用刨根問底的方式提問,終究是面試經(jīng)驗(yàn)不夠,導(dǎo)致面試的節(jié)奏有點(diǎn)亂。 經(jīng)過半年的沉淀,加上對(duì)MySQL,redis和分布式這塊的補(bǔ)齊,終于開始重拾面試信心,再次出征。 鵝廠 面試職位:go后端開發(fā)工程師,接受從Jav...
閱讀 2203·2021-11-15 11:38
閱讀 1164·2021-09-06 15:02
閱讀 3404·2021-08-27 13:12
閱讀 1372·2019-08-30 14:20
閱讀 2410·2019-08-29 15:08
閱讀 651·2019-08-29 14:08
閱讀 1735·2019-08-29 13:43
閱讀 1472·2019-08-26 12:11