Lintcode题目总结
Posted xero10
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Lintcode题目总结相关的知识,希望对你有一定的参考价值。
方法技巧题:
Complete Binary Tree: http://www.lintcode.com/en/problem/complete-binary-tree/
用一个queue进行层序遍历,如果q.front()为NULL,则pop并break,否则将其左右儿子加入queue。然后检查queue中剩余的元素,如果全是NULL则返回true,否则返回false
Stack Sorting: http://www.lintcode.com/en/problem/stack-sorting/
用另一个stack名为s。在!stk.empty()时,如果s为空或stk.top() <= s.top()则将stk中的元素pop出并加入s;否则令value = stk.top(),令stk进行pop但并不加入s,然后在!s.empty() && s.top() <= value时将s中的元素pop并加入stk,然后将value加入stk,再将s中剩余的元素pop并加入stk。最后再将s中的元素pop并加入stk即可
Reverse Pairs: http://www.lintcode.com/en/problem/reverse-pairs/
用divide & conquer + merge sort,将数组分成两部分分别排序,然后再merge,令用 i 遍历前半部分,j 遍历后半部分,如果nums[i] > nums[j],则nums[j]一定小于前半部分剩下的所有元素(包括 i),所以此时result += mid - i + 1
Swap Two Nodes in Linked List: http://www.lintcode.com/en/problem/swap-two-nodes-in-linked-list/
要注意特殊判断一下两个节点相邻的情况。只要保证这种情况下pre1在pre2前面即可
LFU Cache: http://www.lintcode.com/en/problem/lfu-cache/
用unordered_map + map + doubly linked list:
1)unordered_map<int, ListNode*> hash:存储key和对应双向链表节点的对应关系
2)map<int, cacheNode*> freq:int型变量是一个cache被访问的次数,cacheNode是一个新的struct,里面只有两个变量:ListNode *head, *newest,分别存储某个固定访问次数的所有cache,head->next是最旧的。注意这里的第二个元素必须用指针
具体的算法是:
set:首先判断如果要加入新的key是否会超出capacity,如果超出则将freq中第一个元素最老的cache删除;然后检查要set的key是否存在,如果已存在则将其从原来freq对应的双向链表中移出,但并不删除这个节点,只是将其frequency++,如果不存在则创建新的节点;最后将更改/新创建的节点加入到freq中正确的出现次数对应的位置。需要注意两点:a) 在从双向链表中移出节点时,要判断cur->next是不是空,不为空才更新cur->next->prev;b) 如果当双向链表移出某个节点后head = newest,则说明当前出现次数下没有对应的cache了,此时应该将对应的cacheNode*进行delete并从freq中erase
get:如果hash中不存在key则返回-1,否则将对应节点从双向链表中移出并将其出现次数+1再插入到合适的位置
注意在定义ListNode时要包括key,val和frequency,其中包括key是为了在从双向链表中删除某个元素时能够从hash中也进行erase,frequency是为了保证将某个节点从双向链表中移出时能对出现次数+1以找到它新的合适的位置。另外注意在destructor中对动态分配的变量进行释放。对于所有的操作,由于不需要进行查找,所以时间复杂度都是O(1)
Dynamic Programming:
Coins In a Line II: http://www.lintcode.com/en/problem/coins-in-a-line-ii/
用dp[i]表示从 i 到最后一个硬币,某个玩家所能获得的最大和。则对于dp[i]:
1)如果当前玩家取一个,则另一个玩家可能取一个或两个:val1 = values[i] + min(dp[i + 2], dp[i + 3])
2)如果当前玩家取两个,则另一个玩家可能取一个或两个:val2 = values[i] + values[i + 1] + min(dp[i + 3], dp[i + 4])
dp[i] = max(val1, val2)
最后再返回dp[0] > total - dp[0]即可。total和dp[i]的计算可以在一个for循环中完成
Backpack: http://www.lintcode.com/en/problem/backpack/
声明一个二维vector<vector<bool>> (size + 1, vector<bool>(bag + 1, false))名为can,can[i + 1][j]表示用了前 i 个元素后能否获得值 j,则can[i + 1][j] = can[i][j] || (j >= items[i] && can[i][j - items[i]]),最后再返回 j 从大到小第一个can[size][j]为true时的 j 即可。注意初始化can[i][0] = true。另外空间复杂度可以优化为O(bag),只要声明两个一维的vector即可,初始化时令[0] = true即可
Copy Books: http://www.lintcode.com/en/problem/copy-books/
O(k *n^2):最多只需要书的本数的人,所以k = min(size, k)。用dp[i][j]表示前 i 本书分给 j 个人时的最小值,计算从第 i 本([i - 1])到前面第一本,如果都给第 j 个人所能获得的最小值,这里面最小的那个就是结果,即dp[i][j] = min(dp[i][j], max(sum, dp[l][j - 1])),其中sum是[l] ~ [i - 1]的和。注意初始化:1)当 i = 0即没有书时,dp[0][j] = 0;2)当只有一个人时,dp[i][1]应该等于前 i 本书的和。初始化完成后,令 j = 2 ~ k即可
O(k * n):仍然用dp[i][j]表示前 i 本书分给前 j 个人时的结果,初始化dp[0][i]和dp[i][1],令 i = 2 ~ k,对于每个 i 计算dp[right][i]的值,令left = 0,right = 1,在right <= size时,令sum = dp[right][1] - dp[left][1]表示从pages[left + 1]到pages[right]的和,则dp[right][i] = min(dp[right][i], max(sum, dp[left][i - 1]))。因为随着left的增加,dp[left][i - 1]会增加而sum会减少,所以如果left < right && sum > dp[left][i - 1],则令left++;否则令right++,此外因为当前的left是invalid的,而之前的left是valid,所以应该令left--。最后返回dp[size][k]即可
以上是关于Lintcode题目总结的主要内容,如果未能解决你的问题,请参考以下文章