《程序员面试金典》
RayoNicks
这个作者很懒,什么都没留下…
展开
-
程序员面试金典(第六版)
从3月16日到8月2日,终于刷完了109题,因为之前的博客太多太分散,都整理在这里。原创 2020-08-09 13:47:25 · 2766 阅读 · 1 评论 -
程序员面试金典 17.26
Sparse Similarity:给定一些整数集合,计算集合之间的稀疏相似度。稀疏相似度定义为交集大小和并集大小的比值。假设有s个集合,每个集合中有n个整数。最简单的方式就是对于每一对集合,查找第一个集合中有多少元素在第二个集合中,这样就算出了交集的大小,最后根据容斥原理计算并集的大小即可。这种方法的时间复杂度为O(s ^ 2 * n ^ 2);如果查找过程用set,那么复杂度降为O(s ^ 2 * nlogn);如果查找过程用unordered_set,那么复杂度降为O(s ^ 2 * n)。根据题干原创 2020-08-02 17:12:51 · 254 阅读 · 0 评论 -
程序员面试金典 17.25
Word Rectangle:给定一个字典,使用字典中的单词组成一个最大的矩阵,该矩阵中每行和每列都是字典中的单词,单词可以重复使用。最喜欢这种题了,反正也没什么取巧的方法,直接搜索就好了,主要看代码能力。因为要返回最大的矩阵,所以我们从最大的边长开始,慢慢缩小搜索边长。返回类型为vector<string>,根据其特点,每次添加矩阵的一行较为方便,然后在新得到的部分矩阵中,去检查每一列是否是字典中单词的前缀即可。题解中的很多方法都是使用整个字典构建的Trie树,不过我感觉这样子不利于剪枝,原创 2020-08-02 14:27:25 · 232 阅读 · 0 评论 -
程序员面试金典 17.24
Max Submatrix:求矩阵中和最大的子矩阵。根据提示,先回顾下如何求最大子数组的和(16.17):只需要依次将数组中的元素进行累加,如果目前的累加和变大了,就进行更新,如果目前的累加和变成了负数,那么就将累加和重置为0,这样就在O(n)的时间内找到了最大子数租的和。如果能将某一个子矩阵压缩成一行,那么就可以用上面的方法进行计算了。假设要压缩的矩阵起始行为startRow,终止行为endRow,当求出了每一列的和之后,该矩阵就压缩为了一行,然后应用上面的方法,可以在O(r ^ 3 * c)的时间内原创 2020-08-01 22:09:49 · 150 阅读 · 0 评论 -
程序员面试金典 17.23
Max Square Matrix:矩阵中的元素只有0和1,找出一个最大的方阵,满足方阵四条边上的元素全为0。原创 2020-08-01 16:41:11 · 205 阅读 · 0 评论 -
程序员面试金典 17.22
Word Transformer:给定两个相同长度的单词,判断是否可以通过一系列的字母代换将一个单词转换为另一个,转换过程中的每个单词都应该出现在给定的字典中。这是一个在图中找路径的问题,最主要的是如何将输入转换为图,即找到字典中可以互相转换的单词。因为每次只能替换一个单词,所以可以根据每个单词抹掉一个字符后剩余的字符串对原始单词进行分组,这样就找到了可以互相转换的单词。第一次提交深搜方法超时了,是因为在DFS()返回后又将Visited[adj]设置为了false,这会导致后续搜索过程中再次搜索无效路原创 2020-08-01 13:39:37 · 204 阅读 · 0 评论 -
程序员面试金典 17.21
Volume of Histogram:直方图中每一列的宽度为1,计算直方图的盛水量。最高的一列将直方图分成了两部分,因此可以分别计算左右两部分的盛水量再求和,这样就将直方图分成了两部分,同时这一列变成了左边一部分的右边界,而左边最高的一列又将左边分成了两个小部分,靠右部分的盛水量由这一列和刚才确定的右边界决定,而靠左部分的盛水量由这一列作为右边界递归确定。不过上面的解法太复杂了。从题目中给的图来看,每一块的盛水量是由左边最高的和右边最高的这二者中较矮的决定的。class Solution {pub原创 2020-07-30 23:18:20 · 217 阅读 · 0 评论 -
程序员面试金典 17.20
Continuous Median:设计一个在线算法,可以实时计算输入流的中位数。根据中位数的定义,分为两种情况:当序列长度为偶数时,中位数是排序后最中间两个数的平均值当序列长度为奇数时,中位数是排序后最中间的值如果可以很快的得到最中间的两个值,那么就能很快地计算中位数,因此我们使用两个堆,一个最大堆,一个最小堆,最大堆保存左一半的元素,最小堆保存最右边的元素,这样在总长度为偶数时可以很快的计算中位数。当总长度为奇数时,只要一直维护右边比左边多一个或者左边比右边多一个的关系就好了。class原创 2020-07-30 19:50:15 · 167 阅读 · 0 评论 -
程序员面试金典 17.19
Missing Two:在含有n - 2个元素的非重复数组中,只包含[1, n]之间的值,在O(n)的时间和O(1)的空间复杂度下找出缺失的两个值。这应该是《编程之美》上的进阶题,可以通过找两个等式,然后解二元方程算出答案,不过好像有点复杂的样子。看了一下题解有了思路。如果数组是有序的,那么遍历一下就能找到缺失的元素了,所以要解决如何排序。因为题设保证了在有序时,num[i] == i + 1,所以可以把位置nums[i] - 1处的值和位置i处的值nums[i]交换,这样位置nums[i] - 1上的原创 2020-07-29 23:42:05 · 176 阅读 · 0 评论 -
程序员面试金典 17.18
Shortest Supersequence:在一个大数组big中找到一个子数组,该子数组包含所有在小数组small中的元素,顺序任意。暴搜法懒得写了:对于big的每一个起始位置,在后面查找最近的每一个smalls中的元素,最后返回最短的区间就可以了,看着十万的数据量,不超时就怪了。...原创 2020-07-26 14:50:24 · 149 阅读 · 0 评论 -
程序员面试金典 17.17
Multi Search:给定一个长字符串big和若干个短字符串smalls,查找smalls中每个字符串在和big中匹配的所有位置。class Solution {private: struct TrieNode { array<shared_ptr<TrieNode>, 26> Children; array<size_t, 26> Positions; char ch; TrieNo原创 2020-07-25 13:56:45 · 197 阅读 · 0 评论 -
程序员面试金典 17.16
The Masseuse:原创 2020-07-23 19:45:10 · 166 阅读 · 0 评论 -
程序员面试金典 17.15
Longest Word:原创 2020-07-23 12:27:51 · 176 阅读 · 0 评论 -
程序员面试金典 17.14
Smallest K:查找数组中最小的k个数。原创 2020-07-22 12:57:54 · 151 阅读 · 0 评论 -
程序员面试金典 17.13
Re-Space:给定一个字典和一个句子,根据字典将句子进行拆分,使得最终不在字典中的字母数量最少。最暴力的方法就是依次尝试在每个可能的地方插入空格,最终选取最优解,时间复杂度为O(2 ^ n),n为句子sentence的长度,从输入数据规模来看,会达到2 ^ 1000,所以需要使用记忆化的搜索来进行优化。虽然通过了所有的71个测试用例,但是依然超时了,但是当我把dict的类型从set<string>换成unordered_set<string>后,就过了,我只能说太蠢了。cl原创 2020-07-22 12:36:56 · 201 阅读 · 0 评论 -
程序员面试金典 17.12
BiNode:将一棵二叉搜索树转换为单链表,规则为左子树构成的单链表->根节点->右子树构成的单链表。无论是书上还是力扣上的描述,都不是很容易看懂的样子,这是我过了之后自己的理解。书上要求是双链表,而力扣上是单链表,如果按照双链表做就会出栈溢出。/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right;原创 2020-07-19 14:49:51 · 180 阅读 · 0 评论 -
程序员面试金典 17.11
Word Distance:在一个文本文件中,查找两个给定单词的最短距离。只需要对文件扫描一次即可。假如已经知道了两个单词的第一次出现的位置,假设为Word1LastLocation和Word2LastLocation,并有Word1LastLocation < Word2LastLocation,当从Word2LastLocation继续向右扫描时:如果再次遇到了word1,可以根据新老距离计算最小距离,同时更新Word1LastLocation,因为后面再次遇到word2时,这个距离肯定会更原创 2020-07-19 10:46:48 · 207 阅读 · 0 评论 -
程序员面试金典 17.10
Majority Element:找出数组中出现次数大于一半的元素,如果没有则返回-1。O(n ^ 2)的方法肯定是可解的,因为力扣标的简单题所以我就试了试,呵呵,超时了 ????????????所以我又换了map,这回就过了。class Solution {public: int majorityElement(vector<int>& nums) { map<int, size_t> Freq; for(int n : nu原创 2020-07-18 23:16:52 · 162 阅读 · 0 评论 -
程序员面试金典 17.9
Kth Multiple:求第k个只包含3、5或者7这三个素因子的数。根据输入k,结果肯定小于3 ^ k * 5 ^ k * 7 ^ k,所以可以把k ^ 3个数都求出来,然后返回下标为k - 1的元素。但是这方法显然不行啊,乘着乘着就溢出了。另一种方法就是每次将已获得的最小元素分别乘这三个质数,然后加入到备选集中,每次从备选集中取出最小的加入结果集,备选集可以使用集合或者优先队列。使用集合不需要手动判重,优先队列需要手动去重。class Solution {public: int getK原创 2020-07-18 22:11:48 · 167 阅读 · 0 评论 -
程序员面试金典 17.8
Circus Tower:class Solution {private: struct Person { int height, weight; Person(const int h, const int w) : height(h), weight(w){} bool operator<(const Person &p2) { if(height < p2.height) re原创 2020-07-18 16:17:14 · 174 阅读 · 0 评论 -
程序员面试金典 17.7
Baby Names:class Solution {private: vector<string> Names; map<string, size_t> Name2Idx; vector<int> Freqs; map<string, string> Syn; void transformInput(const vector<string> &names, const vector<str原创 2020-07-18 14:50:28 · 166 阅读 · 0 评论 -
程序员面试金典 17.6
Count of 2s:计算[0, n]中数字2出现的个数。class Solution {public: int numberOf2sInRange(int n) { int remain, quotient, cnt = 0, base = 1; while(n != 0){ quotient = n / 10; remain = n % 10; if(remain > 2){原创 2020-07-14 23:23:55 · 173 阅读 · 0 评论 -
程序员面试金典 17.5
Letters and Numbers:给定一个包含字母和数字的数组,求包含相同个数字母和数字的最长子数组。class Solution {public: vector<string> findLongestSubarray(vector<string>& arr) { unordered_map<int, int> FirstIndex; FirstIndex[0] = -1; int delta =原创 2020-07-14 23:12:08 · 236 阅读 · 0 评论 -
程序员面试金典 17.4
Missing Number:从[1, n]中找出缺失的一个数。这道题应该是微软的面试题,我在《编程之美》中看过,该题的另外一个限制就是只能访问二进制位,但是力扣上没有限制,所以就变成了简单题——利用求和公式算出的结果和数组和的差值就是缺失的数。class Solution {public: int missingNumber(vector<int>& nums) { int sum = accumulate(nums.begin(), nums.end()原创 2020-07-14 23:06:46 · 239 阅读 · 0 评论 -
程序员面试金典 17.1
Add Without Plus:不使用加法完成加法运算。根据手工计算加法的过程,先计算个位,再计算十位及个位的进位,以此类推,但是这个过程其实可以拆分:先计算不带进位的加法,然后将结果和只包含进位的数字再进行不带进位加法,以此类推得到最终的结果。对于二进制,不带进位加法就是异或,只包含进位的加法就是与运算左移1位。力扣上依旧会出现移位溢出崩溃的情形,难道移一下会死 ????????????class Solution {public: int add(int a, int b) {原创 2020-07-12 22:12:52 · 138 阅读 · 0 评论 -
程序员面试金典 16.26
Calculator:实现一个计算器,计算只包含数字和加、减、乘、除运算的表达式(在力扣上,运算符两侧可能有空格)。因为表达式中不包含空格,类似语法分析,可以把表达式拆分为项表达式(Term),项中包含运算符和操作数,然后依次计算即可。每扫描到一项,如果后一项是乘法或者除法,根据运算符的优先级,应该暂时将这一项应用到临时的计算结果processing中,待乘除法计算完毕后再应用到最终结果result中。书中采用的是将扫描项应用到processing中,根据后一项的运算符决定是否应用到result中,注意原创 2020-07-12 10:26:59 · 229 阅读 · 0 评论 -
程序员面试金典 16.25
LRU Cache:设计并实现一个LRU的缓存。为了较快的命中缓存,一般对键值key进行散列运算,但是找到最近最少使用项需要O(N)的时间。为了较快的找到最近最少使用项,可以基于最近使用的频率,对缓存行进行排序,但是这又导致无法快速找到某一缓存行。所以我们应该同时使用上述两种数据结构,使用链表将缓存行串起来,同时利用散列表进行查找。当缓存满时,剔除链表中最后的一项,每当访问或者添加新的缓存行时,将命中项移动到链表头部。class LRUCache {private: struct Cache原创 2020-07-11 17:50:19 · 185 阅读 · 0 评论 -
程序员面试金典 16.24
Pairs with Sum:原创 2020-07-10 23:50:59 · 762 阅读 · 0 评论 -
程序员面试金典 16.22
Langton’s Ant:原创 2020-07-10 23:09:04 · 223 阅读 · 0 评论 -
程序员面试金典 16.21
Sum Swap:给定两个数组,从每个数组中取出一个元素,使得交换这两个元素后,两数组和相等。最简单的方法就是暴力枚举,时间复杂度为O(AB),其中A和B分别表示数组大小。写代码之前看了下测试用例的范围,数组大小上限为100000,估计肯定会超时的,果不其然。class Solution {public: vector<int> findSwapValues(vector<int>& array1, vector<int>& array2)原创 2020-07-07 23:15:26 · 190 阅读 · 0 评论 -
程序员面试金典 16.20
T9:给定T9键盘的按键顺序,求所以可以得到的字典中的单词。最暴力的方法是建立键盘数字到字母的映射,然后深搜,时间复杂度为O(4 ^ n),其中n为num的长度,提交了一下,超时了,所以应该提前打好表,直接返回即可。class Solution {private: vector<char> KeyBoard = { '2', '2', '2', '3', '3', '3', '4', '4', '4', '5', '原创 2020-07-06 19:11:59 · 236 阅读 · 0 评论 -
程序员面试金典 16.19
Pond Sizes:class Solution {public: vector<int> pondSizes(vector<vector<int>>& land) { vector<int> sizes; Visited.assign(land.size(), vector<bool>(land[0].size(), false)); for(size_t r = 0; r &原创 2020-07-03 23:23:57 · 3229 阅读 · 0 评论 -
程序员面试金典 16.18
Pattern Matching:给定模式串和一个字符串,模式串中只包含a和b,判断字符串是否和模式串匹配。首先要明确模式串中只有a和b,原创 2020-07-03 11:47:53 · 179 阅读 · 0 评论 -
程序员面试金典 16.17
Contiguous Sequence:求数组中子序列的最大和。如果将相邻的正负数合并求和,那么就得到了一个正负数相间的序列。接下来考察每一个元素:如果累加和加上当前元素后依然是正数,那么和后面的正数求和后一定会更大,最大和子序列可以包括这个元素如果累加和加上当前元素后是负数,那么和后面的正数求和后一定更小,所以最大子序列和不应该包括这个元素这种方法对于未合并之前的数组也适用,注意在力扣上,空数组要返回int的最小值,全负数组返回数组中最大值。class Solution {public:原创 2020-06-30 23:18:08 · 224 阅读 · 0 评论 -
程序员面试金典 16.16
Sub Sort:在整数数组中求出一个最小区间[m, n],满足将该区间内的数据升序排序后,整个数组都升序。class Solution {public: vector<int> subSort(vector<int>& vec) { if(vec.empty()) return {-1, -1}; size_t b = 1, e = vec.size() - 1; while(b < vec.size()){原创 2020-06-30 23:09:46 · 182 阅读 · 0 评论 -
程序员面试金典 16.15
Master Mind:根据答案solution以及猜测guess,判断猜中和伪猜中的数量。先计算猜中,同时统计未猜中的频次,最后根据频次统计伪猜中。class Solution {public: vector<int> masterMind(string solution, string guess) { vector<int> ans(2, 0); map<char, int> m; for(size_t原创 2020-06-27 15:09:06 · 192 阅读 · 0 评论 -
程序员面试金典 16.14
Best Line:给定平面上n个点,找出一条直线,使其通过的点数最多。书上的解法:求出两两相连后的斜率,平行线归为一类,在平行线中找重合的直线。由于浮点数误差的关系,斜率差值小于epsilon的也算做平行线。我先把书上的写法用C++提交了一遍,60个测试用例过了54个,第55个超时了。class Solution { static bool equal(const double d1, const double d2) { return abs(d1 - d2) &l原创 2020-06-27 14:36:03 · 246 阅读 · 0 评论 -
程序员面试金典 16.13
Bisect Squares:给定两个正方形和一个二维平面,求一条平分两个正方形的最长线段,如果有多条线段,返回斜率最大的一条的两端点。这条线段肯定过这两个正方形的中心,根据这两个中心确定一条直线,然后求4个交点,选择最远的两个就好了。注意斜率为无穷大的问题,以及交点的求法。如果斜率在[-1, 1]之间,则交于正方形左右两边,如果斜率在[-∞, -1] ∪ [1, +∞],则交于正方形上下两边。class Solution { const double EPS = 1e-6; stru原创 2020-06-26 15:24:08 · 166 阅读 · 0 评论 -
程序员面试金典 16.11
Diving Board:求使用k块长度为shorter和longer的木板能组成的所有木板长度。因为有k块木板,要做k次决策,每一次有两种选择方法,根据这个思路可以写一个递归程序,时间复杂度为O(2 ^ k),力扣上测试用例[1, 1, 100000]会超时,代码就不贴了。既然超时了,那可以试试记忆化搜索,去掉一些重复计算,如果当前长度和剩余木板数量出现过,则直接跳过后面的枚举。我照着书上写了一遍,上面的例子确实过了,但是测试用例[136, 9225, 959]的又超时了。“在考察这道题的复杂度时,原创 2020-06-26 12:21:01 · 172 阅读 · 0 评论 -
程序员面试金典 16.10
Living People:给定一些人的出生年份和死亡年份,计算哪一年活着的人数最多,相同情况下输出年份最小的,假设年份都在[1900, 2000]。简单的解法就是暴力搜索,反正就100年,时间复杂度为O(RP),其中R表示年份的区间,P表示人数。class Solution {public: int maxAliveYear(vector<int>& birth, vector<int>& death) { int maxLive =原创 2020-06-25 21:49:40 · 1793 阅读 · 0 评论