【读书笔记】Cracking the Code Interview(第五版中文版)
导语
所有的编程练习都在牛客网OJ提交,链接: https://www.nowcoder.com/ta/cracking-the-coding-interview
第八章 面试考题
8.1 数组与字符串
1.1 实现一个算法,确定一个字符串的所有字符是否全都不相同。假设不允许使用额外的数据结构,又该如何处理?
题解:应该先clarify上面的字符串是 ASCII 还是 unicode,假设是 ASCII,我们可以直接用256个字母表来统计。用个vector<int> st(256, 0)即可。time complexity: O(N)
class Different {
public:
bool checkDifferent(string iniString) {
if (iniString.size() > ) {
return false;
}
vector<int> st(, );
for (int i = ; i < iniString.size(); ++i) {
if (st[iniString[i]]) {return false;}
st[iniString[i]] = ;
}
return true;
}
};
还可以sort之后,前后相邻的字符比较。time complexity: O(nlogn)
1.2 用C++实现void reverse(char* str) 函数,即反转一个null结尾的字符串。
题解:直接2 pointers。
class Reverse {
public:
string reverseString(string iniString) {
int n = iniString.size();
int i = , j = n-;
while (i < j) {
swap(iniString[i++], iniString[j--]);
}
return iniString;
}
};
1.3 给定两个字符串,请编写程序,确定其中一个字符串的字符重新排列之后,能够变成另外一个字符串。
题解:书上给的方法是用一个vector当作字母表,256个字符,统计频次,然后用第二个字符串去减掉。time complexty O(N+M)
也可以排序,或者用个map。
#include <unordered_map>
class Same {
public:
bool checkSam(string stringA, string stringB) {
const int n1 = stringA.size(), n2 = stringB.size();
if (n1 != n2) {return false;}
unordered_map<char, int> mp1;
for (auto& c : stringA) {
mp1[c]++;
}
for (auto& c : stringB) {
if (mp1.find(c) == mp1.end() || mp1[c] == ) {
return false;
}
mp1[c]--;
}
return true;
}
};
1.4 编写一个方法,将字符串中所有的空格都替换成”%20”。假设该字符串尾部有足够的空间存放新字符,并且知道字符串的真实长度。
题解:先统计空格数量,然后计算出新的总长度,然后从后往前一个一个移动处理。2 pass。
class Replacement {
public:
string replaceSpace(string iniString, int length) {
int cntSpace = ;
for (auto c : iniString) {
if (c == ' ') {
cntSpace++;
}
}
int newLen = cntSpace * + length;
string ret;
ret.resize(newLen);
int p2 = newLen - ;
for (int i = length-; i >= ; --i) {
if (iniString[i] == ' ') {
ret[p2--] = '';
ret[p2--] = '';
ret[p2--] = '%';
} else {
ret[p2--] = iniString[i];
}
}
return ret;
}
};
1.5 利用字符重复出现的次数,编写一个方法,实现基本的字符串压缩功能。比如,字符串“aabcccccaaa”会变成“a2b1c5a3”。若“压缩”后的字符串没有变短,则返回原先的字符串。
题解:2 pointers。time complexity: O(N), space complexity: O(N)
class Zipper {
public:
string zipString(string iniString) {
const int n = iniString.size();
string ret;
if (n == ) {return ret;}
int p1 = , p2= ;
while (p2 < n) {
while (p2 < n && iniString[p2] == iniString[p1]) {
p2++;
}
int cnt = p2 - p1;
ret += string(, iniString[p1]) + to_string(cnt);
p1 = p2;
}
return ret.size() < iniString.size() ? ret : iniString;
}
};
1.6 给定一幅由N*N矩阵表示的图像,其中每个像素的大小为4字节,编写一个方法,将图像旋转90度。不占用额外的内存空间能不能做到。48. Rotate Image
题解:转圈矩阵的通用解法。
class Transform {
public:
vector<vector<int> > transformImage(vector<vector<int> > mat, int n) {
int tr = , dr = n-, tc = , dc = n-;
while (tr < dr) {
rotate(mat, tr, dr, tc, dc);
tr++, dr--, tc++, dc--;
}
return mat;
}
void rotate(vector<vector<int>>& mat, int tr, int dr, int tc, int dc) {
int group = dr - tr;
for (int i = ; i < group; ++i) {
int temp = mat[tr][tc+i];
mat[tr][tc+i] = mat[dr-i][tc];
mat[dr-i][tc] = mat[dr][dc-i];
mat[dr][dc-i] = mat[tr+i][dc];
mat[tr+i][dc] = temp;
}
}
};
1.7 编写一个算法,若 M*N的矩阵中某个元素为0,则将其所在的行和列清零。73. Set Matrix Zeroes
题解:书上给的是两个 1D array 存放一行和一列是否为应该set 为0. row[i] = 0 代表第 i 行为 0, col[j] = 0 代表第 j 列为 0. time complexity: O(N*N), space complexity: O(N)
class Clearer {
public:
vector<vector<int> > clearZero(vector<vector<int> > mat, int n) {
vector<int> dp1(n, ), dp2(n, );
for (int i = ; i < n; ++i) {
for (int j = ; j < n; ++j) {
if (mat[i][j] == ) {
dp1[i] = dp2[j] = ;
}
}
}
for (int i = ; i < n; ++i) {
for (int j = ; j < n; ++j) {
if (dp1[i] == || dp2[j] == ) {
mat[i][j] = ;
}
}
}
return mat;
}
};
可以把空间压缩成O(1)的,使用两个变量标记第0行和第0列是否应该为0,然后用第0行和第0列代替上文中的row和col。
1.8 假定有一个方法 isSubstring, 可检查一个单词是否为其他字符串的子串。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成,要求只能调用一次isSubstring。(比如,waterbottle 是 erbottlewat旋转后的字符串)。
题解:假设 s2 是通过 s1 旋转过来的,那么我们可以找出旋转点在哪里。例如,若以 wat 对 waterbottle 旋转,就会得到 erbottlewat 。在旋转字符串的时候,我们会把 s1 切分为两个部分:x 和 y,并且将他们组合成 s2.
s1 = xy = waterbottle
x = wat
y = erbottle
s2 = yx = erbottlewat
因此,我们需要确认有没有办法将s1切分为x和y,以满足 xy = s1 和 yx = s2。 不论x和y之间的分割点在何处,我们会发现 yx 肯定是 xyxy 的子串。也就是 s2 总是 s1s1 的子串。
class ReverseEqual {
public:
bool checkReverseEqual(string s1, string s2) {
if (s1.size() != s2.size()) {return false;}
string s = s1 + s1;
return isSubstring(s, s2);
}
bool isSubstring(string s1, string s2) {
return s1.find(s2) != string::npos;
}
};
8.2 链表
基础知识:
1. 如何创建一个单向链表。
2. 删除单向链表中的结点
3. 快慢指针的技巧:用两个指针来迭代访问链表,其中一个比另外一个稍微超前一些。“快”指针往前先行几步,或者与慢指针相差固定的步数。举个例子===~~~~?
4. 可以递归。
题目:
2.1 编写代码,移除未排序链表中的重复结点。Follow-up: 如果不得使用临时缓冲区,应该怎么解决?
2.2 实现一个算法,找出单向链表中的倒数第 k 个结点。
2.3 实现一个算法,删除单向链表中间的某个结点,假设你只能访问该结点。
eg 输入:单向链表 a->b->c->d->e 中的结点 c。
输出:不返回任何数据,但是该链表变为 a->b->c->d->e
2.4 编写代码,以给定值x 为基准将链表拆分两个部分,所有小于 x 的结点排在大于等于 x 的结点之前。
2.5 给定两个用链表表示的整数,每个结点包含一个数位。这些数位是反向存放的,也就是个位排在链表首部。编写函数对这两个整数求和,并用链表的形式返回结果。
eg: input: (7->1->6) + (5->9->2) output: 2->1->9
Follow-up: 假设这些数是正向存放的,请在做一遍。
eg: input: (6->1->1) + (2->9->5) output: 9->1->2
2.6 给定一个有环的链表,实现一个算法返回环路的头结点。
2.7 编写一个链表,检查链表是否为回文。
8.3 栈和队列:
基础知识:
1. 实现一个栈
2. 实现一个队列
题目:
3.1 描述如何用一个数组实现三个栈
3.2 请设计一个栈,除了pop和push 的方法,还支持 min 的方法,可以返回栈中元素的最小值。Push, pop, min这三个方法的时间复杂度必须为O(1).
3.3 设想有一堆盘子,堆太高可能会倒下来。因此,在现实生活中,盘子堆到一定高度的时候,我们就会堆成另外一堆盘子。请实现数据结构 setOfStacks,模拟这种行为。setOfStacks应该由多个栈组成,并且在前一个栈填满时新建一个栈。此外,setOfStacks.push() 和 setOfStacks.pop() 应该和普通栈的操作方法相同(也就是说,pop()返回的值应该只和一个栈时的情况一样)。
Follow-up:实现一个popAt(int index)方法,根据指定的子栈,执行pop操作。
3.4 在经典问题汉诺塔中,有3根柱子和 N 个不同大小的穿孔圆盘,盘子可以滑入任意一根柱子。一开始,所有盘子自底向上从大到小依次套在第一根柱子上(即每一个盘子只能放在更大的盘子上面)。移动圆盘时有以下限制:
(1) 每次只能移动一个盘子
(2) 盘子只能从柱子顶端滑出移到下一根柱子
(3) 盘子只能叠在比它大的盘子上
请运用栈,编写程序将所有的盘子从第一根柱子移动到最后一根柱子。
3.5 实现一个 MyQueue 类,该类用两个栈来实现一个队列。
3.6 编写程序,按照升序对栈进行排序(最大的元素位于栈顶)。最多只能使用一个额外的栈来存放临时数据,但不得将元素复制到别的数据结构中(如数组)。该栈支持如下操作:push,pop,peek,和 isEmpty。
题解:我们假设有两个栈,s2是排序的,s1是未排序的。每次从s1中弹出一个数,插入到s2的合适位置。怎么做呢?我们先从s1中弹出一个数字num,保存在一个变量中,然后从把s2中比num大的元素都弹出来,放入s1中。然后把num放入s2,再把原来s2中的元素放回去。time complexity: O(N^2), space complexity: O(N)
class TwoStacks {
public:
vector<int> twoStacksSort(vector<int> numbers) {
stack<int> stk1, stk2;
for (int i = numbers.size() - ; i >= ; --i) {
stk1.push(numbers[i]);
}
while (!stk1.empty()) {
int num = stk1.top(); stk1.pop();
while (!stk2.empty() && stk2.top() > num) {
int temp = stk2.top(); stk2.pop();
stk1.push(temp);
}
stk2.push(num);
}
vector<int> ret;
while (!stk2.empty()) {
ret.push_back(stk2.top());
stk2.pop();
}
return ret;
}
};
3.7 有家动物收容所只收容狗和猫,并且按照严格“先进先出”的原则。在收养该收容所的动物时,收养人能够收养所有动物中“最老”(根据进入收容所的时间长短)的动物,或者,可以挑选猫和狗(同时必须收养此类动物中最老的)。换言之,收养人不能自由挑选想收养的对象。请创建适用于这个系统的数据结构,实现各种操作方法,比如enqueue, dequeueAny, dequeueDog, dequeueCat等。允许使用内置的linkedlist数据结构。
牛客网:有家动物收容所只收留猫和狗,但有特殊的收养规则,收养人有两种收养方式,第一种为直接收养所有动物中最早进入收容所的,第二种为选择收养的动物类型(猫或狗),并收养该种动物中最早进入收容所的。
给定一个操作序列int[][2] ope(C++中为vector<vector<int>>)代表所有事件。若第一个元素为1,则代表有动物进入收容所,第二个元素为动物的编号,正数代表狗,负数代表猫;若第一个元素为2,则代表有人收养动物,第二个元素若为0,则采取第一种收养方式,若为1,则指定收养狗,若为-1则指定收养猫。请按顺序返回收养的序列。若出现不合法的操作,即没有可以符合领养要求的动物,则将这次领养操作忽略。
树和图的基本概念
4.1 实现一个函数,检查二叉树是否平衡。在这个问题中,平衡树的定义如下:任意一个结点,其两颗子树的高度差不超过1.
4.2 给定有向图,设计一个算法,找出两个结点之间是否存在一条路径。
4.3 给定一个有序的整数数组,元素各不相同并且按照升序排列,编写一个算法,创建一棵高度最小的BST。
4.4 给定一棵二叉树,设计一个算法,创建含有某一深度上所有结点的链表。(比如,若一棵树的深度为D,则会创建出D个链表)
4.5 设计一个函数,检查一个二叉树是否为BST。
4.6 设计一个算法,找出BST中指定结点的下一个结点(中序后继)。可以假设每个结点都有指向父结点的链接。
4.7 设计并实现一个算法,找出二叉树中某两个结点的第一个公共祖先。不得将额外的结点存储在另外的数据结构中。注意:这不一定是BST。
4.8 你有两颗非常大的二叉树:T1,有几百万个结点;T2,有几百个结点。设计一个算法,判断T2是否为T1的subtree。如果说T1有这么一个结点n,其子树和T2一模一样,则T2为T1的子树。也就是说,从结点n处把树砍断,得到的树与T2完全相同。
4.9 给定一棵二叉树,其中每个结点都含有一个数值。设计一个算法,打印结点数值总和等于某个给定值的所有路径。注意,路径不一定非得从二叉树的根结点或者叶结点开始或结束。
数学和概率
7.1 有一个篮球框,下面两种玩法可以任选一种:
玩法1: 一次出手机会,投篮命中得分
玩法2: 三次出手机会,必须投中两次。
如果p是某次投篮命中的概率,则p的值为多少时,才会选择玩法1或者玩法2?
7.2 三角形的三个顶点上各有一只蚂蚁。如果蚂蚁开始沿着三角形的边爬行,两只或者三只蚂蚁撞在一起的概率多大?假设每只蚂蚁会随机选一个方向,每个方向被选到的几率相等,并且三只蚂蚁的爬行速度相同。类似问题:在 n 个顶点的多边形上有 n 只蚂蚁,求这些蚂蚁发生碰撞的概率。
7.3 给定直角坐标系上的两条线,判断这两条线会不会相交。
7.4 编写方法,实现整数的乘法,减法和除法运算。只允许使用加号。
7.5 在二维平面上,有两个正方形,请找出一条直线,能够将这两个正方形对半分。假定正方形的上下两条边与x轴平行。
7.6 在二维平面上,有一些点,请找出经过点数最多的那条线。
7.7 有些数的素因子只有3,5,7,请设计一个算法,找出其中第k个数。
【读书笔记】Cracking the Code Interview(第五版中文版)的更多相关文章
- Cracking the code interview
推荐一本书<Cracking the code interview> Now in the 5th edition, Cracking the Coding Interview gives ...
- 推荐《C Primer Plus(第五版)中文版》【worldsing笔记】
老外写的C书,看了你会有一种哇塞的感觉,这里提供PDF扫描版的下在,包含数内的例程,请大家支持原版!! C Primer Plus(第五版)中文版.pdf 下载地址:http://pan.bai ...
- 读书笔记 - js高级程序设计 - 第十五章 使用Canvas绘图
读书笔记 - js高级程序设计 - 第十三章 事件 canvas 具备绘图能力的2D上下文 及文本API 很多浏览器对WebGL的3D上下文支持还不够好 有时候即使浏览器支持,操作系统如果缺缺 ...
- 《java编程思想》读书笔记(一)开篇&第五章(1)
2017 ---新篇章 今天终于找到阅读<java编程思想>这本书方法了,表示打开了一个新世界. 第一章:对象导论 内容不多但也有20页,主要是对整本书的一个概括.因为已经有过完整JAV ...
- 读书笔记--C陷阱与缺陷(五)
第五章 第五章干货也偏少,但是几个练习题还不错,写出来大家分享下: 1.当一个程序异常终止时,程序输出的最后几行常常会丢失,原因是什么? 我们能够采取怎么样的措施来解决这个问题? 答:因为异常终止的程 ...
- 【读书笔记】C#高级编程 第五章 泛型
(一)泛型概述 泛型不仅是C#编程语言的一部分,而且与程序集中的IL代码紧密地集成.泛型不仅是C#语言的一种结构,而且是CLR定义的.有了泛型就可以创建独立于被包含类型的类和方法了. 1.性能 泛型的 ...
- 读书笔记_Effective_C++_条款四十五:运用成员函数模板接受所有兼容类型
比如有一个Base类和一个Derived类,像下面这样: class BaseClass {…}; class DerivedClass : public BaseClass {…}; 因为是父类与子 ...
- Cracking the Code Interview 4.3 Array to Binary Tree
Given a sorted (increasing order) array, write an algorithm to create a binary tree with minimal hei ...
- 读书笔记_Effective_C++_条款二十五: 考虑写出一个不抛出异常的swap函数
在之前的理论上调用对象的operator=是这样做的 void swap(A& x) { std::swap(a, x.a); } A& operator=(const A& ...
随机推荐
- 【leetcode】41. First Missing Positive
题目如下: 解题思路:这题看起来和[leetcode]448. Find All Numbers Disappeared in an Array很相似,但是有几点不同:一是本题的输入存在负数,二是没有 ...
- Windows系统安装教程
身边很多朋友电脑系统因为这样那样的问题不能开机,需要重装系统,但是又不知道从何下手.很不建议去电脑店重装系统,因为电脑店用的操作系统很多都有捆绑软件和主页捆绑,对电脑体验影响很坏.这篇教程只是针对新手 ...
- 04 全局配置,java 编意默认版本,1.6.修改配置
https://www.cnblogs.com/liu-s/p/5371289.html <!-- 修改Intellij Idea 创建maven项目默认Java编译版本 --> < ...
- GIS矢量大数据采集
1.使用什么工具采集 2.在哪个网站采集 3.采集哪一种数据 >>地理大数据公众号 >>大数据公众号 >>智能数据湖公众号 点.线.面.体 可视化 >> ...
- SQL中MINUS的用法与UNION的用法
一:MINUS指令 其是运用在两个 SQL 语句上.它先找出第一个 SQL 语句所产生的结果,然后看这些结果有没有在第二个 SQL语句的结果中.如果有的话,那第一个SQL结果数据就被去除,而不会在最后 ...
- jsplumb+dragable+vue(一)
基于vue的jsplumb,支持拖拽生成节点,节点双击展示更多信息,节点连线,删除节点,删除连线,重绘连接图,当前页面刷新连接图,根据json画连接图等功能 本章主要讲 拖拽生成节点 获取链接图的信息 ...
- python比C程序相比非常慢
w http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001374738136930 ...
- Spring cloud gateway自定义filter以及负载均衡
自定义全局filter package com.example.demo; import java.nio.charset.StandardCharsets; import org.apache.co ...
- [LeetCode] 4. Median of Two Sorted Arrays(想法题/求第k小的数)
传送门 Description There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the m ...
- SQL标量函数
调用 MS SQL 标量值函数,应该在函数前面加上 "dbo.",否则会报 “不是可以识别的 内置函数名称”错误.例如 DECLARE @WhichDB TINYINT; ...