想要精通算法和SQL的成长之路 - 系列导航
前言
因为自己SQL
和算法方面比较薄弱。写下本系列文章以此激励自己,坚持每天练习:
SQL
:工作需要,必备技能。多写SQL
没有坏处。目的:不仅要有Mysql
的一个基础知识储备,还要拥有能够熟练写各种复杂SQL
的本领。- 算法:锻炼思维的同时还能复习各种数据结构,熟悉各种结构的
API
等。目的: 让算法变成这一块不要成为自己的短板。还要让其成为自己的一个长处。
不断更新…
一. 算法部分
1.1 回溯法
回溯法的本质就是穷举法,和暴力没什么区别。一般我们解决相关的回溯问题的时候。相关的函数我们一般可以分为三个部分:
- 主函数,就是入口函数。
backtrack
函数。用来递归+回溯的。被入口函数调用。valid
函数,一般用来判断特定的要求的。只有满足特定的要求,才将遍历的元素加入到结果集中。
backtrack
函数中又有着一定的模板:
- 满足递归终止条件,直接
return
。 for
循环遍历,每层循环做三件事:1.元素插入。2.进入下层递归。3.回溯(删除上面插入的元素)。
那么将上面套起来,一个回溯算法的模板就是(以数组回溯、集合List
为例):
// 定义一个结果集
List<List<Integer>> res = new ArrayList<>();
public void main(int[] nums){
backtrack(nums,0,new ArrayList<>());
return res;
}
public void backtrack(int[] nums,int index, List<Integer> tmp){
if(终止(下标越界、满足集合个数等等)){
// 当前结果集加入到结果集
res.add(new ArrayList<>(tmp));
return;
}
for (int i = index; i < nums.length; i++) {
// 如果不需要去重,这段代码也不需要
if (去重操作) {
continue;
}
// 如果需要一个判断函数,就加个判断,如果不需要,就删除就可以了
if(valid()){
// 元素插入
tmp.add(nums[i]);
// 下层递归
backtrack(nums, i + 1, tmp);
// 回溯,元素删除
tmp.remove(tmp.size() - 1);
}
}
}
public boolean valid(){}
1.2 双指针法
1.3 单调栈
记住这两句话:
- 寻找下一个比当前元素大的,我们就应该使用单调递增栈。
- 寻找下一个比当前元素小的,我们就应该使用单调递减栈。
例题:
1.4 动态规划
动态规划类问题往往需要这么几个步骤:
- 定义动态规划数组,一个
dp
数组是代表什么含义(中心思想)。 - 定义动态规划的递归公式(核心逻辑)。
- 思考
dp
数组的初始化动作(递归基建)。
递归的内容三把刷:
- 终止条件。
- 递归要做的事情。
- 进入下一层循环的条件,入参要做什么改变?
- 最大子数组和 、环形子数组的最大和
- 买卖股票的最佳时机系列☆
- 打家劫舍系列☆
- 最长序列问题
- 判断子序列问题
- 两个字符串的删除操作
- 编辑距离
- 填充书架
- 最长等差数列、最长回文子串(这里是用的中心扩散法)、最长回文子序列
- 戳气球
- 预测赢家和石子游戏
1.5 贪心算法
贪心问题就是选择每一个阶段的局部最优(每一个for
循环),从而达到全局最优(最终结果)。
这种题目,我们可以先写出它的暴力法是怎样的。然后再考虑哪些情况是可以舍弃的,以此来减小时间复杂度。或者,我们去寻找哪些条件下,他的最终解肯定不是最优解的。我们将其舍弃掉。以最大子数组和为例:
- 如果以A为元素的子数组和在遍历到元素B的时候和为负数了,那么这部分我们肯定就不要了。直接丢弃。 因为我们要贪心地去寻求局部最优解。
- 因为上一部分的子数组,它带来的永远是负作用,他对总和的影响永远是负数。
如果用到了优先队列,记住大小根堆的一个模板:
大根堆:堆顶元素最大。
PriorityQueue<Integer> heap = new PriorityQueue<>((a, b) -> b - a);
小根堆:堆顶元素最小。
PriorityQueue<Integer> heap = new PriorityQueue<>((a, b) -> a - b);
1.6 二叉树
常规题:
线段树
二叉搜索树
序列化问题
- 验证二叉树的前序序列化 (栈的使用,自底向上)
- 二叉树的序列化和反序列化问题 (
BFS
遍历和队列的特性运用)
1.7 数组
二分法的运用
1.8 链表
1.9 拓扑排序和邻接表
- 课程表II
- 课程表IV 在上面的基础上先决条件可以间接继承。在原本解法上:增加一个二维数组,预计算所有值。
- 受限条件下可到达节点的数目
1.10 并查集
在使用并查集之前,可以看下并查集的运用:并查集的运用和案例,以下是其他例题:
1.11 滑动窗口
- 经典的题目:无重复字符的最长子串和滑动窗口最大值
- 滑动窗口中,红黑树或者其他数据结构的运用:存在重复元素☆
- 需要满足二段性:至少有 K 个重复字符的最长子串
- 滑动窗口和大小根堆(大小根堆维护中位数、红黑树的运用)
1.12 前缀和
二. SQL部分
2.1 左右联结
讲一下左右联结的一些通用模板,假设红色部分是我们希望取的数据。两个圆圈分别代表着两张表A和B。
情况一:左联结,左边表数据全要。
select xxx from A as a left join B as b on (a.列 = b.列)
情况二:右联结,右边表数据全要。
select xxx from A as a right join B as b on (a.列 = b.列)
情况三:只要两张表的公共部分
select xxx from A as a inner join B as b on (a.列 = b.列)
情况四:在表A但是不在表B的数据。
select xxx from A as a left join B as b on (a.列 = b.列) where b.列 is null
情况五:在表B但是不在表A的数据。
select xxx from A as a right join B as b on (a.列 = b.列) where a.列 is null
- 第N高的薪水:
limit + offset + ifnull
的使用:limit n offset m
代表:先跳过m
条结果,再取前n
条结果。 - 分数排名:子查询
- 超过经理收入的员工:子查询、自连接、
join
语句。 - 部门工资最高的员工
- 删除重复的电子邮箱:中间表。