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

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

 
🔗
 楼主| zhuli19901106 2015-7-26 17:31:52 | 只看该作者
全局:
Number of Islands
题意:给定一个01数组,如果1表示陆地,0表示水的话,按照4邻接规则,求有多少块陆地?
解法:这题检查的是连通性,所以既可以用并查集,也可以用DFS、BFS来做。我就选了DFS。
代码:
  1. class Solution {
  2. public:
  3.     Solution() {
  4.         d.resize(4, vector<int>(2));
  5.         int i;
  6.         d[0][0] = -1;
  7.         d[0][1] = 0;
  8.         d[1][0] = +1;
  9.         d[1][1] = 0;
  10.         d[2][0] = 0;
  11.         d[2][1] = -1;
  12.         d[3][0] = 0;
  13.         d[3][1] = +1;
  14.     }
  15.     /**
  16.      * @param grid a boolean 2D matrix
  17.      * @return an integer
  18.      */
  19.     int numIslands(vector<vector<bool> > &grid) {
  20.         n = grid.size();
  21.         if (n == 0) {
  22.             return 0;
  23.         }
  24.         m = grid[0].size();
  25.         if (m == 0) {
  26.             return 0;
  27.         }
  28.         int ans = 0;
  29.         int i, j;
  30.         
  31.         b.resize(n, vector<bool>(m));
  32.         for (i = 0; i < n; ++i) {
  33.             for (j = 0; j < m; ++j) {
  34.                 if (grid[i][j] && !b[i][j]) {
  35.                     ++ans;
  36.                     DFS(i, j);
  37.                 }
  38.             }
  39.         }
  40.         b.clear();
  41.         return ans;
  42.     }
  43. private:
  44.     vector<vector<bool> > b;
  45.     vector<vector<int> > d;
  46.     int n, m;
  47.    
  48.     void DFS(int x, int y, vector<vector<bool> > &grid) {
  49.         b[x][y] = true;
  50.         int x1, y1;
  51.         int i;
  52.         for (i = 0; i < 4; ++i) {
  53.             x1 = x + d[i][0];
  54.             y1 = y + d[i][1];
  55.             if (x1 < 0 || x1 > n - 1 || y1 < 0 || y1 > m - 1) {
  56.                 continue;
  57.             }
  58.             if (grid[x1][y1] && !b[x1][y1]) {
  59.                 DFS(x1, y1, grid);
  60.             }
  61.         }
  62.     }
  63. };
复制代码
复杂度:时间O(N ^ 2),一样。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-26 17:37:08 | 只看该作者
全局:
Number of Islands II
题意:hard难度。和Number Of Islands一样,求有多少块大陆。不过这题要求每次把一块水填成陆地,要求没改变一次地形,就求一次。
解法:显然,这题由于地形会改变,所以flooding算法就不再适用了,所以放弃BFS和DFS。于是选用并查集作为解法,为了保证效率,路径压缩自然是必需品了。
代码:
  1. /**
  2. * Definition for a point.
  3. * struct Point {
  4. *     int x;
  5. *     int y;
  6. *     Point() : x(0), y(0) {}
  7. *     Point(int a, int b) : x(a), y(b) {}
  8. * };
  9. */
  10. class Solution {
  11. public:
  12.     Solution() {
  13.         d.resize(4, vector<int>(2));
  14.         d[0][0] = +1;
  15.         d[0][1] = 0;
  16.         d[1][0] = -1;
  17.         d[1][1] = 0;
  18.         d[2][0] = 0;
  19.         d[2][1] = +1;
  20.         d[3][0] = 0;
  21.         d[3][1] = -1;
  22.     }
  23.     /**
  24.      * @param n an integer
  25.      * @param m an integer
  26.      * @param operators an array of point
  27.      * @return an integer array
  28.      */
  29.     vector<int> numIslands2(int n, int m, vector<Point> &operators) {
  30.         b.clear();
  31.         dj.clear();
  32.         
  33.         this->n = n;
  34.         this->m = m;
  35.         b.resize(n * m, false);
  36.         dj.resize(n * m);
  37.         
  38.         int i;
  39.         for (i = 0; i < n * m; ++i) {
  40.             dj[i] = i;
  41.         }
  42.         
  43.         int cc = 0;
  44.         int x, y;
  45.         int x1, y1;
  46.         int r, r1;
  47.         vector<int> ans;
  48.         vector<int> adj;
  49.         int j;
  50.         for (i = 0; i < operators.size(); ++i) {
  51.             x = operators[i].x;
  52.             y = operators[i].y;
  53.             if (b[x * m + y]) {
  54.                 ans.push_back(cc);
  55.                 continue;
  56.             }
  57.             b[x * m + y] = true;
  58.             adj.clear();
  59.             for (j = 0; j < 4; ++j) {
  60.                 x1 = x + d[j][0];
  61.                 y1 = y + d[j][1];
  62.                 if (inbound(x1, y1) && b[x1 * m + y1]) {
  63.                     adj.push_back(x1 * m + y1);
  64.                 }
  65.             }
  66.             if (adj.empty()) {
  67.                 ans.push_back(++cc);
  68.                 continue;
  69.             }
  70.             dj[findRoot(adj[0])] = findRoot(x * m + y);
  71.             for (j = 1; j < adj.size(); ++j) {
  72.                 r = findRoot(x * m + y);
  73.                 r1 = findRoot(adj[j]);
  74.                 if (r != r1) {
  75.                     dj[r1] = r;
  76.                     --cc;
  77.                 }
  78.             }
  79.             ans.push_back(cc);
  80.         }
  81.         return ans;
  82.     }
  83. private:
  84.     vector<vector<int> > d;
  85.     vector<int> b, dj;
  86.     int n, m;
  87.    
  88.     bool inbound(int x, int y) {
  89.         return x >=0 && x <= n - 1 && y >= 0 && y <= m - 1;
  90.     }
  91.    
  92.     int findRoot(int x) {
  93.         int r = x;
  94.         while (r != dj[r]) {
  95.             r = dj[r];
  96.         }
  97.         int k = x;
  98.         while (x != r) {
  99.             x = dj[x];
  100.             dj[k] = r;
  101.             k = x;
  102.         }
  103.         return r;
  104.     }
  105. };
复制代码
复杂度:时间O(K),K为query次数。空间O(N ^ 2)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-26 18:45:13 | 只看该作者
全局:
本帖最后由 zhuli19901106 于 2015-7-26 18:47 编辑

Find the Connected Component in the Undirected Graph
题意:求无向图的联通分量。
解法:使用并查集。
代码:
  1. #include <unordered_map>
  2. using namespace std;
  3. /**
  4. * Definition for Undirected graph.
  5. * struct UndirectedGraphNode {
  6. *     int label;
  7. *     vector<UndirectedGraphNode *> neighbors;
  8. *     UndirectedGraphNode(int x) : label(x) {};
  9. * };
  10. */
  11. class Solution {
  12. public:
  13.     /**
  14.      * @param nodes a array of Undirected graph node
  15.      * @return a connected set of a Undirected graph
  16.      */
  17.     vector<vector<int> > connectedSet(vector<UndirectedGraphNode*> &nodes) {
  18.         int n = nodes.size();
  19.         int i;
  20.         
  21.         dj.resize(n);
  22.         for (i = 0; i < n; ++i) {
  23.             dj[i] = i;
  24.             um[nodes[i]] = i;
  25.         }
  26.         int j;
  27.         int x, y, rx, ry;
  28.         for (i = 0; i < n; ++i) {
  29.             x = um[nodes[i]];
  30.             for (j = 0; j < nodes[i]->neighbors.size(); ++j) {
  31.                 y = um[nodes[i]->neighbors[j]];
  32.                 rx = findRoot(x);
  33.                 ry = findRoot(y);
  34.                 dj[rx] = ry;
  35.             }
  36.         }
  37.         vector<vector<int> > ans;
  38.         unordered_map<int, vector<int> > cc;
  39.         unordered_map<int, vector<int> >::iterator it;
  40.         
  41.         for (i = 0; i < n; ++i) {
  42.             findRoot(i);
  43.             cc[dj[i]].push_back(nodes[i]->label);
  44.         }
  45.         for (it = cc.begin(); it != cc.end(); ++it) {
  46.             ans.push_back(it->second);
  47.         }
  48.         dj.clear();
  49.         um.clear();
  50.         cc.clear();
  51.         
  52.         return ans;
  53.     }
  54. private:
  55.     vector<int> dj;
  56.     unordered_map<UndirectedGraphNode*, int> um;
  57.    
  58.     int findRoot(int x) {
  59.         int r = x;
  60.         while (r != dj[r]) {
  61.             r = dj[r];
  62.         }
  63.         int k = x;
  64.         while (x != r) {
  65.             x = dj[x];
  66.             dj[k] = r;
  67.             k = x;
  68.         }
  69.         return r;
  70.     }
  71. };
复制代码
复杂度:时间O(N + E),空间O(N)。

回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-26 18:55:20 | 只看该作者
全局:
Find the Weak Connected Component in the Directed Graph
题意:给定一耳光有向图,求出弱连通分量。弱连通分量也就是把这个图当成无向图之后的连通分量。
解法:还是并查集。
代码:
  1. #include <algorithm>
  2. #include <unordered_map>
  3. using namespace std;
  4. /**
  5. * Definition for Directed graph.
  6. * struct DirectedGraphNode {
  7. *     int label;
  8. *     vector<DirectedGraphNode *> neighbors;
  9. *     DirectedGraphNode(int x) : label(x) {};
  10. * };
  11. */
  12. typedef DirectedGraphNode DGN;
  13. class Solution {
  14. public:
  15.     /**
  16.      * @param nodes a array of directed graph node
  17.      * @return a connected set of a directed graph
  18.      */
  19.     vector<vector<int> > connectedSet2(vector<DGN *> &nodes) {
  20.         dj.clear();
  21.         comp.clear();
  22.         ans.clear();
  23.         
  24.         int n = nodes.size();
  25.         int i, j;
  26.         for (i = 0; i < n; ++i) {
  27.             dj[nodes[i]] = nodes[i];
  28.         }
  29.         int m;
  30.         DGN *x, *y, *rx, *ry;
  31.         for (i = 0; i < n; ++i) {
  32.             m = nodes[i]->neighbors.size();
  33.             for (j = 0; j < m; ++j) {
  34.                 x = nodes[i];
  35.                 y = nodes[i]->neighbors[j];
  36.                 rx = findRoot(x);
  37.                 ry = findRoot(y);
  38.                 if (rx == ry) {
  39.                     continue;
  40.                 }
  41.                 dj[rx] = ry;
  42.             }
  43.         }
  44.         for (i = 0; i < n; ++i) {
  45.             findRoot(nodes[i]);
  46.             comp[dj[nodes[i]]].push_back(nodes[i]->label);
  47.         }
  48.         for (auto it = comp.begin(); it != comp.end(); ++it) {
  49.             sort(it->second.begin(), it->second.end());
  50.             ans.push_back(it->second);
  51.         }
  52.         return ans;
  53.     }
  54. private:
  55.     unordered_map<DGN *, DGN *> dj;
  56.     unordered_map<DGN *, vector<int> > comp;
  57.     vector<vector<int> > ans;
  58.    
  59.     DGN *findRoot(DGN *x) {
  60.         DGN *r = x;
  61.         while (r != dj[r]) {
  62.             r = dj[r];
  63.         }
  64.         DGN *k = x;
  65.         while (x != r) {
  66.             x = dj[x];
  67.             dj[k] = r;
  68.             k = x;
  69.         }
  70.         return r;
  71.     }
  72. };
复制代码
复杂度:时间O(N + E),空间O(N)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-26 19:04:54 | 只看该作者
全局:
Scramble String
题意:hard难度。给定两个字符串S和T。如果把S分成左右两部分,而且如此递归下去,就可以用一棵二叉树来表示。求问,如果允许把这棵二叉树的一些节点的左右孩子反转,请问是否能够构成T的一种表示?
解法:题意还是看示例吧,文字描述挺绕口的。这题有O(N^4)的DP解法,网上流传很广泛。我这个也是,所以不用多解释了。至于O(N ^ 3)时间的解法,当时苦想一晚上也没想出来,上网搜也找不到。如果谁会,还请不吝赐教!
代码:
  1. // O(n ^ 4) solution using DP
  2. class Solution {
  3. public:
  4.     /**
  5.      * @param s1 A string
  6.      * @param s2 Another string
  7.      * @return whether s2 is a scrambled string of s1
  8.      */
  9.     bool isScramble(string &s1, string &s2) {
  10.         int n = s1.length();
  11.         if (n != s2.length()) {
  12.             return false;
  13.         }
  14.         if (s1 == s2) {
  15.             return true;
  16.         }
  17.         
  18.         int i, j, k, ii;
  19.         vector<vector<vector<bool> > > dp(n, vector<vector<bool> >(n, vector<bool>(n, false)));
  20.         for (i = 0; i < n; ++i) {
  21.             for (j = 0; j < n; ++j) {
  22.                 dp[0][i][j] = s1[i] == s2[j];
  23.             }
  24.         }
  25.         for (i = 1; i < n; ++i) {
  26.             for (j = 0; j + i < n; ++j) {
  27.                 for (k = 0; k + i< n; ++k) {
  28.                     for (ii = 0; ii < i; ++ii) {
  29.                         if (dp[ii][j][k] && dp[i - ii - 1][j + ii + 1][k + ii + 1]) {
  30.                             dp[i][j][k] = true;
  31.                         }
  32.                         if (dp[ii][j][k + i - ii] && dp[i - ii - 1][j + ii + 1][k]) {
  33.                             dp[i][j][k] = true;
  34.                         }
  35.                     }
  36.                 }
  37.             }
  38.         }
  39.         return dp[n - 1][0][0];
  40.     }
  41. };
复制代码
复杂度:时间O(N ^ 4),空间O(N ^ 3)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-26 19:22:28 | 只看该作者
全局:
Submatrix Sum
题意:给定一个矩阵,找到和为0的子矩阵,给出左上角和右下角。
解法1:暴力解法。直接求和,找找0在哪儿。
代码1:
  1. // O(n ^ 4) solution
  2. class Solution {
  3. public:
  4.     /**
  5.      * @param matrix an integer matrix
  6.      * @return the coordinate of the left-up and right-down number
  7.      */
  8.     vector<vector<int> > submatrixSum(vector<vector<int> > &matrix) {
  9.         vector<vector<int> > &a = matrix;
  10.         int n, m;
  11.         n = a.size();
  12.         m = n ? a[0].size() : 0;
  13.         vector<vector<int> > ans(2, vector<int>(2));
  14.         vector<vector<int> > s(n + 1, vector<int>(m + 1, 0));
  15.         int i, j;
  16.         for (i = 1; i <= n; ++i) {
  17.             for (j = 1; j <= m; ++j) {
  18.                 s[i][j] = s[i - 1][j] + s[i][j - 1] + a[i - 1][j - 1] - s[i - 1][j - 1];
  19.             }
  20.         }
  21.         int i1, j1;
  22.         int sum;
  23.         for (i = 0; i < n; ++i) {
  24.             for (j = 0; j < m; ++j) {
  25.                 for (i1 = i + 1; i1 <= n; ++i1) {
  26.                     for (j1 = j + 1; j1 <= m; ++j1) {
  27.                         sum = 0;
  28.                         sum += s[i][j] + s[i1][j1];
  29.                         sum -= s[i][j1] + s[i1][j];
  30.                         if (sum != 0) {
  31.                             continue;
  32.                         }
  33.                         ans[0][0] = i;
  34.                         ans[0][1] = j;
  35.                         ans[1][0] = i1 - 1;
  36.                         ans[1][1] = j1 - 1;
  37.                         return ans;
  38.                     }
  39.                 }
  40.             }
  41.         }
  42.         return ans;
  43.     }
  44. };
复制代码
复杂度1:时间O(N ^ 4),空间O(N ^ 2)。

解法2:在一个数组中找出加起来等于0的子数组,这个可以在O(N)时间内做到。所以这个问题总体可以在O(N ^ 3)时间解决。
代码2:
  1. // O(n ^ 3) solution
  2. #include <algorithm>
  3. using namespace std;

  4. class Solution {
  5. public:
  6.     /**
  7.      * @param matrix an integer matrix
  8.      * @return the coordinate of the left-up and right-down number
  9.      */
  10.     vector<vector<int> > submatrixSum(vector<vector<int> > &matrix) {
  11.         vector<vector<int> > &a = matrix;
  12.         int n = a.size();
  13.         int m = n ? a[0].size() : 0;
  14.         vector<vector<int> > s(n + 1, vector<int>(m, 0));
  15.         int i, j, k;
  16.         unordered_map<int, int> um;
  17.         
  18.         for (i = 1; i <= n; ++i) {
  19.             for (j = 0; j < m; ++j) {
  20.                 s[i][j] = s[i - 1][j] + a[i - 1][j];
  21.             }
  22.         }
  23.         int sum;
  24.         vector<vector<int> > ans(2, vector<int>(2));
  25.         for (i = 0; i < n; ++i) {
  26.             for (j = i + 1; j <= n; ++j) {
  27.                 um.clear();
  28.                 um[0] = -1;
  29.                 sum = 0;
  30.                 for (k = 0; k < m; ++k) {
  31.                     sum += s[j][k] - s[i][k];
  32.                     if (um.find(sum) != um.end()) {
  33.                         ans[0][0] = i;
  34.                         ans[0][1] = um[sum] + 1;
  35.                         ans[1][0] = j - 1;
  36.                         ans[1][1] = k;
  37.                         return ans;
  38.                     }
  39.                     um[sum] = k;
  40.                 }
  41.             }
  42.         }
  43.         return ans;
  44.     }
  45. };
复制代码
复杂度2:时间O(N ^ 3),空间O(N ^ 2)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-26 19:48:41 | 只看该作者
全局:
Word Break
题意:给定一个长字符串,和一个词典。判断字符串能否分割成若干段,每段都是词典里的单词。
解法:思路是DP。
代码:
  1. #include <algorithm>
  2. using namespace std;

  3. typedef unordered_set<string> uss;
  4. class Solution {
  5. public:
  6.     /**
  7.      * @param s: A string s
  8.      * @param dict: A dictionary of words dict
  9.      */
  10.     bool wordBreak(string s, uss &dict) {
  11.         int n = s.length();
  12.         if (n == 0) {
  13.             return true;
  14.         }
  15.         vector<bool> dp(n + 1, false);
  16.         int maxlen = 0;
  17.         for (auto it = dict.begin(); it != dict.end(); ++it) {
  18.             maxlen = max(maxlen, (int)it->length());
  19.         }
  20.         
  21.         int i, j;
  22.         dp[0] = true;
  23.         for (i = 1; i <= n; ++i) {
  24.             for (j = i - 1; j >= 0; --j) {
  25.                 if (i - j > maxlen) {
  26.                     break;
  27.                 }
  28.                 if (dp[j] && dict.find(s.substr(j, i - j)) != dict.end()) {
  29.                     dp[i] = true;
  30.                     break;
  31.                 }
  32.             }
  33.         }
  34.         return dp[n];
  35.     }
  36. };
复制代码
复杂度:时间O(N ^ 3),空间O(N)。需要指出,substr本身是O(N)级别的算法,所以总体复杂度应该算是O(N ^ 3),而不是O(N ^ 2)。就算是换种写法,避免使用substr,在算hash key的时候,还是需要O(N)时间。

此处补充两个关于字符串hash key的链接:
来自byvoid大神
https://www.byvoid.com/blog/string-hash-compare
来自知乎
http://www.zhihu.com/question/25506718
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-26 19:55:08 | 只看该作者
全局:
Triangle
题意:给定一个三角形,从顶端走到底下,每次允许向左或向右,求能得到的最小和。
解法:基础的DP题目,在POJ上刚学编程时,就是做这种题。
代码:
  1. #include <algorithm>
  2. using namespace std;

  3. class Solution {
  4. public:
  5.     /**
  6.      * @param triangle: a list of lists of integers.
  7.      * @return: An integer, minimum path sum.
  8.      */
  9.     int minimumTotal(vector<vector<int> > &triangle) {
  10.         vector<vector<int> > &a = triangle;
  11.         int n = a.size();
  12.         if (n == 0) {
  13.             return 0;
  14.         }
  15.         
  16.         int i, j;
  17.         for (i = 1; i < n; ++i) {
  18.             a[i][0] += a[i - 1][0];
  19.             for (j = 1; j < i; ++j) {
  20.                 a[i][j] += min(a[i - 1][j - 1], a[i - 1][j]);
  21.             }
  22.             a[i][i] += a[i - 1][i - 1];
  23.         }
  24.         int ans = a[n - 1][0];
  25.         for (i = 1; i < n; ++i) {
  26.             ans = min(ans, a[n - 1][i]);
  27.         }
  28.         return ans;
  29.     }
  30. };
复制代码
复杂度:时间O(N ^ 2),空间O(1)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-26 19:57:52 | 只看该作者
全局:
Remove Duplicates from Sorted Array
题意:有序数组去重。
解法:参见代码。
代码:
  1. class Solution {
  2. public:
  3.     /**
  4.      * @param A: a list of integers
  5.      * @return : return an integer
  6.      */
  7.     int removeDuplicates(vector<int> &nums) {
  8.         int n = nums.size();
  9.         int m = 0;
  10.         int i, j;
  11.         
  12.         i = 0;
  13.         while (i < n) {
  14.             j = i + 1;
  15.             while (j < n && nums[i] == nums[j]) {
  16.                 ++j;
  17.             }
  18.             nums[m++] = nums[i];
  19.             i = j;
  20.         }
  21.         while (nums.size() > m) {
  22.             nums.pop_back();
  23.         }
  24.         return m;
  25.     }
  26. };
复制代码
复杂度:时间O(N),空间O(1)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-26 20:00:23 | 只看该作者
全局:
Remove Duplicates from Sorted Array II
题意:有序数组去重,但是每个元素允许至多两个。
解法:代码稍作修改即可。
代码:
  1. class Solution {
  2. public:
  3.     /**
  4.      * @param A: a list of integers
  5.      * @return : return an integer
  6.      */
  7.     int removeDuplicates(vector<int> &nums) {
  8.         int n = nums.size();
  9.         int m = 0;
  10.         int i, j;
  11.         i = 0;
  12.         while (i < n) {
  13.             j = i + 1;
  14.             while (j < n && nums[i] == nums[j]) {
  15.                 ++j;
  16.             }
  17.             nums[m++] = nums[i];
  18.             if (j - i > 1) {
  19.                 nums[m++] = nums[i];
  20.             }
  21.             i = j;
  22.         }
  23.         while (nums.size() > m) {
  24.             nums.pop_back();
  25.         }
  26.         return m;
  27.     }
  28. };
复制代码
复杂度:时间O(N),空间O(1)。
回复

使用道具 举报

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

本版积分规则

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