楼主: zhuli19901106
跳转到指定楼层
上一主题 下一主题
收起左侧

分享我的Lintcode题解,目前进度244/248

 
🔗
 楼主| zhuli19901106 2015-7-22 02:00:00 | 只看该作者
全局:
Word Ladder
题意:给定一个词典,其中所有的单词都等长。给你两个同样长的单词作为起点和终点,要求在每次只改变一个字母的情况下,从起点变到终点。还要求每次变化的单词都必须在词典中。求起点到终点的最短距离。
解法:既然每次允许变一个字母,那么就等同于”相邻单词的距离都为1“,于是求最短距离自然要用BFS了。这题我写过好几版代码,都是同一思路。这个是写的比较简洁的一个。
代码:
  1. // Solution using BFS
  2. #include <algorithm>
  3. #include <queue>
  4. #include <unordered_map>
  5. using namespace std;

  6. typedef unordered_set<string> uss;
  7. class Solution {
  8. public:
  9.     /**
  10.       * @param start, a string
  11.       * @param end, a string
  12.       * @param dict, a set of string
  13.       * @return an integer
  14.       */
  15.     int ladderLength(string start, string end, uss &dict) {
  16.         if (start == end) {
  17.             return 0;
  18.         }
  19.         
  20.         dict.insert(start);
  21.         dict.insert(end);
  22.         
  23.         queue<string> q;
  24.         unordered_map<string, int> um;
  25.         
  26.         string p;
  27.         char ch;
  28.         int i, j, len = start.length();
  29.         int cc;
  30.         
  31.         um[start] = 1;
  32.         q.push(start);
  33.         while (um.find(end) == um.end() && !q.empty()) {
  34.             p = q.front();
  35.             cc = um[p];
  36.             q.pop();
  37.             for (i = 0; i < len; ++i) {
  38.                 ch = p[i];
  39.                 for (j = 0; j < 26; ++j) {
  40.                     if (ch == 'a' + j) {
  41.                         continue;
  42.                     }
  43.                     p[i] = 'a' + j;
  44.                     if (dict.find(p) == dict.end()) {
  45.                         // Not in dict
  46.                         continue;
  47.                     }
  48.                     if (um.find(p) != um.end()) {
  49.                         // Already visited
  50.                         continue;
  51.                     }
  52.                     um[p] = cc + 1;
  53.                     q.push(p);
  54.                 }
  55.                 p[i] = ch;
  56.             }
  57.         }
  58.         return um[end];
  59.     }
  60. };
复制代码
复杂度:时间是O(26 ^ LD),其中LD是起点和终点的最短编辑距离。空间是O(DS),DS是词典中的单词数。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-22 02:01:41 | 只看该作者
全局:
又被审核吞掉一题:Word Ladder。
可恶~我说什么值得审核的了?有本事来审我全家~
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-22 02:06:42 | 只看该作者
全局:
你们机器审核用的是不是用敏感词表+正则匹配?把模式改改吧,被误杀很不爽的有木有!
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-22 02:13:46 | 只看该作者
全局:
Word Ladder II
题意:hard难度。跟Word Ladder一样,不过这次要求出所有长度最短的路径。
解法:因为要求的是具体的路径,于是题目复杂多了。按照BFS一对多的形式,我们要求出路径,只能记录每个单词在路径中的前一个单词,也就是前驱节点。这样可以逐个向前回溯出一条路径来。首先要做的还是BFS,不过为了保存路径,我们还需要利用backtrace数组保存每个搜到单词的前一个单词。搜索过程中需要不断地从字典中删掉单词,这个是保证算法效率的关键。
代码:
  1. #include <algorithm>
  2. #include <unordered_map>
  3. using namespace std;

  4. class Solution {
  5. public:
  6.     /**
  7.       * @param start, a string
  8.       * @param end, a string
  9.       * @param dict, a set of string
  10.       * @return a list of lists of string
  11.       */
  12.     vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {
  13.         ans.clear();
  14.         bt.clear();
  15.         
  16.         dict.insert(start);
  17.         dict.insert(end);
  18.         
  19.         vector<vector<string> > a(2);
  20.         string s1, s2;
  21.         int f, nf;
  22.         a[0].push_back(start);
  23.         f = 1;
  24.         nf = !f;
  25.         
  26.         int i, j, k, n, len;
  27.         char ch;
  28.         while (true) {
  29.             a[f].clear();
  30.             n = a[nf].size();
  31.             for (i = 0; i < n; ++i) {
  32.                 dict.erase(a[nf][i]);
  33.             }
  34.             for (i = 0; i < n; ++i) {
  35.                 s1 = s2 = a[nf][i];
  36.                 len = s1.length();
  37.                 for (j = 0; j < len; ++j) {
  38.                     ch = s1[j];
  39.                     for (k = 0; k < 26; ++k) {
  40.                         if (ch == 'a' + k) {
  41.                             continue;
  42.                         }
  43.                         s1[j] = 'a' + k;
  44.                         if (dict.find(s1) == dict.end()) {
  45.                             continue;
  46.                         }
  47.                         a[f].push_back(s1);
  48.                         bt[s1].insert(s2);
  49.                     }
  50.                     s1[j] = ch;
  51.                 }
  52.             }
  53.             if (a[f].empty() || bt.find(end) != bt.end()) {
  54.                 break;
  55.             }
  56.             f = !f;
  57.             nf = !f;
  58.         }
  59.         if (bt.find(end) == bt.end()) {
  60.             return ans;
  61.         }
  62.         res.clear();
  63.         backTrace(end);
  64.         return ans;
  65.     }
  66. private:
  67.     vector<vector<string> > ans;
  68.     unordered_map<string, unordered_set<string> > bt;
  69.     vector<string> res;
  70.    
  71.     void backTrace(string s) {
  72.         if (bt.find(s) == bt.end()) {
  73.             // End of back trac
  74.             vector<string> r(res);
  75.             r.push_back(s);
  76.             reverse(r.begin(), r.end());
  77.             ans.push_back(r);
  78.             return;
  79.         }
  80.         unordered_set<string> &v = bt[s];
  81.         res.push_back(s);
  82.         for (auto it = v.begin(); it != v.end(); ++it) {
  83.             backTrace(*it);
  84.         }
  85.         res.pop_back();
  86.     }
  87. };
复制代码
复杂度:跟Word Ladder一样。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-22 02:14:45 | 只看该作者
全局:
本帖最后由 zhuli19901106 于 2015-7-22 02:33 编辑

敏感词测试开始
周永康
令计划
闷声发大财
作大死
陈光诚
送温暖
查水表
修炼
圆满
审核si全家
大法好
Big Brother is watching you.
网络审查
审你妹审个锤子
审个毛线
screw you
防民之口甚于防川
falungong
法轮功
敏感词测试结束

这你都不审,跑去审我的题解,你几个意思?
你敏感词表里存的是运算符跟C语言关键字吧?发个代码你倒要审核了,审核系统怎么做的?
吐槽完毕





回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-22 02:46:19 | 只看该作者
全局:
Largest Rectangle in Histogram
题意:hard难度。给定一个直方图,如果每一条的宽度是1,求直方图覆盖的区域中,能画出的和坐标轴对齐的最大矩形的面积。
解法:对于每个位置,比如第i位的高度为A{i},我们关心的是向左向右能找到多少个连续的位置,这些位置的高度都不低于A{i}。剩下的请参见下面代码。这种算法的思路,其实和并查集的路径压缩有点像,效率自然也很高。这题还有使用栈的一种解法,时间空间都是相同数量级的,而且感觉比较难懂,所以我就没去深究了。
代码:
  1. #include <algorithm>
  2. using namespace std;

  3. class Solution {
  4. public:
  5.     /**
  6.      * @param height: A list of integer
  7.      * @return: The area of largest rectangle in the histogram
  8.      */
  9.     int largestRectangleArea(vector<int> &height) {
  10.         vector<int> &a = height;
  11.         int n = a.size();
  12.         if (n == 0) {
  13.             return 0;
  14.         }
  15.         vector<int> dl(n), dr(n);
  16.         int i;
  17.         dl[0] = 0;
  18.         for (i = 1; i <= n - 1; ++i) {
  19.             dl[i] = i;
  20.             while (dl[i] - 1 >= 0 && a[dl[i] - 1] >= a[i]) {
  21.                 dl[i] = dl[dl[i] - 1];
  22.             }
  23.         }
  24.         dr[n - 1] = n - 1;
  25.         for (i = n - 2; i >= 0; --i) {
  26.             dr[i] = i;
  27.             while (dr[i] + 1 <= n - 1 && a[dr[i] + 1] >= a[i]) {
  28.                 dr[i] = dr[dr[i] + 1];
  29.             }
  30.         }
  31.         int ans = 0;
  32.         for (i = 0; i < n; ++i) {
  33.             ans = max(ans, a[i] * (dr[i] - dl[i] + 1));
  34.         }
  35.         return ans;
  36.     }
  37. };
复制代码
复杂度:时间O(N),空间O(N)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-22 03:03:06 | 只看该作者
全局:
Word Search
题意:给定一个字符矩阵A,和一个单词W。允许你从矩阵任意位置出发,上下左右移动。看能不能找到轨迹为W的路径。
解法:快使用DFS。
代码:
  1. class Solution {
  2. public:
  3.     Solution() {
  4.         d.resize(4, vector<int>(2));
  5.         d[0][0] = -1;
  6.         d[0][1] = 0;
  7.         d[1][0] = +1;
  8.         d[1][1] = 0;
  9.         d[2][0] = 0;
  10.         d[2][1] = -1;
  11.         d[3][0] = 0;
  12.         d[3][1] = +1;
  13.     }
  14.     /**
  15.      * @param board: A list of lists of character
  16.      * @param word: A string
  17.      * @return: A boolean
  18.      */
  19.     bool exist(vector<vector<char> > &board, string word) {
  20.         n = board.size();
  21.         if (n == 0) {
  22.             return false;
  23.         }
  24.         m = board[0].size();
  25.         if (m == 0) {
  26.             return false;
  27.         }
  28.         target = word;
  29.         if (target == "") {
  30.             return true;
  31.         }
  32.         b.clear();
  33.         b.resize(n, vector<int>(m, false));
  34.         ans = false;
  35.         
  36.         int i, j;
  37.         for (i = 0; !ans && i < n; ++i) {
  38.             for (j = 0; !ans && j < m; ++j) {
  39.                 if (board[i][j] != target[0]) {
  40.                     continue;
  41.                 }
  42.                 b[i][j] = true;
  43.                 DFS(i, j, board, 1);
  44.                 b[i][j] = false;
  45.             }
  46.         }
  47.         return ans;
  48.     }
  49. private:
  50.     int n, m;
  51.     string target;
  52.     vector<vector<int> > b;
  53.     vector<vector<int> > d;
  54.     bool ans;
  55.    
  56.     bool inbound(int x, int y) {
  57.         return x >= 0 && x <= n - 1 && y >= 0 && y <= m - 1;
  58.     }
  59.    
  60.     void DFS(int x, int y, vector<vector<char> > &board, int len) {
  61.         if (ans) {
  62.             return;
  63.         }
  64.         if (len == target.length()) {
  65.             ans = true;
  66.             return;
  67.         }
  68.         int i;
  69.         int xx, yy;
  70.         for (i = 0; i < 4; ++i) {
  71.             xx = x + d[i][0];
  72.             yy = y + d[i][1];
  73.             if (!inbound(xx, yy)) {
  74.                 continue;
  75.             }
  76.             if (b[xx][yy]) {
  77.                 continue;
  78.             }
  79.             if (board[xx][yy] != target[len]) {
  80.                 continue;
  81.             }
  82.             b[xx][yy] = true;
  83.             DFS(xx, yy, board, len + 1);
  84.             b[xx][yy] = false;
  85.         }
  86.     }
  87. };
复制代码
复杂度:时间O((N * M)!),空间一样。

补充内容 (2015-7-23 15:10):
更正:复杂度:时间O(4 ^ (N * M)),空间一样。只是理论复杂度很高,实际当然没这么高。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-22 03:11:13 | 只看该作者
全局:
Longest Consecutive Sequence
题意:给定一个无序数组,求其中能够组成的最长连续序列。比如[100, 4, 200, 1, 3, 2]的最长连续序列是[1, 2, 3, 4],返回最大长度。
解法:又是哈希表的妙用。我们可以把各个元素看成一个个独立的段。只要是连续的,就可以进行合并。合并完了之后就变成了[100->1, 1->4, 200->1],所以最大长度就是4了。
代码:
  1. // O(n) time and space
  2. #include <algorithm>
  3. #include <unordered_map>
  4. using namespace std;

  5. class Solution {
  6. public:
  7.     /**
  8.      * @param nums: A list of integers
  9.      * @return an integer
  10.      */
  11.     int longestConsecutive(vector<int> &num) {
  12.         vector<int> &a = num;
  13.         unordered_map<int, int> um;
  14.         int n = a.size();
  15.         int i;
  16.         for (i = 0; i < n; ++i) {
  17.             um[a[i]] = 1;
  18.         }
  19.         unordered_map<int, int>::iterator it1, it2;
  20.         it1 = um.begin();
  21.         while (it1 != um.end()) {
  22.             while (true) {
  23.                 i = it1->first + it1->second;
  24.                 it2 = um.find(i);
  25.                 if (it2 == um.end()) {
  26.                     break;
  27.                 }
  28.                 it1->second += it2->second;
  29.                 um.erase(it2);
  30.             }
  31.             ++it1;
  32.         }
  33.         int ans = 0;
  34.         for (it1 = um.begin(); it1 != um.end(); ++it1) {
  35.             ans = max(ans, it1->second);
  36.         }
  37.         return ans;
  38.     }
  39. };
复制代码
复杂度:时间O(N),空间O(N)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-22 03:15:45 | 只看该作者
全局:
Backpack II
题意:典型的背包问题,给定N件物品和M容量,求可获得的最大价值。
解法:DP。
代码:
  1. // O(n * m) time, O(m) space
  2. #include <algorithm>
  3. using namespace std;

  4. class Solution {
  5. public:
  6.     /**
  7.      * @param m: An integer m denotes the size of a backpack
  8.      * @param A & V: Given n items with size A[i] and value V[i]
  9.      * @return: The maximum value
  10.      */
  11.     int backPackII(int m, vector<int> A, vector<int> V) {
  12.         vector<int> dp;
  13.         int n = A.size();
  14.         int i, j;
  15.         
  16.         dp.resize(m + 1, -1);
  17.         dp[0] = 0;
  18.         for (i = 0; i < n; ++i) {
  19.             for (j = m; j >= A[i]; --j) {
  20.                 if (dp[j - A[i]] < 0) {
  21.                     continue;
  22.                 }
  23.                 dp[j] = max(dp[j], dp[j - A[i]] + V[i]);
  24.             }
  25.         }
  26.         int ans = 0;
  27.         for (i = m; i >= 0; --i) {
  28.             ans = max(ans, dp[i]);
  29.         }
  30.         return ans;
  31.     }
  32. };
复制代码
实现:时间O(N * M),空间O(M)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-22 03:29:32 | 只看该作者
全局:
Max Tree
题意:Cartesian tree
解法1:首先,构造笛卡尔树的关键是找到最大点。那么就在“找到最大”上面想办法。于是想到了RMQ问题的稀疏表解法,因为数组的内容是不会变的。
代码1:
  1. // O(log ^ 2(n)) solution, using RMQ
  2. /**
  3. * Definition of TreeNode:
  4. * class TreeNode {
  5. * public:
  6. *     int val;
  7. *     TreeNode *left, *right;
  8. *     TreeNode(int val) {
  9. *         this->val = val;
  10. *         this->left = this->right = NULL;
  11. *     }
  12. * }
  13. */
  14. class Solution {
  15. public:
  16.     /**
  17.      * @param A: Given an integer array with no duplicates.
  18.      * @return: The root of max tree.
  19.      */
  20.     TreeNode* maxTree(vector<int> A) {
  21.         int n = A.size();
  22.         if (n == 0) {
  23.             return NULL;
  24.         }
  25.         
  26.         st.clear();
  27.         calcSparseTable(A);
  28.         
  29.         return maxTreeRecur(A, 0, A.size() - 1);
  30.     }
  31. private:
  32.     // Needed for RMQ
  33.     vector<vector<int> > st;
  34.    
  35.     TreeNode *maxTreeRecur(vector<int> &a, int ll, int rr) {
  36.         if (ll > rr) {
  37.             return NULL;
  38.         }
  39.         int i, mi;
  40.         
  41.         mi = RMQ(a, ll, rr);
  42.         TreeNode *root = new TreeNode(a[mi]);
  43.         root->left = maxTreeRecur(a, ll, mi - 1);
  44.         root->right = maxTreeRecur(a, mi + 1, rr);
  45.         return root;
  46.     }
  47.    
  48.     void calcSparseTable(vector<int> &a) {
  49.         int n = a.size();
  50.         int b = 1;
  51.         int m = 1;
  52.         while (b << 1 <= n) {
  53.             b <<= 1;
  54.             ++m;
  55.         }
  56.         st.resize(m, vector<int>(n));
  57.         int i;
  58.         for (i = 0; i < n; ++i) {
  59.             st[0][i] = i;
  60.         }
  61.         b = 1;
  62.         int j;
  63.         for (i = 1; i < m; ++i) {
  64.             for (j = 0; j + (b << 1) <= n; ++j) {
  65.                 if (a[st[i - 1][j]] > a[st[i - 1][j + b]]) {
  66.                     st[i][j] = st[i - 1][j];
  67.                 } else {
  68.                     st[i][j] = st[i - 1][j + b];
  69.                 }
  70.             }
  71.             b <<= 1;
  72.         }
  73.     }
  74.    
  75.     int RMQ(vector<int> &a, int ll, int rr) {
  76.         int b = 1;
  77.         int i = 0;
  78.         while (b << 1 <= rr - ll + 1) {
  79.             b <<= 1;
  80.             ++i;
  81.         }
  82.         if (a[st[i][ll]] > a[st[i][rr - b + 1]]) {
  83.             return st[i][ll];
  84.         } else {
  85.             return st[i][rr - b + 1];
  86.         }
  87.     }
  88. };
复制代码
复杂度1:平均时间O(log^2(N)),最坏时间O(N * log(N))。空间O(N * log(N))。

解法2:这种解法我没独立想出来,参考了github其他人上的代码。思路一两句话说不清楚,利用了单调栈。感觉得多看几遍代码才能理解,很巧妙。
代码2:
  1. // Cartesian Tree, make it O(n)
  2. /**
  3. * Definition of TreeNode:
  4. * class TreeNode {
  5. * public:
  6. *     int val;
  7. *     TreeNode *left, *right;
  8. *     TreeNode(int val) {
  9. *         this->val = val;
  10. *         this->left = this->right = NULL;
  11. *     }
  12. * }
  13. */
  14. class Solution {
  15. public:
  16.     /**
  17.      * @param A: Given an integer array with no duplicates.
  18.      * @return: The root of max tree.
  19.      */
  20.     TreeNode* maxTree(vector<int> A) {
  21.         int n = A.size();
  22.         if (n == 0) {
  23.             return NULL;
  24.         }
  25.         stack<TreeNode *> st;
  26.         TreeNode *p, *p1, *p2;
  27.         int i;
  28.         for (i = 0; i < n; ++i) {
  29.             p = new TreeNode(A[i]);
  30.             if (!st.empty() && A[i] > st.top()->val) {
  31.                 p1 = st.top();
  32.                 st.pop();
  33.                 while (!st.empty() && A[i] > st.top()->val) {
  34.                     p2 = st.top();
  35.                     st.pop();
  36.                     p2->right = p1;
  37.                     p1 = p2;
  38.                 }
  39.                 p->left = p1;
  40.             }
  41.             st.push(p);
  42.         }
  43.         
  44.         TreeNode *r = st.top();
  45.         st.pop();
  46.         while (!st.empty()) {
  47.             st.top()->right = r;
  48.             r = st.top();
  49.             st.pop();
  50.         }
  51.         return r;
  52.     }
  53. };
复制代码
复杂度2:时间O(N),空间O(N)。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册账号
隐私提醒:
  • ☑ 禁止发布广告,拉群,贴个人联系方式:找人请去🔗同学同事飞友,拉群请去🔗拉群结伴,广告请去🔗跳蚤市场,和 🔗租房广告|找室友
  • ☑ 论坛内容在发帖 30 分钟内可以编辑,过后则不能删帖。为防止被骚扰甚至人肉,不要公开留微信等联系方式,如有需求请以论坛私信方式发送。
  • ☑ 干货版块可免费使用 🔗超级匿名:面经(美国面经、中国面经、数科面经、PM面经),抖包袱(美国、中国)和录取汇报、定位选校版
  • ☑ 查阅全站 🔗各种匿名方法

本版积分规则

>
快速回复 返回顶部 返回列表