ARTS挑战第二周

第二周

为了准备春招疯狂刷题中,所以algorithm这块内容比较多。

Algorithm

  • 752. 打开转盘锁 BFS框架解就好。每一步都有8种选择,即四个位置向上或者向下调整。在入队列时判断是否在visited集合中,不在则加入visited集合。然后对于死亡数字,也加入set中,开始就要判断死亡数字里是否包含target,包含的话直接返回-1。然后对于出队列的元素,也要判断是否在死亡数字中,在的话就跳过这个数字。
  • 773. 滑动谜题 使用bfs进行遍历,二维数组不好操作与比较,最好转化成一维字符串进行比较,由于固定6个格子,每个格子的邻居都可以直接算出来。
  • 172. 阶乘后的零 统计1~n所有数进行因子分解后,能拆除多少个5. 0是由2*5组成,即使末尾为0的数也可以分解出2和5.而2只要是偶数都能分解出来,因此够用,主要统计因子5的数量。先统计出能贡献1个因子的数的数量,再统计出能贡献出两个5的数的数量,以此类推。
  • 793. 阶乘函数后 K 个零 使用函数f统计n!后面的零,然后使用二分搜索在0到一个很大值之间做二分搜索寻找左右边界。需要注意的是,那个寻找左右边界的模板,如果要找的不存在,则应该返回-1。这里直接返回的时候,左边界右边界都是指要插入的位置,左边界的话,插入后对应元素往右移。右边界的话,插入后对应元素全部往左移。因此如果元素不存在,左边界=右边界+1。从而右边界-左边界=-1. 函数最终返回结果为右边界-左边界+1。当不存在时会返回0.
  • 204. 计数质数 使用埃氏筛算法,用长为n的一个bool数组标记当前数是否为素数,默认值为true。然后从2开始,直到sqrt(n),查看当前数是否是素数,如果是,则从i*i开始,步长为i,将后面的数字标记为false。最后从2开始统计bool数组中1的数字。
  • 652. 寻找重复的子树 重要的是如何比较两棵子树:序列化子树,这个过程需要后序遍历,因为直到左子树和右子树的序列化字符串才能直到以当前节点为根节点的序列化字符串。 然后用全局变量来记录出现过的序列化字符串,并且次形成后进行对比
  • 面试题34. 二叉树中和为某一值的路径 回溯法。参数:root,trace,target。终止条件,当前节点已经是叶节点,如果target=0,则trace加入结果集。选择:这里都是选择把左子节点放入,或者把右子节点放入,因此对于根节点,这个逻辑不成立,必须事先加入trace。target减去trace中的和递归。
  • 124. 二叉树中的最大路径和 这题是hard难度,但是面试阿里,因为时间不够竟然让我口头做这题,当场吐血。这题由于是树的题目,肯定还是dfs。首先,根据问题的定义,路径可能带拐弯,因此不能直接根据左右子树的结果直接算出根节点的结果。所以需要一个辅助函数,它用来计算以root节点为根节点的,单边路径最大和。并且在算出左右子树单边最大和后,也顺便算下经过root节点的最大带拐的路径和,然后用一个全局最大值来记录下。题目代码量不大,主要这个题目不够直接,需要转换下思路。
  • 230. 二叉搜索树中第K小的元素 中序遍历,使用全局变量记录当前节点的rank值,如果相等就用全局变量res记录结果。最后返回res
  • 538. 把二叉搜索树转换为累加树 中序遍历,先右子树再左子树,使用全局变量记录当前累加值,然后root值更改为累加值,此题同1038. 把二叉搜索树转换为累加树
  • 98. 验证二叉搜索树 仅仅比较当前节点与左右子树的根节点是不够的,必须保证左子树的所有值小于当前根节点的值,而有子树的所有值大于当前节点的值。 有三种解法:(1)可以将每棵树的值区间范围给传递下去,确保根节点都在区间范围内。因为题目测试用例会使用INT_MAX测试,这里传递初始边界时,用LLONG_MAX和LLONG_MIN。(2)对于每个节点,它需要大于左子树最右边节点,小于右子树最左边节点(3)中序遍历是递增数组。
  • 701. 二叉搜索树中的插入操作 定义,将值插入以root为根节点的树中. 根节点为空的情况,则新建节点返回,否则比较与当前节点的值,大于则插入右子树,小于则插入左子树
  • 700. 二叉搜索树中的搜索
  • 450. 删除二叉搜索树中的节点 根节点为空的情况,说明没找到,不需要删,直接返回nullptr; 根节点的值大于key,则去左子树里删,由于函数返回删除后的树的根节点,root的左子树原来根节点可能换了,root需要更新左子树;反之亦然; 根节点的值等于key,说明这个要被删了,有四种情况,最简单的是根节点没有左右子树或只有单棵子树,则直接返回空或单棵子树根节点. 还有一种是同时拥有左右子树,这时候需要找到左子树最大的节点或者右子树最小的节点来顶替根节点,然后递归删除顶替节点的值。
  • 297. 二叉树的序列化与反序列化 这题比较难,序列化使用后序遍历,这个是固定套路。而反序列化,使用深度优先遍历的方式,无论是序列化成前序序列还是后序序列,都是使用前序遍历完成反序列化。在做反序列化之前,首先将字符串切割成数组,这里如果使用c++则要自己实现splitstring函数了。并且,使用一个全局指针指向当前遍历到的位置。
  • 341. 扁平化嵌套列表迭代器 这里在flatten单个NestedInteger的时候,可以使用深度优先的思想,类似深度优先遍历多叉树的思想. 因为每次都会先调用hasNext函数,因此在hasNext函数中,展开list中最前面的NestInteger,并放入队列中. 在next函数中,直接从队列前面拿,然后删掉队列的元素. 从而实现惰性运算.
  • 236. 二叉树的最近公共祖先 难点在于如何定义这个递归函数定义,变量,以及如何使用递归返回值. 一个误区就是: 虽然函数的输入保证树中一定包含p和q,但是在递归的中间过程中,此情形不一定成立。 定义: 函数返回的是什么? 如果root为根的树同时包含p和q,则返回最近公共祖先;如果只包含一个,则返回包含的那个节点;如果两个都不包含,则返回null。 变量,root, base case : root== nullptr 或者root == p 或者 root == q ,返回root. 如何处理返回值: 如果 left == null && right == null, 返回nullptr; 如果left==nullptr , return right; right ==null, return left; 否则返回root。 使用的是后序遍历的方式:只有先知道左右子树的情况,才能处理当前的根节点
  • 146. LRU 缓存机制 注意两点:1. Node里面要有key和val,只有value无法删除hashtable元素。2. 记得删除插入的时候hashtable的操作
  • 46. 全排列 backtrack 算法,函数参数:原数组,trace。终止条件:当trace的大小等于数组大小时加入结果集。做选择:在所有没用过的数中选择一个,加入trace,并DFS遍历,函数返回时从trace中拿掉。可优化的点:由于结果和原数组长度一样,直接在原数组上操作,将原数组分为两部分,前半部分表示已经放好了,后半部分表示还没有放好。函数参数中加入下标cur表示当前需要放哪个位置。例如[1,2,|3,4,5],cur=2,正在放第3个位置的数,如果想把4放入第三个位置,可以交换两个元素,然后回溯时再交换回来
  • 51. N 皇后 backtrack算法,函数参数:trace(即棋盘),n(当前所在的行下标)。终止条件:当n==棋盘行数时,加入结果集并返回。做选择:当前行的每一列都是可选项,需要一个函数判断在当前位置放置是否合法。选择放置则可以将对位置置成Q,撤销选择置成‘.’。注意如何初始化一个定长string,可以调用其fill constructor
  • 78. 子集 函数参数:nums,trace,start。终止条件:当start==nums.size()。做选择:从start到数组末尾,选择其中一个加入当前trace,并直接加入结果集。撤销选择:从trace中将该元素移除。
  • 77. 组合 函数参数,nums, trace, start,k .终止条件,k==0,即没有空位了,并将结果加入集合。做选择,从start开始到末尾,选择一个元素加入trace。
  • 22. 括号生成 函数参数:n(括号对数*2),trace,start,left(当前未配对的左括号数量)。终止条件:start=n,如果left=0,则将trace加入结果集。做选择:如果left<n/2 ,则可以将trace的当前位置设为‘(’,然后继续递归,start+1,left+1。如果left>0,则可以将trace当前位置设为‘)’,然后继续递归,start+1,left-1。
  • 37. 解数独 函数参数:board(本身也是trace),row,col(当前访问的坐标)。终止条件:row=9。当col=9时,递归遍历下一行。由于部分位置已经有数并且不能改,碰到非‘.’就直接递归下一列。做选择:可以看成每一格选哪个数字的问题,如果数字合法 ,则board位值设为这个数字,并递归下一列。根据函数返回值进行剪枝,因为只要得到一个解就行。
  • 99. 恢复二叉搜索树这题简单的做法先中序遍历拿到序列,排序后,再中序遍历用序列值覆盖原来的值。但是空间复杂度是O(n),对于空间复杂度O(1)的算法。需要找到两个异常节点,然后交换它们的值。例如1324,异常点是3和2。需要先用lvr算法找到3,再用rvl算法找到2.这里需要注意两个方面,就是记录上一个节点必须用全局变量或者引用参数不断改变它的值,然后就是记录最终结果也需要一个全局变量或者引用参数。一共需要4个全局变量。
  • 191. 位1的个数 利用n&(n-1) 消除二进制表示的最后一个1,直到n=0.统计循环执行的次数
  • 231. 2的幂 (1)利用n&(n-1)统计数字二进制表示1的个数,如果个数大于1,则不是。另外,非正整数 也不是;(2)第二种解法更优,使用 x&(-x)取得最右边第一个二进制位,例如 x=6, 则 x&(-x)=2,由于2的幂只存在一个1,因此判断x&(-x) == x 即可。

一些练手题目:

Review

Indexes When to Use and When to Avoid In SQL.
什么时候避免创建索引:

  1. 列被频繁更新
  2. 列的基数很小(distinct count 很小)
  3. lie存在很多none

Know the Differences between TRUNCATE, DELETE, and DROP

  1. DROP和TRUNCATE都是DDL,DELETE是DML
  2. DELETE使用行锁,每删一行都要写log,可以回滚,很慢
  3. DROP和TRUNCATE 只有一条log,不能回滚,很快
  4. TRUNCATE 不删表,只删数据;DROP 删整个表

Tips

  1. c++字符串分割
void SplitString(const std::string& s, std::vector<std::string>& v, const std::string& c)
{
  std::string::size_type pos1, pos2;
  pos2 = s.find(c);
  pos1 = 0;
  while(std::string::npos != pos2)
  {
    v.push_back(s.substr(pos1, pos2-pos1));
 
    pos1 = pos2 + c.size();
    pos2 = s.find(c, pos1);
  }
  if(pos1 != s.length())
    v.push_back(s.substr(pos1));
}
  1. c++ 不想使用编译器自动提供的拷贝构造函数或者赋值函数,可以将他们声明为private并且不实现。也可以集成一个Uncopyable这样的class
class Uncopyable{
private:
	Uncopyable(const Uncopyable&);
	Uncopyable & operator=(const Uncopyable&);
public:
Uncopyable(){};
~Uncopyable(){}

}
  1. c++ 初始化string带长度和默认值
std::string str(6,'.'); // = "......"
  1. c++位操作实现英文字母大小写转换
('d' ^ ' ') = 'D'
('D' ^ ' ') = 'd'
  1. c++通过位操作实现判断数字是否异号
// 如果0的符号是正的话,这个也适合存在零的情况
int x=1,y=-1;
bool f = ((x^y)<0); // true 表示异号
  1. c++通过位操作获取二进制最后一个1,以及将它置为0
int n = 6; // 110;
int last = n&(-n); // last = 010
n = n&(n-1); // n= 100;
  1. c++ vector 批量初始化
// 一种是声明时
vector<int> vec (10,0); //10个0
// 一种声明后
vector<int> vec;
vec.resize(10,0);
  1. c++ priority_queue 存放自定义指针型变量
struct mytype{
	int a;
	int b;
	int len;
};
struct cmp{
	bool operator()(mytype*a, mytype*b){
		return a->len > b->len;
	}
};
priority_queue<mytype*,vector<mytype*>,cmp>pq;

Share

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值