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

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

 
🔗
 楼主| zhuli19901106 2015-7-18 16:01:21 | 只看该作者
全局:
Trailing Zeros
题意:给定N,求N的阶乘末尾有多少个0
解法:0的个数等于N!可以分解出多少个10,也就是多少个5,所以不断除以5并求和即可。
代码:
  1. class Solution {
  2. public:
  3.     // param n : description of n
  4.     // return: description of return
  5.     long long trailingZeros(long long n) {
  6.         long long int sum = 0;
  7.         while (n > 0) {
  8.             sum += n / 5;
  9.             n /= 5;
  10.         }
  11.         return sum;
  12.     }
  13. };
复制代码
复杂度:时间O(log N),空间O(1)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-18 16:11:37 | 只看该作者
全局:
本帖最后由 zhuli19901106 于 2015-7-18 22:36 编辑

Digit Counts
题意:给定一个数字k,以及一个整数n,求0~n的所有整数中,数字k出现了多少次。k可以是0~9。
解法:典型的数位动归题目,这种题直接从0数到N肯定会被面试官鄙视的。这题头疼的是0的处理,我的代码中1~9可以用同一套解法,0单独处理。数组sum{i}表示i位数中总共出现了多少个1~9,sum0{i}表示数组中总共出现了多少个0。至于它们为什么不能归为同类,可以这么理解。最高位数字可以是1~9,而不能是0。所以0要单独处理,思路也不一样。这题我的实现很复杂,自己都觉得晕,请问有效率不差,而且更简洁易懂的思路吗?
代码:
  1. typedef long long int LL;

  2. class Solution {
  3. public:
  4.     Solution() {
  5.         int i, j;
  6.         LL b10;
  7.         
  8.         sum[0] = 0;
  9.         sum[1] = 1;
  10.         b10 = 1;
  11.         for (i = 2; i < M; ++i) {
  12.             b10 *= 10;
  13.             sum[i] = 10 * sum[i - 1] + b10;
  14.         }
  15.         
  16.         LL ss;

  17.         sum0[0] = 0;
  18.         sum0[1] = 0;
  19.         b10 = 1;
  20.         for (i = 2; i < M; ++i) {
  21.             b10 *= 10;
  22.             ss = 0;
  23.             for (j = 1; j < i; ++j) {
  24.                 ss += sum0[j];
  25.             }
  26.             sum0[i] = 9 * (leadingZero(b10 - 1, i - 1) + ss);
  27.         }
  28.     }
  29.     /*
  30.      * param k : As description.
  31.      * param n : As description.
  32.      * return: How many k's between 0 and n.
  33.      */
  34.     int digitCounts(int k, int n) {
  35.         if (k == 0) {
  36.             return countZero(n) + 1;
  37.         }
  38.         return countDigit(n, k);
  39.     }
  40. private:
  41.     static const int M = 19;
  42.     LL sum[M];
  43.     LL sum0[M];
  44.    
  45.     LL countDigit(LL x, int d) {
  46.         LL b10;
  47.         int idx;

  48.         if (x < d) {
  49.             return 0;
  50.         } else if (x < 10) {
  51.             return 1;
  52.         }

  53.         b10 = 1;
  54.         idx = 0;
  55.         while (b10 * 10 <= x) {
  56.             b10 *= 10;
  57.             ++idx;
  58.         }
  59.         if (x / b10 > d) {
  60.             return (x / b10) * sum[idx] + b10 + countDigit(x % b10, d);
  61.         } else if (x / b10 == d) {
  62.             return (x / b10) * sum[idx] + (x % b10 + 1) + countDigit(x % b10, d);
  63.         } else {
  64.             return (x / b10) * sum[idx] + countDigit(x % b10, d);
  65.         }
  66.     }
  67.    
  68.     LL leadingZero(LL x, int idx) {
  69.         LL b10 = 1;
  70.         LL sum = idx;
  71.         int bi = 1;
  72.         while (b10 * 10 <= x) {
  73.             sum += 9 * b10 * (idx - bi);
  74.             b10 *= 10;
  75.             ++bi;
  76.         }
  77.         sum += (x - b10 + 1) * (idx - bi);
  78.         return sum;
  79.     }
  80.    
  81.     LL countZero(LL x) {
  82.         LL b10;
  83.         int idx;
  84.         
  85.         if (x < 10) {
  86.             return 0;
  87.         }

  88.         b10 = 1;
  89.         idx = 0;
  90.         while (b10 * 10 <= x) {
  91.             b10 *= 10;
  92.             ++idx;
  93.         }

  94.         LL ans = 0;
  95.         LL ss = 0;
  96.         int i;

  97.         for (i = 1; i <= idx; ++i) {
  98.             ans += sum0[i];
  99.             ss += sum0[i];
  100.         }
  101.         ans += (x / b10 - 1) * (ss + leadingZero(b10 - 1, idx));
  102.         ans += leadingZero(x % b10, idx) + countZero(x % b10);

  103.         return ans;
  104.     }
  105. };
复制代码
复杂度:时间上对DP数组的预处理O(log N),函数调用过程也是O(log N)。空间也是O(log N)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-18 16:21:02 | 只看该作者
全局:
Ugly Number
题意:这题和Humble Number一样,数论里名字有好几个,下面这个应该是一般化的定义。就是求所有质因数只有3, 5, 7的数里,从小到大排第k的那个。
https://en.wikipedia.org/wiki/Smooth_number
解法:3个指针逐步向前移,每次选取最小值。
代码:
  1. #include <algorithm>
  2. using namespace std;

  3. typedef long long int LL;

  4. class Solution {
  5. public:
  6.     /*
  7.      * @param k: The number k.
  8.      * @return: The kth prime number as description.
  9.      */
  10.     LL kthPrimeNumber(int k) {
  11.         vector<LL> v;
  12.         int p1, p2, p3;
  13.         LL a1, a2, a3;
  14.         LL val;
  15.         
  16.         p1 = p2 = p3 = 0;
  17.         v.push_back(1);
  18.         while (v.size() <= k) {
  19.             a1 = v[p1] * 3;
  20.             a2 = v[p2] * 5;
  21.             a3 = v[p3] * 7;
  22.             val = min(a1, min(a2, a3));
  23.             if (val == a1) {
  24.                 ++p1;
  25.             }
  26.             if (val == a2) {
  27.                 ++p2;
  28.             }
  29.             if (val == a3) {
  30.                 ++p3;
  31.             }
  32.             v.push_back(val);
  33.         }
  34.         return v[k];
  35.     }
  36. };
复制代码
复杂度:时间空间都是O(K)
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-18 16:26:09 | 只看该作者
全局:
本帖最后由 zhuli19901106 于 2015-7-18 22:29 编辑

Kth Largest Element
题意:求一个数组中,第K大的数。允许交换数组中的元素。
解法1:根据快排改造得到快速选择算法。注意题目要求的是第K大,不是第K小。
代码1:
  1. #include <algorithm>
  2. using namespace std;

  3. class Solution {
  4. public:
  5.     /*
  6.      * param k : description of k
  7.      * param nums : description of array and index 0 ~ n-1
  8.      * return: description of return
  9.      */
  10.     int kthLargestElement(int k, vector<int> nums) {
  11.         int n = nums.size();
  12.         return quickSelect(nums, 0, n - 1, n - k);
  13.     }
  14. private:
  15.     int quickSelect(vector<int> &a, int ll, int rr, int k) {
  16.         if (ll == rr) {
  17.             return a[k];
  18.         }
  19.         int i = ll + 1;
  20.         int j = rr;
  21.         int piv = a[ll];
  22.         while (true) {
  23.             while (i <= j && a[i] < piv) {
  24.                 ++i;
  25.             }
  26.             while (i <= j && a[j] > piv) {
  27.                 --j;
  28.             }
  29.             if (i > j) {
  30.                 break;
  31.             }
  32.             swap(a[i++], a[j--]);
  33.         }
  34.         swap(a[ll], a[j]);
  35.         if (k < j) {
  36.             return quickSelect(a, ll, j - 1, k);
  37.         } else if (k > j) {
  38.             return quickSelect(a, j + 1, rr, k);
  39.         } else {
  40.             return a[k];
  41.         }
  42.     }
  43. };
复制代码
复杂度1:时间可以做到O(N),但由于是递归,理论上空间复杂度介于O(log N)和O(N)之间。不知道O(1)空间的算法应该怎么做?

解法2:感谢stellari的提醒,递归经过简单的改造就变成了迭代。我居然没看出自己写的是尾递归(-_-)||
代码2:
  1. // The iterative version
  2. #include <algorithm>
  3. using namespace std;

  4. class Solution {
  5. public:
  6.     /*
  7.      * param k : description of k
  8.      * param nums : description of array and index 0 ~ n-1
  9.      * return: description of return
  10.      */
  11.     int kthLargestElement(int k, vector<int> nums) {
  12.         int n = nums.size();
  13.         return quickSelect(nums, 0, n - 1, n - k);
  14.     }
  15. private:
  16.     int quickSelect(vector<int> &a, int ll, int rr, int k) {
  17.         int i;
  18.         int j;
  19.         int piv;
  20.         
  21.         while (true) {
  22.             if (ll == rr) {
  23.                 return a[k];
  24.             }
  25.             i = ll + 1;
  26.             j = rr;
  27.             piv = a[ll];
  28.             while (true) {
  29.                 while (i <= j && a[i] < piv) {
  30.                     ++i;
  31.                 }
  32.                 while (i <= j && a[j] > piv) {
  33.                     --j;
  34.                 }
  35.                 if (i > j) {
  36.                     break;
  37.                 }
  38.                 swap(a[i++], a[j--]);
  39.             }
  40.             swap(a[ll], a[j]);
  41.             if (k < j) {
  42.                 rr = j - 1;
  43.             } else if (k > j) {
  44.                 ll = j + 1;
  45.             } else {
  46.                 return a[k];
  47.             }
  48.         }
  49.     }
  50. };
复制代码
复杂度2:由于是迭代,所以空间变成O(1)了,时间是O(N)。

回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-18 16:32:37 | 只看该作者
全局:
Merge Sorted Array II
题意:归并两个有序数组,存在新数组里。
解法:略
代码:
  1. class Solution {
  2. public:
  3.     /**
  4.      * @param A and B: sorted integer array A and B.
  5.      * @return: A new sorted integer array
  6.      */
  7.     vector<int> mergeSortedArray(vector<int> &A, vector<int> &B) {
  8.         vector<int> C;
  9.         int i, j;
  10.         int na, nb;
  11.         
  12.         na = A.size();
  13.         nb = B.size();
  14.         i = j = 0;
  15.         while (i < na && j < nb) {
  16.             if (A[i] < B[j]) {
  17.                 C.push_back(A[i++]);
  18.             } else {
  19.                 C.push_back(B[j++]);
  20.             }
  21.         }
  22.         while (i < na) {
  23.             C.push_back(A[i++]);
  24.         }
  25.         while (j < nb) {
  26.             C.push_back(B[j++]);
  27.         }
  28.         return C;
  29.     }
  30. };
复制代码
复杂度:时间O(N + M),空间O(1)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-18 16:37:23 | 只看该作者
全局:
Binary Tree Serialization
题意:序列化和反序列化一棵二叉树。
解法:这题其实考察的是对二叉树遍历的理解,不论前序、后序、中序、层次遍历都可以。我倾向于选前序或者层次遍历。序列化的表示方法则可以自有选择。
代码:
  1. #include <vector>
  2. using namespace std;
  3. /**
  4. * Definition of TreeNode:
  5. * class TreeNode {
  6. * public:
  7. *     int val;
  8. *     TreeNode *left, *right;
  9. *     TreeNode(int val) {
  10. *         this->val = val;
  11. *         this->left = this->right = NULL;
  12. *     }
  13. * }
  14. */
  15. class Solution {
  16. public:
  17.     string serialize(TreeNode *root) {
  18.         serializePreorder(root);
  19.         
  20.         string ans = "";
  21.         int n = v.size();
  22.         int i;
  23.         for (i = 0; i < n; ++i) {
  24.             ans += v[i];
  25.             ans.push_back(' ');
  26.         }
  27.         ans.pop_back();
  28.         v.clear();
  29.         
  30.         return ans;
  31.     }

  32.     TreeNode *deserialize(string data) {
  33.         int n = data.length();
  34.         int i, j;
  35.         string s;
  36.         
  37.         while (i < n) {
  38.             s = "";
  39.             j = i;
  40.             while (j < n && data[j] != ' ') {
  41.                 s.push_back(data[j++]);
  42.             }
  43.             v.push_back(s);
  44.             ++j;
  45.             i = j;
  46.         }
  47.         
  48.         idx = 0;
  49.         TreeNode *root;
  50.         deserializePreorder(root);
  51.         v.clear();
  52.         
  53.         return root;
  54.     }
  55. private:
  56.     vector<string> v;
  57.     int idx;
  58.    
  59.     void serializePreorder(TreeNode *root) {
  60.         if (root == NULL) {
  61.             v.push_back("#");
  62.             return;
  63.         }
  64.         v.push_back(to_string(root->val));
  65.         serializePreorder(root->left);
  66.         serializePreorder(root->right);
  67.     }
  68.    
  69.     void deserializePreorder(TreeNode *&root) {
  70.         if (v[idx] == "#") {
  71.             root = NULL;
  72.             ++idx;
  73.         } else {
  74.             root = new TreeNode(atoi(v[idx].data()));
  75.             ++idx;
  76.             deserializePreorder(root->left);
  77.             deserializePreorder(root->right);
  78.         }
  79.     }
  80. };
复制代码
复杂度:时间O(N),空间O(N)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-18 16:41:41 | 只看该作者
全局:
Rotate String
题意:给定一个字符串,把它循环右移K位。
解法:使用神奇的reverse函数,注意处理边界情况。
代码:
  1. #include <algorithm>
  2. using namespace std;

  3. class Solution {
  4. public:
  5.   /**
  6.      * param A: A string
  7.      * param offset: Rotate string with offset.
  8.      * return: Rotated string.
  9.      */
  10.     string rotateString(string A, int offset) {
  11.         if (A == "") {
  12.             return A;
  13.         }
  14.         offset %= A.length();
  15.         if (offset == 0) {
  16.             return A;
  17.         }
  18.         reverse(A.begin(), A.begin() + A.length() - offset);
  19.         reverse(A.begin() + A.length() - offset, A.end());
  20.         reverse(A.begin(), A.end());
  21.         return A;
  22.     }
  23. };
复制代码
复杂度:O(N)
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-18 16:44:57 | 只看该作者
全局:
Fizz Buzz
题意:纯水题,在面试里能碰见也算是人品爆发了。
解法:水过
代码:
  1. class Solution {
  2. public:
  3.     /**
  4.      * param n: As description.
  5.      * return: A list of strings.
  6.      */
  7.     vector<string> fizzBuzz(int n) {
  8.         vector<string> results;
  9.         for (int i = 1; i <= n; i++) {
  10.             if (i % 15 == 0) {
  11.                 results.push_back("fizz buzz");
  12.             } else if (i % 5 == 0) {
  13.                 results.push_back("buzz");
  14.             } else if (i % 3 == 0) {
  15.                 results.push_back("fizz");
  16.             } else {
  17.                 results.push_back(to_string(i));
  18.             }
  19.         }
  20.         return results;
  21.     }
  22. };
复制代码
复杂度:时间O(N),空间O(1)
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-18 16:50:26 | 只看该作者
全局:
Search Range in Binary Search Tree
题意:在一个BST中,给定K1个K2两个值,输出BST中所有介于两者之间的值,要求升序输出。
解法:对中序遍历进行修改,超出K1~K2的范围就不用继续递归了,可以理解为剪枝。
代码:
  1. /**
  2. * Definition of TreeNode:
  3. * class TreeNode {
  4. * public:
  5. *     int val;
  6. *     TreeNode *left, *right;
  7. *     TreeNode(int val) {
  8. *         this->val = val;
  9. *         this->left = this->right = NULL;
  10. *     }
  11. * }
  12. */
  13. class Solution {
  14. public:
  15.     /**
  16.      * @param root: The root of the binary search tree.
  17.      * @param k1 and k2: range k1 to k2.
  18.      * @return: Return all keys that k1<=key<=k2 in ascending order.
  19.      */
  20.     vector<int> searchRange(TreeNode* root, int k1, int k2) {
  21.         ans.clear();
  22.         ll = k1;
  23.         rr = k2;
  24.         
  25.         inorder(root);
  26.         return ans;
  27.     }
  28. private:
  29.     vector<int> ans;
  30.     int ll;
  31.     int rr;
  32.    
  33.     void inorder(TreeNode *root) {
  34.         if (root == NULL) {
  35.             return;
  36.         }
  37.         if (root->val > ll) {
  38.             inorder(root->left);
  39.         }
  40.         if (root->val >= ll && root->val <= rr) {
  41.             ans.push_back(root->val);
  42.         }
  43.         if (root->val < rr) {
  44.             inorder(root->right);
  45.         }
  46.     }
  47. };
复制代码
复杂度:时间基本还是O(N),对递归进行剪枝并不降低理论复杂度。空间也是O(N)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-18 16:55:08 | 只看该作者
全局:
Min Stack
题意:实现一个栈,除了普通栈的功能外,还能随时返回栈中的最小值。
解法:经典题目,用一个额外的栈维护最小值。每当遇到小于等于当前最小值的,就压入栈中。这个最小栈始终是单调的。
代码:
  1. #include <stack>
  2. using namespace std;

  3. class MinStack {
  4. public:
  5.     MinStack() {}

  6.     void push(int number) {
  7.         if (st.empty() || number <= mst.top()) {
  8.             mst.push(number);
  9.         }
  10.         st.push(number);
  11.     }

  12.     int pop() {
  13.         int val = st.top();
  14.         if (mst.top() == st.top()) {
  15.             mst.pop();
  16.         }
  17.         st.pop();
  18.         return val;
  19.     }

  20.     int min() {
  21.         return mst.top();
  22.     }
  23. private:
  24.     stack<int> st, mst;
  25. };
复制代码
复杂度:每个基本操作都是O(1)时间,维护一个最小栈需要额外O(N)空间。
回复

使用道具 举报

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

本版积分规则

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