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

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

 
🔗
 楼主| zhuli19901106 2015-7-24 07:36:23 | 只看该作者
全局:
本帖最后由 zhuli19901106 于 2015-7-24 07:38 编辑
水逼一枚 发表于 2015-7-24 06:01
我想问一下,像这个题还有类似的题目出现过的吗?就是利用HashMap左右延展来解题这类似的题目?这题想了 ...

用DP的前提是能知道“问题”与“子问题”之间的递推关系。这题并不存在和子问题的关联,所以DP无从说起。
另外,你说hashmap向两边延伸,感觉说的也太具体了吧。。不论hashmap还是map,各有各的特点,因为特点不同,所以用处就不同。并没有什么固定解法,规定一个数据结构一定要怎么用。

比如一个RMQ问题,就可以用好多数据结构来解。关键是,每种解法,写的人都清楚自己要怎么用一个数据结构。
你不妨试试building outline那题?看看什么数据结构好用。还有sliding window median。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-24 07:51:19 | 只看该作者
全局:
本帖最后由 zhuli19901106 于 2015-7-24 07:57 编辑
水逼一枚 发表于 2015-7-24 06:01
我想问一下,像这个题还有类似的题目出现过的吗?就是利用HashMap左右延展来解题这类似的题目?这题想了 ...

倒不是说hard题目都出现在数组上,只是因为数组和链表是最简单的数据结构,实现起来相对容易,所以面试考的尽是这些。要考其他的简直没法搞~
我们在这儿讨论的东西,专业选手们小学初中就已经会了。


回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-24 08:12:19 | 只看该作者
全局:
Interval Sum
题意:给定一个数组,每次给你起点终点的下标,求子数组和。
解法:这题的提示居然是用线段树做,实际上这题中数组的内容不会变,所以直接求和即可,没必要用线段树或者树状数组。
代码:
  1. typedef long long int LL;
  2. /**
  3. * Definition of Interval:
  4. * classs Interval {
  5. *     int start, end;
  6. *     Interval(int start, int end) {
  7. *         this->start = start;
  8. *         this->end = end;
  9. *     }
  10. */
  11. class Solution {
  12. public:
  13.     /**
  14.      *@param A, queries: Given an integer array and an query list
  15.      *@return: The result list
  16.      */
  17.     vector<LL> intervalSum(vector<int> &A, vector<Interval> &queries) {
  18.         vector<LL> sum;
  19.         int n = A.size();
  20.         sum.resize(n + 1, 0);
  21.         int i;
  22.         for (i = 0; i < n; ++i) {
  23.             sum[i + 1] = sum[i] + A[i];
  24.         }
  25.         vector<LL> ans;
  26.         int m = queries.size();
  27.         for (i = 0; i < m; ++i) {
  28.             ans.push_back(sum[queries[i].end + 1] - sum[queries[i].start]);
  29.         }
  30.         return ans;
  31.     }
  32. };
复制代码
复杂度:预处理时间O(N),每次求和时间O(1),空间O(N)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-24 08:16:03 | 只看该作者
全局:
Interval Sum II
题意:hard难度。给定一个数组,要求实现修改单个元素,子数组求和两个功能,复杂度都是O(log(N))。
解法:树状数组,此时不用更待何时。
代码:
  1. typedef long long int LL;
  2. class Solution {
  3. public:
  4.     /**
  5.      * @param A: An integer vector
  6.      */
  7.     Solution(vector<int> A) {
  8.         n = A.size();
  9.         a.resize(n + 1, 0);
  10.         int i;
  11.         for (i = 0; i < n; ++i) {
  12.             add(i + 1, A[i]);
  13.         }
  14.     }
  15.    
  16.     /**
  17.      * @param start, end: Indices
  18.      * @return: The sum from start to end
  19.      */
  20.     LL query(int start, int end) {
  21.         ++start;
  22.         ++end;
  23.         return sum(end) - sum(start - 1);
  24.     }
  25.    
  26.     /**
  27.      * @param index, value: modify A[index] to value.
  28.      */
  29.     void modify(int index, int value) {
  30.         int oldValue = query(index, index);
  31.         ++index;
  32.         add(index, value - oldValue);
  33.     }
  34. private:
  35.     vector<LL> a;
  36.     int n;
  37.    
  38.     int lowbit(int x) {
  39.         return x & -x;
  40.     }
  41.    
  42.     void add(int index, int value) {
  43.         while (index <= n) {
  44.             a[index] += value;
  45.             index += lowbit(index);
  46.         }
  47.     }
  48.    
  49.     LL sum(int index) {
  50.         LL s = 0;
  51.         while (index > 0) {
  52.             s += a[index];
  53.             index -= lowbit(index);
  54.         }
  55.         return s;
  56.     }
  57. };
复制代码
复杂度:单次操作时间O(log(N)),全局空间O(N)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-24 08:19:53 | 只看该作者
全局:
Segment Tree Query II
题意:其实还是区间求和,不过这次线段树已经建好了,实现求和函数。
解法:因为是教学题目,所以按照提示完成即可。
代码:
  1. /**
  2. * Definition of SegmentTreeNode:
  3. * class SegmentTreeNode {
  4. * public:
  5. *     int start, end, count;
  6. *     SegmentTreeNode *left, *right;
  7. *     SegmentTreeNode(int start, int end, int count) {
  8. *         this->start = start;
  9. *         this->end = end;
  10. *         this->count = count;
  11. *         this->left = this->right = NULL;
  12. *     }
  13. * }
  14. */
  15. typedef SegmentTreeNode STN;
  16. class Solution {
  17. public:
  18.     /**
  19.      *@param root, start, end: The root of segment tree and
  20.      *                         an segment / interval
  21.      *@return: The count number in the interval [start, end]
  22.      */
  23.     int query(STN *root, int start, int end) {
  24.         if (root == NULL) {
  25.             return 0;
  26.         }
  27.         if (start > root->end || end < root->start || start > end) {
  28.             return 0;
  29.         }
  30.         if (root->start == root->end) {
  31.             return root->count;
  32.         }
  33.         int mid = root->start + (root->end - root->start) / 2;
  34.         if (end <= mid) {
  35.             return query(root->left, start, end);
  36.         }
  37.         if (start >= mid + 1) {
  38.             return query(root->right, start, end);
  39.         }
  40.         int c1 = root->start == start ? root->left->count :
  41.                  query(root->left, start, mid);
  42.         int c2 = root->end == end ? root->right->count :
  43.                  query(root->right, mid + 1, end);
  44.         return c1 + c2;
  45.     }
  46. };
复制代码
复杂度:时间O(log(N)),空间O(log(N))。全局空间O(N * log(N))。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-24 17:54:26 | 只看该作者
全局:
First Missing Positive
题意:给定一个整数数组,求其中不包含的最小整数
解法:这题用哈希表肯定容易做,O(N)时间,O(N)空间。于是我们要想出O(1)空间的解法。注意,一个长度为N的数组,至多包含了1-N,那么解就是N+1。对于其他情况,解必然在1-N之间。所以我们直接用原数组当成哈希表来用。请看代码。
代码:
  1. class Solution {
  2. public:
  3.     /**   
  4.      * @param A: a vector of integers
  5.      * @return: an integer
  6.      */
  7.     int firstMissingPositive(vector<int> A) {
  8.         int n = A.size();
  9.         if (n == 0) {
  10.             return 1;
  11.         }
  12.         
  13.         int i;
  14.         for (i = 0; i < n; ++i) {
  15.             if (A[i] <= 0 || A[i] > n) {
  16.                 A[i] = n + 1;
  17.             }
  18.         }
  19.         for (i = 0; i < n; ++i) {
  20.             if (abs(A[i]) > n) {
  21.                 continue;
  22.             } else if (A[abs(A[i]) - 1] > 0) {
  23.                 A[abs(A[i]) - 1] *= -1;
  24.             }
  25.         }
  26.         for (i = 0; i < n; ++i) {
  27.             if (A[i] > 0) {
  28.                 return i + 1;
  29.             }
  30.         }
  31.         return n + 1;
  32.     }
  33. private:
  34.     int abs(int x) {
  35.         return x >= 0 ? x : -x;
  36.     }
  37. };
复制代码
复杂度:时间O(N),空间O(1)。
回复

使用道具 举报

🔗
caffery24 2015-7-24 20:44:55 | 只看该作者
全局:
给楼主赞一个啊。。。好羡慕楼主的意志力,楼主是研究生要毕业找工作吗?
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-24 22:44:12 | 只看该作者
全局:
caffery24 发表于 2015-7-24 20:44
给楼主赞一个啊。。。好羡慕楼主的意志力,楼主是研究生要毕业找工作吗?

不是,是研究生刚要开学~
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-25 00:00:58 | 只看该作者
全局:
本帖最后由 zhuli19901106 于 2015-7-25 00:02 编辑

Sliding Window Maximum
题意:hard难度。给定一个长度为N的数组,有一个宽度为K的滑动窗口,从头移到尾。每滑动一位,请给出窗口中的最大值。
解法:这题借助map的平衡树结构可以在logK时间内取得窗口最大值。不过这题自然有更优化的方法,就是单调队列。参见此题解http://blog.csdn.net/justmeh/article/details/5844650其中使用到的不是queue,而是deque,因为需要尾部入队,头尾出队的功能。
代码:
  1. #include <deque>
  2. using namespace std;

  3. class Solution {
  4. public:
  5.     /**
  6.      * @param nums: A list of integers.
  7.      * @return: The maximum number inside the window at each moving.
  8.      */
  9.     vector<int> maxSlidingWindow(vector<int> &nums, int k) {
  10.         d.clear();
  11.         vector<int> ans;
  12.         vector<int> &a = nums;
  13.         int n = a.size();
  14.         if (n == 0 || k == 0) {
  15.             return ans;
  16.         }
  17.         
  18.         int i;
  19.         for (i = 0; i < k - 1; ++i) {
  20.             enQueue(a, i, k);
  21.         }
  22.         for (i = k - 1; i < n; ++i) {
  23.             enQueue(a, i, k);
  24.             ans.push_back(a[d.front()]);
  25.         }
  26.         return ans;
  27.     }
  28. private:
  29.     deque<int> d;
  30.    
  31.     void enQueue(vector<int> &a, int i, int k) {
  32.         while (!d.empty() && i - d.front() >= k) {
  33.             d.pop_front();
  34.         }
  35.         while (!d.empty() && a[d.back()] < a[i]) {
  36.             d.pop_back();
  37.         }
  38.         d.push_back(i);
  39.     }
  40. };
复制代码
复杂度:时间O(N),空间O(K)。
回复

使用道具 举报

🔗
 楼主| zhuli19901106 2015-7-25 00:07:56 | 只看该作者
全局:
Trapping Rain Water
题意:给定类似直方图的形状,规定每条的宽度都是1。如果下雨的话,这形状能攒下多少水。
解法:这题挺好玩,第一次碰见的时候,我还想了好久如何找峰值、谷值,后来没想出好的思路。看了别人的思路后,才发现自己考虑问题的方式就错了。
关键思路在于把每一条分开想,如果左右都存在比它高的,那么这条就能存水,否则就存不了水。
代码:
  1. #include <algorithm>
  2. using namespace std;

  3. class Solution {
  4. public:
  5.     /**
  6.      * @param heights: a vector of integers
  7.      * @return: a integer
  8.      */
  9.     int trapRainWater(vector<int> &heights) {
  10.         int n = heights.size();
  11.         if (n == 0) {
  12.             return 0;
  13.         }
  14.         vector<int> ll, rr;
  15.         ll.resize(n);
  16.         rr.resize(n);
  17.         
  18.         int i;
  19.         int mx = 0;
  20.         for (i = 0; i <= n - 1; ++i) {
  21.             ll[i] = mx;
  22.             mx = max(mx, heights[i]);
  23.         }
  24.         mx = 0;
  25.         for (i = n - 1; i >= 0; --i) {
  26.             rr[i] = mx;
  27.             mx = max(mx, heights[i]);
  28.         }
  29.         
  30.         int ans = 0;
  31.         for (i = 0; i <= n - 1; ++i) {
  32.             mx = max(0, min(ll[i], rr[i]) - heights[i]);
  33.             ans += mx;
  34.         }
  35.         return ans;
  36.     }
  37. };
复制代码
复杂度:时间O(N),空间O(N)。
回复

使用道具 举报

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

本版积分规则

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