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

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

 
🔗
 楼主| zhuli19901106 2015-7-20 22:44:35 | 只看该作者
全局:
First Bad Version
题意:猜数字。
解法:二分不解释。
代码:
  1. /**
  2. * class VersionControl {
  3. *     public:
  4. *     static bool isBadVersion(int k);
  5. * }
  6. * you can use VersionControl::isBadVersion(k) to judge whether
  7. * the kth code version is bad or not.
  8. */
  9. class Solution {
  10. public:
  11.     /**
  12.      * @param n: An integers.
  13.      * @return: An integer which is the first bad version.
  14.      */
  15.     int findFirstBadVersion(int n) {
  16.         int ll = 1;
  17.         int rr = n;
  18.         if (VersionControl::isBadVersion(ll)) {
  19.             return ll;
  20.         }
  21.         int mm;
  22.         while (rr - ll > 1) {
  23.             mm = ll + (rr - ll) / 2;
  24.             if (VersionControl::isBadVersion(mm)) {
  25.                 rr = mm;
  26.             } else {
  27.                 ll = mm;
  28.             }
  29.         }
  30.         return rr;
  31.     }
  32. };
复制代码
复杂度:时间O(log(N)),空间O(1)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-20 23:22:05 | 只看该作者
全局:
Find Peak Element
题意:给定一个数组,保证相邻元素不相等,并且A[0] < A[1] && A[A.length - 2] > A[A.length - 1]。请找出一个大于左右邻居的元素。
解法1:顺着扫一遍。
代码1:
  1. // The O(n) solution.
  2. class Solution {
  3. public:
  4.     /**
  5.      * @param A: An integers array.
  6.      * @return: return any of peek positions.
  7.      */
  8.     int findPeak(vector<int> A) {
  9.         for (i = 1; i < n - 1; ++i) {
  10.             if (A[i] > A[i - 1] && A[i] > A[i + 1]) {
  11.                 return i;
  12.             }
  13.         }
  14.         return -1;
  15.     }
  16. };
复制代码
复杂度1:时间O(N),空间O(1)。

解法2:为什么可以二分?因为左端小于,右端大于,至少会存在一个位置是小于和大于汇合的地方。
代码2:
  1. // The O(log(n)) solution
  2. class Solution {
  3. public:
  4.     /**
  5.      * @param A: An integers array.
  6.      * @return: return any of peek positions.
  7.      */
  8.     int findPeak(vector<int> A) {
  9.         int n = A.size();
  10.         int ll, rr, mm;
  11.         
  12.         ll = 0;
  13.         rr = n - 1;
  14.         while (rr - ll > 2) {
  15.             mm = (ll + rr) / 2;
  16.             if (A[mm] > A[mm - 1] && A[mm] > A[mm + 1]) {
  17.                 return mm;
  18.             } else if (A[mm - 1] < A[mm]) {
  19.                 ll = mm;
  20.             } else {
  21.                 rr = mm;
  22.             }
  23.         }
  24.         return (ll + rr) / 2;
  25.     }
  26. };
复制代码
复杂度2:时间O(log(N)),空间O(1)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-20 23:43:32 | 只看该作者
全局:
本帖最后由 zhuli19901106 于 2015-7-20 23:50 编辑

Longest Common Subsequence
题意:最长公共子序列,经典问题。解法1:DP
代码1:
  1. // O(n ^ 2) solution using DP
  2. #include <algorithm>
  3. using namespace std;

  4. class Solution {
  5. public:
  6.     /**
  7.      * @param A, B: Two strings.
  8.      * @return: The length of longest common subsequence of A and B.
  9.      */
  10.     int longestCommonSubsequence(string A, string B) {
  11.         int la = A.length();
  12.         int lb = B.length();
  13.         if (la == 0 || lb == 0) {
  14.             return 0;
  15.         }
  16.         vector<vector<int> > dp;
  17.         dp.resize(la + 1, vector<int>(lb + 1, 0));
  18.         
  19.         int i, j;
  20.         for (i = 1; i <= la; ++i) {
  21.             for (j = 1; j <= lb; ++j) {
  22.                 if (A[i - 1] == B[j - 1]) {
  23.                     dp[i][j] = dp[i - 1][j - 1] + 1;
  24.                 } else {
  25.                     dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
  26.                 }
  27.             }
  28.         }
  29.         return dp[la][lb];
  30.     }
  31. };
复制代码
复杂度1:时间O(N * M),空间O(N * M)。

解法2:空间可以优化到成O(M)。其实这题可以转化成最长递增子序列问题。不过转化后只能把时间的下限优化到O(N * log(N)),上限依然是O(N ^ 2),实现也比较复杂,所以就不写了。
代码2:
  1. // Space optimized to O(n)
  2. #include <algorithm>
  3. using namespace std;

  4. class Solution {
  5. public:
  6.     /**
  7.      * @param A, B: Two strings.
  8.      * @return: The length of longest common subsequence of A and B.
  9.      */
  10.     int longestCommonSubsequence(string A, string B) {
  11.         int la = A.length();
  12.         int lb = B.length();
  13.         if (la == 0 || lb == 0) {
  14.             return 0;
  15.         }
  16.         vector<vector<int> > dp;
  17.         dp.resize(2, vector<int>(lb + 1, 0));
  18.         
  19.         int i, j;
  20.         int f, nf;
  21.         
  22.         f = 1;
  23.         nf = !f;
  24.         for (i = 1; i <= la; ++i) {
  25.             dp[f][0] = 0;
  26.             for (j = 1; j <= lb; ++j) {
  27.                 if (A[i - 1] == B[j - 1]) {
  28.                     dp[f][j] = dp[nf][j - 1] + 1;
  29.                 } else {
  30.                     dp[f][j] = max(dp[f][j - 1], dp[nf][j]);
  31.                 }
  32.             }
  33.             f = !f;
  34.             nf = !f;
  35.         }
  36.         return dp[nf][lb];
  37.     }
  38. };
复制代码
复杂度2:时间O(N * M),空间O(M)。

回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-20 23:52:02 | 只看该作者
全局:
Longest Increasing Subsequence
题意:最长递增子序列。
解法:用二分查找,可以实现O(N * log(N))的解法,面试时务必写出来,否则必被刷。
代码:
  1. #include <algorithm>
  2. using namespace std;

  3. class Solution {
  4. public:
  5.     /**
  6.      * @param nums: The integer array
  7.      * @return: The length of LIS (longest increasing subsequence)
  8.      */
  9.     int longestIncreasingSubsequence(vector<int> nums) {
  10.         vector<int> &a = nums;
  11.         vector<int> v;
  12.         int n = a.size();
  13.         if (n == 0) {
  14.             return 0;
  15.         }
  16.         v.push_back(a[0]);
  17.         int i;
  18.         for (i = 1; i < n; ++i) {
  19.             if (a[i] >= v.back()) {
  20.                 v.push_back(a[i]);
  21.                 continue;
  22.             }
  23.             j = lower_bound(v.begin(), v.end(), a[i]) - v.begin();
  24.             v[j] = a[i];
  25.         }
  26.         return v.size();
  27.     }
  28. };
复制代码
复杂度:时间O(N * log(N)),空间O(N)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-21 00:09:05 | 只看该作者
全局:
Longest Common Prefix
题意:给定一些字符串,求它们的最长公共前缀。
解法:这题用字典树当然也可以做,但感觉代码更麻烦,效率也没提高多少,所以我就没写。还不如直接把当前的最长前缀和那些字符串逐个对比。反正前缀只会越变越短。
代码:
  1. class Solution {
  2. public:   
  3.     /**
  4.      * @param strs: A list of strings
  5.      * @return: The longest common prefix
  6.      */
  7.     string longestCommonPrefix(vector<string> &strs) {
  8.         int n = strs.size();
  9.         if (n == 0) {
  10.             return "";
  11.         }
  12.         string ans = strs[0];
  13.         int i, j;
  14.         for (i = 1; i < n; ++i) {
  15.             j = 0;
  16.             while (j < ans.length() && j < strs[i].length()) {
  17.                 if (ans[j] != strs[i][j]) {
  18.                     break;
  19.                 }
  20.                 ++j;
  21.             }
  22.             while (ans.length() > j) {
  23.                 ans.pop_back();
  24.             }
  25.         }
  26.         return ans;
  27.     }
  28. };
复制代码
复杂度:时间O(字符总数),空间O(1)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-21 00:22:27 | 只看该作者
全局:
Longest Common Substring
题意:给定两个字符串,求最长公共子串。注意子串是连续的,而子序列可以不连续。
解法1:首先想到的就是DP,定义DP{i}{j}为以A{i}和B{j}结尾的公共子串最长能有多长,于是有了以下代码。
代码1:
  1. class Solution {
  2. public:   
  3.     /**
  4.      * @param A, B: Two string.
  5.      * @return: the length of the longest common substring.
  6.      */
  7.     int longestCommonSubstring(string &A, string &B) {
  8.         int la = A.size();
  9.         int lb = B.size();
  10.         vector<vector<int> > dp;
  11.         dp.resize(la + 1, vector<int>(lb + 1, 0));
  12.         int i, j;
  13.         int ans = 0;
  14.         for (i = 1; i <= la; ++i) {
  15.             for (j = 1; j <= lb; ++j) {
  16.                 if (A[i - 1] == B[j - 1]) {
  17.                     dp[i][j] = dp[i - 1][j - 1] + 1;
  18.                 } else {
  19.                     dp[i][j] = 0;
  20.                 }
  21.                 ans = max(ans, dp[i][j]);
  22.             }
  23.         }
  24.         return ans;
  25.     }
  26. };
复制代码
复杂度1:时间O(N * M),空间O(N * M)。

解法2:状态转移方程只涉及相邻状态,所以照例把空间优化成O(M)。
代码2:
  1. // Space optimized to O(n)
  2. class Solution {
  3. public:   
  4.     /**
  5.      * @param A, B: Two string.
  6.      * @return: the length of the longest common substring.
  7.      */
  8.     int longestCommonSubstring(string &A, string &B) {
  9.         int la = A.size();
  10.         int lb = B.size();
  11.         if (la == 0 || lb == 0) {
  12.             return 0;
  13.         }
  14.         
  15.         vector<vector<int> > dp;
  16.         dp.resize(2, vector<int>(lb + 1, 0));
  17.         int i, j;
  18.         int ans = 0;
  19.         int f = 1;
  20.         int nf = !f;
  21.         for (i = 1; i <= la; ++i) {
  22.             for (j = 1; j <= lb; ++j) {
  23.                 if (A[i - 1] == B[j - 1]) {
  24.                     dp[f][j] = dp[nf][j - 1] + 1;
  25.                 } else {
  26.                     dp[f][j] = 0;
  27.                 }
  28.                 ans = max(ans, dp[f][j]);
  29.             }
  30.             f = !f;
  31.             nf = !f;
  32.         }
  33.         return ans;
  34.     }
  35. };
复制代码
复杂度2:时间O(N * M),空间O(M)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-21 00:42:40 | 只看该作者
全局:
Median
题意:给定一个数组,求中位数。
解法1:根据快速排序的代码,修改成快速选择算法。
代码1:
  1. #include <algorithm>
  2. using namespace std;

  3. class Solution {
  4. public:
  5.     /**
  6.      * @param nums: A list of integers.
  7.      * @return: An integer denotes the middle number of the array.
  8.      */
  9.     int median(vector<int> &nums) {
  10.         // write your code here
  11.                 int n = nums.size();
  12.                 return quickSelect(nums, (n - 1) / 2, 0, n - 1);
  13.     }
  14. private:
  15.         int quickSelect(vector<int> &a, int k, int ll, int rr) {
  16.                 if (ll == rr) {
  17.                         return a[k];
  18.                 }
  19.                
  20.                 int i, j;
  21.                 int piv = a[ll];
  22.                
  23.                 i = ll + 1;
  24.                 j = rr;
  25.                 while (true) {
  26.                         while (i <= j && a[i] < piv) {
  27.                                 ++i;
  28.                         }
  29.                         while (i <= j && a[j] > piv) {
  30.                                 --j;
  31.                         }
  32.                         if (i > j) {
  33.                                 break;
  34.                         }
  35.                         swap(a[i++], a[j--]);
  36.                 }
  37.                 swap(a[j], a[ll]);
  38.                 if (k < j) {
  39.                         return quickSelect(a, k, ll, j - 1);
  40.                 } else if (k > j) {
  41.                         return quickSelect(a, k, j + 1, rr);
  42.                 } else {
  43.                         return a[k];
  44.                 }
  45.         }
  46. };
复制代码
复杂度1:时间O(N),空间O(log(N))。

解法2:改成非递归,因为上面那个是尾递归。
代码2:
  1. #include <algorithm>
  2. using namespace std;

  3. class Solution {
  4. public:
  5.     /**
  6.      * @param nums: A list of integers.
  7.      * @return: An integer denotes the middle number of the array.
  8.      */
  9.     int median(vector<int> &nums) {
  10.         // write your code here
  11.                 int n = nums.size();
  12.                 return quickSelect(nums, (n - 1) / 2, 0, n - 1);
  13.     }
  14. private:
  15.         int quickSelect(vector<int> &a, int k, int ll, int rr) {
  16.                 int i, j;
  17.                 int piv;
  18.                
  19.         while (true) {
  20.             if (ll == rr) {
  21.                 return a[k];
  22.             }
  23.             i = ll + 1;
  24.             j = rr;
  25.             piv = a[ll];
  26.             while (true) {
  27.                 while (i <= j && a[i] < piv) {
  28.                     ++i;
  29.                 }
  30.                 while (i <= j && a[j] > piv) {
  31.                     --j;
  32.                 }
  33.                 if (i > j) {
  34.                     break;
  35.                 }
  36.                 swap(a[i++], a[j--]);
  37.             }
  38.             swap(a[j], a[ll]);
  39.             if (k < j) {
  40.                 rr = j - 1;
  41.             } else if (k > j) {
  42.                 ll = j + 1;
  43.             } else {
  44.                 return a[k];
  45.             }
  46.         }
  47.         }
  48. };
复制代码
复杂度2:时间O(N),空间O(1)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-21 00:46:54 | 只看该作者
全局:
Data Stream Median
题意:hard难度。不断输入一些数,每读入一个返回当前的中位数。
解法:利用最大堆,最小堆,保证一半小的,一般大的分开存放。用map也行。
代码:
  1. #include <queue>
  2. using namespace std;

  3. class Solution {
  4. public:
  5.     /**
  6.      * @param nums: A list of integers.
  7.      * @return: The median of numbers
  8.      */
  9.     vector<int> medianII(vector<int> &nums) {
  10.         vector<int> &a = nums;
  11.         int n = a.size();
  12.         // The smaller half
  13.         priority_queue<int, vector<int>, less<int> > small;
  14.         // The larger half
  15.         priority_queue<int, vector<int>, greater<int> > large;
  16.         int i;
  17.         vector<int> ans;
  18.         
  19.         small.push(INT_MIN);
  20.         large.push(INT_MAX);
  21.         int vs, vl;
  22.         for (i = 0; i < n; ++i) {
  23.             if (i & 1) {
  24.                 large.push(a[i]);
  25.             } else {
  26.                 small.push(a[i]);
  27.             }
  28.             vs = small.top();
  29.             vl = large.top();
  30.             if (vs > vl) {
  31.                 small.pop();
  32.                 small.push(vl);
  33.                 large.pop();
  34.                 large.push(vs);
  35.             }
  36.             ans.push_back(small.top());
  37.         }
  38.         return ans;
  39.     }
  40. };
复制代码
复杂度:时间O(N * log(N)),空间O(N)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-21 00:50:30 | 只看该作者
全局:
Single Number
题意:数组中有个数出现了一次,其他数都出现两次,把那个单独的找出来。
解法:异或。
代码:
  1. class Solution {
  2. public:
  3.         /**
  4.          * @param A: Array of integers.
  5.          * return: The single number.
  6.          */
  7.     int singleNumber(vector<int> &A) {
  8.         int i;
  9.         int n = A.size();
  10.         int ans = 0;
  11.         for (i = 0; i < n; ++i) {
  12.             ans ^= A[i];
  13.         }
  14.         return ans;
  15.     }
  16. };
复制代码
复杂度:时间O(N),空间O(1)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-21 00:56:31 | 只看该作者
全局:
本帖最后由 zhuli19901106 于 2015-7-21 01:16 编辑

Single Number II
题意:一个数组中,除了一个数出现一次外,其他的都出现了三次。找出那个单独的。
解法1:把每个数按照32位分开考虑,每一位如果“1”的总个数是3的倍数,则那个单独的数的对应位就是“0”,反之则为“1”。所以用个长度32的数组来统计“1”的个数。
代码1:
  1. #include <cstring>
  2. using namespace std;

  3. class Solution {
  4. public:
  5.         /**
  6.          * @param A : An integer array
  7.          * @return : An integer
  8.          */
  9.     int singleNumberII(vector<int> &A) {
  10.         const int NB = 32;
  11.         int c[NB];
  12.         int i, j;
  13.         int n = A.size();
  14.         
  15.         memset(c, 0, sizeof(c));
  16.         for (i = 0; i < n; ++i) {
  17.             for (j = 0; j < NB; ++j) {
  18.                 if (A[i] & (1 << j)) {
  19.                     ++c[j];
  20.                 }
  21.             }
  22.         }
  23.         int ans = 0;
  24.         for (i = 0; i < NB; ++i) {
  25.             if (c[i] % 3) {
  26.                 ans |= (1 << i);
  27.             }
  28.         }
  29.         return ans;
  30.     }
  31. };
复制代码
复杂度1:时间O(N),空间O(1)。

解法2:这儿还有种比较欠揍的写法,可以用一个64位整数来代替数组,因为我们只关心1的个数是不是3的倍数,所以保存余数即可。鉴于代码可读性极差,所以不推荐把位运算当成装X利器。你指望你离职以后新同事读得懂这种代码?
代码2:
  1. #include <cstring>
  2. using namespace std;

  3. typedef long long int LL;
  4. class Solution {
  5. public:
  6.         /**
  7.          * @param A : An integer array
  8.          * @return : An integer
  9.          */
  10.     int singleNumberII(vector<int> &A) {
  11.         const int NB = 32;
  12.         LL c = 0;
  13.         LL i, j;
  14.         LL bit;
  15.         int n = A.size();
  16.         
  17.         for (i = 0; i < n; ++i) {
  18.             for (j = 0; j < NB; ++j) {
  19.                 if (A[i] & (1 << j)) {
  20.                     bit = (c >> (j << 1)) & 3;
  21.                     bit = bit == 2 ? 0 : bit + 1;
  22.                     c = (c & ~(3LL << (j << 1))) | (bit << (j << 1));
  23.                 }
  24.             }
  25.         }
  26.         int ans = 0;
  27.         for (i = 0; i < NB; ++i) {
  28.             bit = (c >> (i << 1)) & 3;
  29.             if (bit) {
  30.                 ans |= (1 << i);
  31.             }
  32.         }
  33.         return ans;
  34.     }
  35. };
复制代码
复杂度2:时间O(N),空间O(1)。

回复

使用道具 举报

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

本版积分规则

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