一刷leetcode——数据结构
208. Implement Trie (Prefix Tree)
题意:构造Trie树的插入、查找操作
我的思路:字典树模板
我的代码:
class Trie { public: vector<vector<int> > ch; vector<int> val; /** Initialize your data structure here. */ Trie() { vector<int> root(26, 0); ch.push_back(root); val.push_back(0); } int idx(char c) { return c-'a'; } /** Inserts a word into the trie. */ void insert(string word) { int u = 0, n = word.size(), c; for (int i = 0; i < n; i++) { c = idx(word[i]); if (!ch[u][c]) { vector<int> tmp(26, 0); ch[u][c] = ch.size(); ch.push_back(tmp); val.push_back(0); } u = ch[u][c]; } val[u] = 1; } /** Returns if the word is in the trie. */ bool search(string word) { int u = 0, n = word.size(), c; for (int i = 0; i < n; i++) { c = idx(word[i]); if (!ch[u][c]) return 0; u = ch[u][c]; } return val[u] > 0; } /** Returns if there is any word in the trie that starts with the given prefix. */ bool startsWith(string prefix) { int u = 0, n = prefix.size(); for (int i = 0; i < n; i++) { int c = idx(prefix[i]); if (!ch[u][c]) return 0; u = ch[u][c]; } return 1; } }; /** * Your Trie object will be instantiated and called as such: * Trie obj = new Trie(); * obj.insert(word); * bool param_2 = obj.search(word); * bool param_3 = obj.startsWith(prefix); */
211. Add and Search Word - Data structure design
题意:add函数插入单词形成词典,search函数查询有没有某单词,查询时“.”可以代表任何一个字母
我的思路:字典树+递归
我的代码:数组写法
class WordDictionary { public: /** Initialize your data structure here. */ int ch[40000][26], sz, val[40000]; WordDictionary() { sz = 1; memset(ch[0], 0, sizeof(ch[0])); } /** Adds a word into the data structure. */ void addWord(string word) { int u = 0, n = word.size(); for (int i = 0; i < n; i++) { int c = word[i]-'a'; if (!ch[u][c]) { memset(ch[sz], 0, sizeof(ch[sz])); val[sz] = 0; ch[u][c] = sz++; } u = ch[u][c]; } val[u] = 1; } /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */ bool query(int j, string word) { int n = word.size(); for (int i = 0; i < n; i++) { if (word[i] != '.') { j = ch[j][word[i]-'a']; if (j == 0) return 0; } else { int flag = 1, k; for (k = 0; k < 26; k++) { if (ch[j][k]) { flag = 0; if (query(ch[j][k], word.substr(i+1, n-1-i))) return 1; } } if (flag || k == 26) return 0; } } if (val[j] == 1) return 1; return 0; } bool search(string word) { return query(0, word); } };
solution解法:字典树指针写法
class TrieNode { public: bool isKey; TrieNode* children[26]; TrieNode(): isKey(false) { memset(children, NULL, sizeof(TrieNode*) * 26); } }; void addWord(string word) { TrieNode* run = root; for (char c : word) { if (!(run -> children[c - 'a'])) run -> children[c - 'a'] = new TrieNode(); run = run -> children[c - 'a']; } run -> isKey = true; } private: TrieNode* root; WordDictionary() { root = new TrieNode(); } class TrieNode { public: bool isKey; TrieNode* children[26]; TrieNode(): isKey(false) { memset(children, NULL, sizeof(TrieNode*) * 26); } }; class WordDictionary { public: WordDictionary() { root = new TrieNode(); } // Adds a word into the data structure. void addWord(string word) { TrieNode* run = root; for (char c : word) { if (!(run -> children[c - 'a'])) run -> children[c - 'a'] = new TrieNode(); run = run -> children[c - 'a']; } run -> isKey = true; } // Returns if the word is in the data structure. A word could // contain the dot character '.' to represent any one letter. bool search(string word) { return query(word.c_str(), root); } private: TrieNode* root; bool query(const char* word, TrieNode* node) { TrieNode* run = node; for (int i = 0; word[i]; i++) { if (run && word[i] != '.') run = run -> children[word[i] - 'a']; else if (run && word[i] == '.') { TrieNode* tmp = run; for (int j = 0; j < 26; j++) { run = tmp -> children[j]; if (query(word + i + 1, run)) return true; } } else break; } return run && run -> isKey; } };
212. Word Search II
题意:给定一个字符棋盘和一个字典,输出棋盘上相邻字符连成的存在于字典中的单词
我的思路:Trie+dfs
我的代码:
class Solution { public: vector<vector<int> > ch; vector<int> val; vector<string> ans; int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; int idx(char c) { return c-'a'; } void insert(string word) { int u = 0, n = word.size(), c; for (int i = 0; i < n; i++) { c = idx(word[i]); if (!ch[u][c]) { vector<int> tmp(26, 0); ch[u][c] = ch.size(); ch.push_back(tmp); val.push_back(0); } u = ch[u][c]; } val[u] = 1; } void dfs(vector<vector<char>>& board, int x, int y, int u, string tmp, vector<vector<bool>> flag) { flag[x][y] = 1; if (val[u] > 0 && find(ans.begin(), ans.end(), tmp) == ans.end()) ans.push_back(tmp); for (int i = 0; i < 4; i++) { int xx = x+dir[i][0], yy = y+dir[i][1]; if (xx >= 0 && xx < board.size() && yy >= 0 && yy < board[0].size() && flag[xx][yy] == 0 && ch[u][board[xx][yy]-'a']) dfs(board, xx, yy, ch[u][board[xx][yy]-'a'], tmp+board[xx][yy], flag); } } vector<string> findWords(vector<vector<char>>& board, vector<string>& words) { int m = board.size(), n = board[0].size(); vector<int> root(26, 0); ch.push_back(root); val.push_back(0); for (int i = 0; i < words.size(); i++) insert(words[i]); vector<vector<bool> > flag(m, vector<bool>(n, 0)); for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) if (ch[0][board[i][j]-'a']) { string tmp; dfs(board, i, j, ch[0][board[i][j]-'a'], tmp+board[i][j], flag); } return ans; } };
214. Shortest Palindrome
题意:输出给定字符串前边加上最少的字符变成的回文串
我的思路:问题可以转化为求最长的回文前缀长度,因为在前边加上剩下的倒序即可、
最长回文前缀长度:将原字符串翻转以后加在原字符串的后面(中间需要加一个其他字符),前缀与后缀最大相同长度(KMP)即是
我的代码:
class Solution { public: string shortestPalindrome(string s) { if (s.size() == 0) return s; string ss = s, ans = s; reverse(ss.begin(), ss.end()); s = s+'#'+ss; int n = s.size(), i = 0, j = -1, m = ss.size(); vector<int> next(n+1, -1); while (s[i]) { if (j == -1 || s[i] == s[j]) { i++, j++; next[i] = j; } else j = next[j]; } ss = ss.substr(0, m-next[n]); return ss+ans; } };
218. The Skyline Problem
题意:给出一些矩形,求出这些矩形构成的轮廓线,返回轮廓线上每条水平线左边点的坐标集合。
我的思路:线段树区间修改求最大,离散化,最后逐个节点查询高度值,高度改变压入结果
我的代码:
const int maxn = 20005; class Solution { public: unordered_map<int, int> mp, mp_re; struct node { int l, r, mx; //mx既是最大,也充当lazy标记 }p[4*maxn]; void build(int l, int r, int i) { p[i].l = l; p[i].r = r; p[i].mx = 0; if (l == r) return; int mid = (l+r)>>1; build(l, mid, i<<1); build(mid+1, r, i<<1|1); } void insert(int l, int r, int i, int h) { if (p[i].mx >= h) return; if (p[i].l >= l && p[i].r <= r) { p[i].mx = h; return; } if (p[i].mx) { p[i<<1].mx = max(p[i].mx, p[i<<1].mx); p[i<<1|1].mx = max(p[i].mx, p[i<<1|1].mx); p[i].mx = 0; } int mid = (p[i].l + p[i].r)>>1; if(l <= mid) insert(l, r, i<<1, h); if(mid < r) insert(l, r, i<<1|1, h); } void query(vector<pair<int, int>> &ans, int i) { if (p[i].l == p[i].r) { if (!ans.empty() && p[i].mx == ans[ans.size()-1].second) return; ans.push_back(make_pair(mp_re[p[i].l], p[i].mx)); return; } if (p[i].mx) { p[i<<1].mx = max(p[i].mx, p[i<<1].mx); p[i<<1|1].mx = max(p[i].mx, p[i<<1|1].mx); p[i].mx = 0; } query(ans, i<<1); query(ans, i<<1|1); } vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) { vector<int> idx; vector<pair<int, int>> ans; if (buildings.size() == 0) return ans; for (int i = 0; i < buildings.size(); i++) for (int j = 0; j < 2; j++) if (mp.find(buildings[i][j]) == mp.end()) { mp[buildings[i][j]] = 1; idx.push_back(buildings[i][j]); } sort(idx.begin(), idx.end()); for (int i = 0; i < idx.size(); i++) { mp[idx[i]] = i+1; mp_re[i+1] = idx[i]; } build(1, idx.size() ,1); for (int i = 0; i < buildings.size(); i++) insert(mp[buildings[i][0]], mp[buildings[i][1]]-1, 1, buildings[i][2]); query(ans, 1); return ans; } };
solution解法:优先队列,http://blog.csdn.net/u012501459/article/details/47271561
class Solution { public: vector<pair<int, int>> getSkyline(vector<vector<int>>& buildings) { vector<pair<int, int>> ans; int cur = 0, cur_x, cur_h = -1, l = buildings.size(); priority_queue<pair<int, int>> live; //前边是高度,后边是结束点坐标 while (cur < l || !live.empty()) { cur_x = live.empty() ? buildings[cur][0] : live.top().second; //最高建筑结束点 if (cur >= l || buildings[cur][0] > cur_x) while (!live.empty() && (live.top().second <= cur_x)) live.pop(); //将结束时间小于等于最高建筑结束点的建筑物从优先队列中弹出 else { //如果当前遍历到的建筑物在最高的建筑物结束之前开始,那么处理当前的建筑物 cur_x = buildings[cur][0]; while (cur < l && buildings[cur][0] == cur_x) { //所有在同一点开始的建筑 live.push(make_pair(buildings[cur][2], buildings[cur][1])); cur++; } } cur_h = live.empty() ? 0 : live.top().first; if (ans.empty() || ans.back().second != cur_h) ans.push_back(make_pair(cur_x, cur_h)); } return ans; } };
224. Basic Calculator
题意:给定字符串表示有括号加减法,输出结果
我的思路:栈
我的代码:
class Solution { public: int calculate(string s) { s += '.'; stack<int> nums, oper; int num = 0, fuhao = 1, ans = 0; for (int i = 0; i < s.size(); i++) { if (isdigit(s[i])) { num = num*10+s[i]-'0'; } else { if (s[i] == ' ') continue; ans += fuhao*num; num = 0; if (s[i] == '+') fuhao = 1; else if (s[i] == '-') fuhao = -1; else if (s[i] == '(') { nums.push(ans); ans = 0; oper.push(fuhao); fuhao = 1; } else if (s[i] == ')') { ans = ans*oper.top()+nums.top(); nums.pop(); oper.pop(); } } } return ans; } };
225. Implement Stack using Queues
题意:队列实现栈
我的思路:两个队列
我的代码:
class MyStack { public: queue<int> q[2]; int flag; /** Initialize your data structure here. */ MyStack() { flag = 0; ///初始化0进1出 } /** Push element x onto stack. */ void push(int x) { q[flag].push(x); } /** Removes the element on top of the stack and returns that element. */ int pop() { int n = q[flag].size(); for (int i = 0; i < n-1; i++) { q[flag^1].push(q[flag].front()); q[flag].pop(); } int ans = q[flag].front(); q[flag].pop(); flag ^= 1; return ans; } /** Get the top element. */ int top() { int n = q[flag].size(); for (int i = 0; i < n-1; i++) { q[flag^1].push(q[flag].front()); q[flag].pop(); } int ans = q[flag].front(); q[flag^1].push(ans); q[flag].pop(); flag ^= 1; return ans; } /** Returns whether the stack is empty. */ bool empty() { return q[flag].empty(); } };
solution:一个队列就可以。。
class MyStack { public: /** Initialize your data structure here. */ int size; queue<int> q; MyStack() { size = 0; } /** Push element x onto stack. */ void push(int x) { q.push(x); size++; } /** Removes the element on top of the stack and returns that element. */ int pop() { int t = q.back(); while(q.front() != t){ q.push(q.front()); q.pop(); } q.pop(); size--; return t; } /** Get the top element. */ int top() { return q.back(); } /** Returns whether the stack is empty. */ bool empty() { return size == 0; } }; /** * Your MyStack object will be instantiated and called as such: * MyStack obj = new MyStack(); * obj.push(x); * int param_2 = obj.pop(); * int param_3 = obj.top(); * bool param_4 = obj.empty(); */
227. Basic Calculator II
题意:计算器,加减乘除
我的思路:加:原数压栈;减:相反数压栈;乘:取出一个数相乘压栈;除:取出一个数相除压栈,最后栈里数字相加
我的代码:
class Solution { public: int calculate(string s) { s += '.'; stack<int> sk; int num = 0, fuhao = 1, a; for (int i = 0; i < s.size(); i++) { if (isdigit(s[i])) { num = num*10+s[i]-'0'; } else { if (s[i] == ' ') continue; switch (fuhao) { case 1: sk.push(num); break; case 2: sk.push(-num); break; case 3: a = sk.top(); sk.pop(); sk.push(a*num); break; case 4: a = sk.top(); sk.pop(); sk.push(a/num); break; } switch (s[i]) { case '+': fuhao = 1; break; case '-': fuhao = 2; break; case '*': fuhao = 3; break; case '/': fuhao = 4; break; } num = 0; } } int ans = 0; while (!sk.empty()) { ans += sk.top(); sk.pop(); } return ans; } };
232. Implement Queue using Stacks
题意:用队列实现栈
我的sl:水题
我的代码:
class MyQueue { public: stack<int> s; /** Initialize your data structure here. */ MyQueue() { } /** Push element x to the back of queue. */ void push(int x) { s.push(x); } /** Removes the element from in front of queue and returns that element. */ int pop() { int n = s.size(); stack<int> tmp; for (int i = 0; i < n-1; i++) { tmp.push(s.top()); s.pop(); } int ans = s.top(); s.pop(); for (int i = 0; i < n-1; i++) { s.push(tmp.top()); tmp.pop(); } return ans; } /** Get the front element. */ int peek() { int n = s.size(); stack<int> tmp; for (int i = 0; i < n-1; i++) { tmp.push(s.top()); s.pop(); } int ans = s.top(); tmp.push(ans); s.pop(); for (int i = 0; i < n; i++) { s.push(tmp.top()); tmp.pop(); } return ans; } /** Returns whether the queue is empty. */ bool empty() { return s.empty(); } };
solution写法:
class Queue { stack<int> input, output; public: void push(int x) { input.push(x); } void pop(void) { peek(); output.pop(); } int peek(void) { if (output.empty()) while (input.size()) output.push(input.top()), input.pop(); return output.top(); } bool empty(void) { return input.empty() && output.empty(); } };
239. Sliding Window Maximum
题意:输出一个数组给定窗口长度移动的最大值
solution解法:双向队列deque(单调队列)
class Solution { public: vector<int> maxSlidingWindow(vector<int>& nums, int k) { deque<int> dq; vector<int> ans; for (int i = 0; i < nums.size(); i++) { if (!dq.empty() && dq.front() == i-k) dq.pop_front(); while (!dq.empty() && nums[dq.back()] < nums[i]) dq.pop_back(); dq.push_back(i); if (i >= k-1) ans.push_back(nums[dq.front()]); } return ans; } };
257. Binary Tree Paths
题意:以字符串形式输出二叉搜索树的所有路径
我的思路:dfs,to_string
我的代码:
class Solution { public: void dfs(TreeNode* root, vector<string> &ans, string tmp) { if (root->left == NULL && root->right == NULL) { ans.push_back(tmp); return; } if (root->left) dfs(root->left, ans, tmp+"->"+to_string(root->left->val)); if (root->right) dfs(root->right, ans, tmp+"->"+to_string(root->right->val)); } vector<string> binaryTreePaths(TreeNode* root) { vector<string> ans; if (root == NULL) return ans; string tmp; tmp = to_string(root->val); dfs(root, ans, tmp); return ans; } };
九章最优解:
class Solution { public: /** * @param root the root of the binary tree * @return all root-to-leaf paths */ vector<string> binaryTreePaths(TreeNode* root) { // Write your code here vector<string> path; if(root == NULL) return path; vector<vector<int> > pathv; unordered_map<TreeNode*, bool> visited; stack<TreeNode*> stk; stk.push(root); visited[root] = true; if(root->left == NULL && root->right == NULL) save(pathv, stk); while(!stk.empty()) { TreeNode* top = stk.top(); if(top->left && visited[top->left] == false) { stk.push(top->left); visited[top->left] = true; if(top->left->left == NULL && top->left->right == NULL) save(pathv, stk); continue; } if(top->right && visited[top->right] == false) { stk.push(top->right); visited[top->right] = true; if(top->right->left == NULL && top->right->right == NULL) save(pathv, stk); continue; } stk.pop(); } return convert(pathv); } void save(vector<vector<int> >& pathv, stack<TreeNode*> stk) { vector<int> cur; while(!stk.empty()) { TreeNode* top = stk.top(); cur.push_back(top->val); stk.pop(); } reverse(cur.begin(), cur.end()); pathv.push_back(cur); } vector<string> convert(vector<vector<int> >& pathv) { vector<string> path; for(int i = 0; i < pathv.size(); i ++) { string cur; cur += to_string(pathv[i][0]); for(int j = 1; j < pathv[i].size(); j ++) { cur += "->"; cur += to_string(pathv[i][j]); } path.push_back(cur); } return path; } };
307. Range Sum Query - Mutable
题意:区间和查询,点修改
我的思路:线段树
我的代码:繁琐了
class NumArray { public: struct Node { int l, r, sum; }; vector<Node> p; vector<int> num; void build(int l, int r, int i) { p[i].l = l; p[i].r = r; if (l == r) { p[i].sum = num[l]; return; } int mid = (l+r)/2; build(l, mid, i<<1); build(mid+1, r, i<<1|1); p[i].sum = p[i<<1].sum+p[i<<1|1].sum; } NumArray(vector<int> nums) { int n = nums.size(); if (n > 0) { num = nums; p.resize(n<<2); build(0, n-1, 1); } } void upd(int k, int add, int i) { if (p[i].l == p[i].r) { p[i].sum += add; return; } int mid = (p[i].l+p[i].r)>>1; if (k <= mid) upd(k, add, i<<1); else upd(k, add, i<<1|1); p[i].sum = p[i<<1].sum+p[i<<1|1].sum; } void update(int i, int val) { upd(i, val-num[i], 1); num[i] = val; } int query(int l, int r, int i) { if(l == p[i].l && p[i].r == r) return p[i].sum; int mid = (p[i].l+p[i].r)>>1; if (r<=mid) return query(l, r, i<<1); else if (l>mid) return query(l, r, (i<<1)+1); else return query(l, mid, i<<1)+query(mid+1, r, (i<<1)+1); } int sumRange(int i, int j) { return query(i, j, 1); } };
solution解法:树状数组
class NumArray { public: NumArray(vector<int> nums) { int n = nums.size(); this->nums = bit = vector<int>(n + 1); for (int i = 0; i < n; i++) update(i, nums[i]); } void update(int i, int val) { for (int j = i + 1; j < nums.size(); j += j & -j) bit[j] += val - nums[i + 1]; nums[i + 1] = val; } int sumRange(int i, int j) { return sum(j + 1) - sum(i); } private: vector<int> nums, bit; int sum(int i) { int res = 0; for (; i > 0; i -= i & -i) res += bit[i]; return res; } };
331. Verify Preorder Serialization of a Binary Tree
题意:判断一个序列是否可以是一个二叉树的前序遍历
我的思路:连续遇到两个“#”,说明这是叶子节点,删去他们及他们的根节点,用一个’#‘代替,直到最后剩一个’#‘说明是二叉树。否则,返回false。
我的代码:
class Solution { public: bool isValidSerialization(string preorder) { stack<char> s; int num = 0; for (int i = 0; i < preorder.size(); i++) { if (isdigit(preorder[i])) { while (isdigit(preorder[i])) { num = num*10+preorder[i]-'0'; i++; } s.push(num); num = 0; } else if (preorder[i] == '#') { while (!s.empty() && s.top() == '#') { s.pop(); if (!s.empty() && s.top() != '#') s.pop(); else return 0; } s.push(preorder[i]); } } return s.size() == 1 && s.top() == '#'; } };
disscuss解法:通过出度、入度之差计算,如果是二叉树,那么在整个过程中差值为非负且最后为0
public boolean isValidSerialization(String preorder) { String[] nodes = preorder.split(","); int diff = 1; for (String node: nodes) { if (--diff < 0) return false; if (!node.equals("#")) diff += 2; } return diff == 0; }
347. Top K Frequent Elements
题意:给定一个数组,输出数组中出现频率前k位的数字
我的思路:统计各个数字的出现次数,map表示数字与次数数组的映射,优先队列排出前k位
我的代码:
class Solution { public: struct Item { int num, cnt; bool operator < (const Item& a) const { return cnt < a.cnt; } }; vector<int> topKFrequent(vector<int>& nums, int k) { unordered_map <int, int> hash; int n = nums.size(); vector<Item> item; for (int i = 0; i < n; i++) { if (hash.find(nums[i]) != hash.end()) item[hash[nums[i]]].cnt++; else { Item tmp; tmp.num = nums[i]; tmp.cnt = 1; item.push_back(tmp); hash[nums[i]] = item.size()-1; } } priority_queue<Item> pq; vector<int> ans; for (int i = 0; i < item.size(); i++) pq.push(item[i]); while (k--) { Item tmp = pq.top(); pq.pop(); ans.push_back(tmp.num); } return ans; } };
九章最优解:
public class Solution { public List<Integer> topKFrequent(int[] nums, int k) { Map<Integer, Integer> hashmap = new HashMap<Integer, Integer>(); PriorityQueue<Map.Entry<Integer, Integer>> queue = new PriorityQueue<Map.Entry<Integer, Integer>>( new Comparator<Map.Entry<Integer, Integer>>() { public int compare(Map.Entry<Integer, Integer> e1, Map.Entry<Integer, Integer> e2) { return e1.getValue() - e2.getValue(); } }); for (int i = 0; i < nums.length; i++) { if (!hashmap.containsKey(nums[i])) { hashmap.put(nums[i], 1); } else { hashmap.put(nums[i], hashmap.get(nums[i]) + 1); } } for (Map.Entry<Integer, Integer> entry : hashmap.entrySet()) { if (queue.size() < k) { queue.offer(entry); } else if (queue.peek().getValue() < entry.getValue()) { queue.poll(); queue.offer(entry); } } List<Integer> ans = new ArrayList<Integer>(); for (Map.Entry<Integer, Integer> entry : queue) ans.add(entry.getKey()); return ans; } }
352. Data Stream as Disjoint Intervals
题意:将数据流表示成区间形式
我的思路:数据流插入排序,再表示成区间,O(n)
我的代码:
class SummaryRanges { public: vector<int> num; /** Initialize your data structure here. */ SummaryRanges() { } void addNum(int val) { int i = 0; while (i < num.size() && num[i] < val) i++; num.insert(num.begin()+i, val); } vector<Interval> getIntervals() { vector<Interval> ans; int flag = 0, i = 0; Interval tmp; while (i < num.size()) { if (flag) { while (num[i] == num[i-1] || num[i] == num[i-1]+1) i++; tmp.end = num[i-1]; ans.push_back(tmp); flag = 0; } else { tmp.start = num[i++]; flag = 1; } } if (flag) { tmp.end = num[i-1]; ans.push_back(tmp); } return ans; } };
discuss解法:用一个数组来保存结果, 然后每次搜索的时候用lower_bound可以找到第一个大于等于要插入的值的区间, 当前要插入的值可能会正好等于上个区间的end+1, 因此需要做个判断. 把能合并的区间都从数组中删除, 最后插入一个新的区间.set二叉搜索树插入查找都可以在O(log n)完成, 只需要在返回结果的时候将set中的值放到vector中即可.
class SummaryRanges { public: /** Initialize your data structure here. */ void addNum(int val) { auto it = st.lower_bound(Interval(val, val)); int start = val, end = val; if(it != st.begin() && (--it)->end+1 < val) it++; while(it != st.end() && val+1 >= it->start && val-1 <= it->end) { start = min(start, it->start); end = max(end, it->end); it = st.erase(it); } st.insert(it,Interval(start, end)); } vector<Interval> getIntervals() { vector<Interval> result; for(auto val: st) result.push_back(val); return result; } private: struct Cmp{ bool operator()(Interval a, Interval b){ return a.start < b.start; } }; set<Interval, Cmp> st; };
378. Kth Smallest Element in a Sorted Matrix
题意:输出一个矩阵中第k小的数
我的思路:优先队列
我的代码:
class Solution { public: int kthSmallest(vector<vector<int>>& matrix, int k) { priority_queue<int> pq; for (int i = 0; i < matrix.size(); i++) for (int j = 0; j < matrix[0].size(); j++) pq.push(matrix[i][j]); k = matrix.size()*matrix[0].size()+1-k; while (k > 1) pq.pop(), k--; return pq.top(); } };
九章最优解:无
404. Sum of Left Leaves
题意:求所有左叶子节点之和
我的思路:递归
class Solution { public: int ans; void dfs(TreeNode* root, bool flag) { if (root->left == NULL && root->right == NULL && flag) ans += root->val; if (root->left) dfs(root->left, 1); if (root->right) dfs(root->right, 0); } int sumOfLeftLeaves(TreeNode* root) { if (root) dfs(root, 0); return ans; } };
solution解法:也是递归,但是写的好一些
class Solution { public: int sumOfLeftLeaves(TreeNode* root) { if(!root) return 0; if(root->left && !root->left->left && !root->left->right) return root->left->val + sumOfLeftLeaves(root->right); return sumOfLeftLeaves(root->left) + sumOfLeftLeaves(root->right); } };
407. Trapping Rain Water II
题意:给定一个二维矩阵,数值表示高度,求存水量
我的思路:优先队列,先将边缘入列,从高度小的开始取,bfs将它周围还没到过的地方入列,ans += max(0, tmp.h-heightMap[x][y]);
我的代码:
class Solution { public: vector<vector<int>> dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; struct cell { int r, c, h; cell(int i, int j, int k) { r = i; c = j; h = k; } bool operator < (const cell& a) const { return h > a.h; } }; int trapRainWater(vector<vector<int>>& heightMap) { if (heightMap.size() == 0) return 0; priority_queue<cell> pq; int m = heightMap.size(), n = heightMap[0].size(); vector<vector<bool>> v(m, vector<bool>(n, 0)); for (int i = 0 ; i< m; i++) { cell tmp1(i, 0, heightMap[i][0]), tmp2(i, n-1, heightMap[i][n-1]); pq.push(tmp1); pq.push(tmp2); v[i][0] = 1; v[i][n-1] = 1; } for (int i = 1; i < n-1; i++) { cell tmp1(0, i, heightMap[0][i]), tmp2(m-1, i, heightMap[m-1][i]); pq.push(tmp1); pq.push(tmp2); v[0][i] = 1; v[m-1][i] = 1; } int ans = 0; while (!pq.empty()) { cell tmp = pq.top(); pq.pop(); for (int i = 0; i < 4; i++) { int x = tmp.r+dir[i][0], y = tmp.c+dir[i][1]; if (x >= 0 && x < m && y >= 0 && y < n && !v[x][y]) { v[x][y] = 1; cell g(x, y, max(heightMap[x][y], tmp.h)); pq.push(g); ans += max(0, tmp.h-heightMap[x][y]); } } } return ans; } };
451. Sort Characters By Frequency
题意:将数组中的字符按频率由大到小输出
我的思路:hash+优先队列
我的代码:
class Solution { public: struct Item { int cnt = 0; char c; bool operator < (const Item& a) const { return cnt < a.cnt; } }; string frequencySort(string s) { priority_queue<Item> pq; vector<Item> hehe(128); string ans; for (int i = 0; i < s.size(); i++) { hehe[s[i]].c = s[i]; hehe[s[i]].cnt++; } for (int i = 0; i < 128; i++) pq.push(hehe[i]); while (pq.top().cnt > 0) { Item a = pq.top(); while (a.cnt--) ans += a.c; pq.pop(); } return ans; } };
solution解法:思路一样的,写的好一点
class Solution { public: string frequencySort(string s) { string ret; vector<int> cnt(256, 0); for (auto& ch : s) { cnt[ch]++; } priority_queue<pair<int, int>> pq; for (int i = 0; i < cnt.size(); i++) { if (cnt[i] != 0) { pq.push({cnt[i], i}); } } while (!pq.empty()) { ret += string(pq.top().first, pq.top().second); pq.pop(); } return ret; } };
493. Reverse Pairs
题意:找出数组中i < j
and nums[i] > 2*nums[j]的对数
我的思路:
1)归并排序
class Solution { public: void merge(vector<int>& nums, int l, int m, int r, int& ans) { vector<int> tmp; int i = l, j = m+1, p = m+1; while (i <= m) { while (p <= r && nums[i] > 2L*nums[p]) p++; ans += p-m-1; while (j <= r && nums[i] >= nums[j]) tmp.push_back(nums[j++]); tmp.push_back(nums[i++]); } while (j <= r) tmp.push_back(nums[j++]); for(i = l; i <= r; i++) nums[i] = tmp[i-l]; } void mergesort(vector<int>& nums, int l, int r, int& ans) { if (l < r) { int mid = l+(r-l)/2; mergesort(nums, l, mid, ans); mergesort(nums, mid+1, r, ans); merge(nums, l, mid, r, ans); } } int reversePairs(vector<int>& nums) { int ans = 0; mergesort(nums, 0, nums.size()-1, ans); return ans; } };
496. Next Greater Element I
题意:数组1是数组2的子集,找出1中的元素在2中的位置以后比他大的第一个数
我的思路:map记录数字在1中的位置,栈找2的上升沿
我的代码:
class Solution { public: vector<int> nextGreaterElement(vector<int>& findNums, vector<int>& nums) { vector<int> ans(findNums.size(), -1); unordered_map<int, int> m; stack<int> s; for (int i = 0; i < findNums.size(); i++) m[findNums[i]] = i; for (int i = 0; i < nums.size(); i++) { while (!s.empty() && s.top() < nums[i]) { if (m.find(s.top()) != m.end()) ans[m[s.top()]] = nums[i]; s.pop(); } s.push(nums[i]); } return ans; } };
547. Friend Circles
题意:给定同学间的认识关系,问有多少个小团体
我的思路:并查集
我的代码:
class Solution { public: int find(int x, vector<int> &pre) { int cur = x, tmp; while (pre[x] != x) x = pre[x]; while (cur != x) { tmp = pre[cur]; pre[cur] = x; cur = tmp; } return x; } void get(int x, int y, vector<int> &pre) { int fx = find(x, pre), fy = find(y, pre); if (fx != fy) pre[fy] = fx; } int findCircleNum(vector<vector<int>>& M) { int n = M.size(), sum = 0; vector<int> pre(n), flag(n, 0); for (int i = 0; i < n; i++) pre[i] = i; for (int i = 0; i < n; i++) for (int j = i+1; j < n; j++) if (M[i][j]) get(i, j, pre); for (int i = 0; i < n; i++) { int k = find(i, pre); if (flag[k] == 0) { sum++; flag[k] = 1; } } return sum; } };
632. Smallest Range
题意:给定k个有序数组,找出最小的区间使得每个数组在此区间里都有数字
我的思路:优先队列,类似于将k个有序数组合并,每次弹出最小的数字后,加入他所在的数组的下一个数字,维护最小的区间
我的代码:
class Solution { public: struct Item { int val, i, j; bool operator < (const Item& a) const { return val > a.val; } }; vector<int> smallestRange(vector<vector<int>>& nums) { priority_queue<Item> pq; int maxn = 0x80000000, range = 0x7fffffff, s, e; for (int i = 0; i < nums.size(); i++) { Item item; maxn = max(maxn, nums[i][0]); item.val = nums[i][0]; item.i = i; item.j = 0; pq.push(item); } while (1) { Item tmp = pq.top(); pq.pop(); if (maxn-tmp.val < range) { range = maxn-tmp.val; s = tmp.val; e = maxn; } if (tmp.j < nums[tmp.i].size()-1) { Item item; maxn = max(maxn, nums[tmp.i][tmp.j+1]); item.val = nums[tmp.i][tmp.j+1]; item.i = tmp.i; item.j = tmp.j+1; pq.push(item); } else break; } return {s, e}; } };
648. Replace Words
题意:将句子中的单词用他的前缀代替,前缀给定
我的思路:字典树
我的代码:
class Solution { public: class Trie { public: vector<vector<int> > ch; vector<int> val; Trie() { vector<int> root(26, 0); ch.push_back(root); val.push_back(0); } int idx(char c) { return c-'a'; } void insert(string word) { int u = 0, n = word.size(), c; for (int i = 0; i < n; i++) { c = idx(word[i]); if (!ch[u][c]) { vector<int> tmp(26, 0); ch[u][c] = ch.size(); ch.push_back(tmp); val.push_back(0); } u = ch[u][c]; } val[u] = 1; } string search(string word) { int u = 0, n = word.size(), c; string tmp; for (int i = 0; i < n; i++) { c = idx(word[i]); tmp += word[i]; if (!ch[u][c]) return word; u = ch[u][c]; if (val[u] > 0) return tmp; } return word; } }; string replaceWords(vector<string>& dict, string sentence) { Trie T; for (int i = 0; i < dict.size(); i++) T.insert(dict[i]); string ans; int i = 0, j = 0; while (j < sentence.length()) { if (sentence[j] == ' ') { ans = ans+T.search(sentence.substr(i, j-i))+' '; i = j+1; } j++; } ans = ans+T.search(sentence.substr(i, j-i)); return ans; } };
684. Redundant Connection
题意:找出无向图中的唯一一条 重边
我的思路:并查集
我的代码:
class Solution { public: int find(int x, vector<int>& pre) { int root=x; while(pre[root]!=root) root=pre[root]; return root; } vector<int> findRedundantConnection(vector<vector<int>>& edges) { int n = edges.size(); vector<int> pre(n+1); for (int i = 0; i <= n; i++) pre[i] = i; for (int i = 0; i < n; i++) { int x = find(edges[i][0], pre), y = find(edges[i][1], pre); if (x == y) return edges[i]; pre[x] = y; } } };