java银行和保险项目哪个好,社招面试心得

Redis 安装配置开机启动整合SpringBoot以及配置文件详解

  返回  

数据结构与算法刷题

2021/7/21 20:54:23 浏览:

0 九阳神功入门:十大排序算法 程序员内功

排序算法是基础中的基础,所以必须得掌握
速记口诀:
快选堆归希
桶记泡插基
不稳定排序4个
希尔快速选择堆
这十大排序要搞清楚,也非常不容易:需要下苦功夫

二分查找 树的中序遍历,树的前序,树的后续
0.1 排序题引论

思路:手写快速排序,然后使用数学定义来判断是不是等差数列

快排的注意点:
While()嵌套while,记得弄完需要自减和自加,非常重要
0.2 快速排序 树的前序 (重点)

0.2 归并排序 树的后续排列 (重点)
0.3
0.4 冒泡排序 (简单排序)
0.5 插入排序
0.6 选择排序

0.7 非递归实现前序遍历

1 九阳神功入门:递归思想

1.1 递归介绍

递归是一种编程技巧,一种解决问题的思维方式:严格来说,递归并不是一种算法。简单的说,就是如果在函数中存在着调用函数本身的情况,这种现象就叫递归
递归的思想就是,将大问题分解得足够小,不用继续分解,可以直接计算结果为止
如果把这个一层一层的分解过程画成图,它其实就是一棵树。我们给这棵树起一个名字,叫作递归树。以斐波那契数列为例

public class solution{
       public int fib(int N){
           if(N <= 1){
               return N;
           }
          return fib(N-1)+fib(N-2);
       }
 }

1.2 基本步骤

  1. 定义一个函数,明确函数功能
  2. 寻找问题与子问题之间的关系(递推公式)
  3. 将地推公式在定义的函数中实现
  4. 推导时间复杂度,判断是否可以接受,无法接受更换算法

1.3 代表题目

1.3.1 爬楼梯(#70)

动态规划解答

1.3.2 青蛙跳台阶(#面试题10-II)

1.3.3 斐波那契数列(#509)

1.4 触类旁通

1.4.1 反转二叉树

1.4.2 路径总和

给你二叉树的根节点 root 和一个表示目标和的整数 targetSum ,判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。

叶子节点 是指没有子节点的节点。

示例 1:

输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true

示例 2:

输入:root = [1,2,3], targetSum = 5
输出:false

示例 3:

输入:root = [1,2], targetSum = 0
输出:false

1.4.3 细胞分裂

2 九阳神功入门:分治策略(递归的孪生兄弟)

3 九阳神功第一式:单调栈

3.1 单调栈介绍

https://www.jianshu.com/p/43bb5204bc6f
单调栈是一种理解起来很容易,但是运用起来并不那么容易的数据结构。一句话解释单调栈,就是一个堆栈,里面的元素的大小按照他们所在栈内的位置,满足一定的单调性,说直白点,就是递增存储元素或者递减存储元素,当该单调性(递增性或者递减性)被打破时要进行适当出栈,这是该算法的关键。那么到底什么时候用这个单调栈,怎么用单调栈呢。下面我们看几个例子

3.1.1 开胃菜-

谷歌面试题

3.1.2 单调栈的性质

  1. 单调栈里的元素具有单调性,栈中元素只能单调递增或者单调递减
  2. 元素加入栈前。会在栈顶端把破坏栈单调性元素都删除;
  3. 使用单调栈可以找到元素向左遍历第一个比它小的元素,也可以找到元素向右遍历第一个比它大的元素。
    最后总结一下单调栈。单调栈这种数据结构,通常应用在一维数组上。如果遇到问题,和前后元素之间的大小关系有关系的话,(例如第一题中我们要找比某个元素大的元素,第二个题目中,前后bar的高低影响了最终矩形的计算),我们可以试图用单调栈来解决。在思考如何使用单调栈的时候,可以回忆一下这两题的解题套路,然后想清楚,如果使用单调栈,每个元素出栈时候的意义。最后的时间复杂度,因为每个元素都出栈入栈各一次,所以是线性时间的复杂度。

3.2 代表题目

3.2.1 柱状图中最大的矩形(#84)

3.2.3 最大的矩形面积(#85)

3.3 触类旁通

每日温度(#739)

思路:该题使用单调栈能够更好的解题
遍历每日温度,维护一个单调栈
1.若栈为空或者当日温度小于栈顶温度则直接入栈;
2.反之,若当日温度小于栈顶温度,说明栈顶元素的升温日已经扎到了,则将栈顶元素出栈,计算其与当日相差的天数即可
此题目要求的是升温的天数,而不是升温后的温度,因此栈中应该存储下标,而不是温度

下一个更大元素II(#503_中等)
接雨水(#42_困难 性能敏感)

股票价格跨度(#901 中等)
滑动窗口最大值(#239_困难)
最大宽度坡(#962)

4 九阳神功第二式:并查集(DSU)

4.1 并查集介绍

武功出处:

并查集顾名思义就是具有”合并集合”和”查找集合中元素”两种操作的一种算法。但是,实际并查集的基本操作有三个:
makeSet(size):建立一个新的并查集,其中包含size个单元素集合。通常该操作比较隐晦,用一句int[] parent = new int[size];直接替换了make set的过程
unionSet(x,y):把元素x和元素y所在的集合合并,要求x和y所在的集合不想交,如果相交则不合并。
Find(x):找到元素x所在的集合的代表,该操作也可以判断两个元素是否位于同一个集合,只要它们各自的代表比较一下就可以了。Find(x)有两种实现方法,一种是递归,一种是非递归形式。
算法:
用集合中的某个元素来这个集合,该元素称为集合的代表元。一个集合内的所有元素组织成以代表元为根的树形结构。对于每一个元素x来说,parent[x]指向x在树形结构上的父节点,如果x是根节点,则令parent[x] = x.对于查找操作,假设需要确定x所在的集合,也就是确定集合的代表元。可以沿着parent[x]不断在树形结构中向上移动,直到到达根节点。因为创建的树可能会严重不平衡,并查集可以用两种办法优化
并查集两种优化策略:

  1. 按秩合并 Union by Rank
  2. 路径压缩

4.2 代表题目:朋友圈(#547)

4.3 触类旁通

5 九阳神功第三式:滑动窗口

6 九阳神功第四式:前缀和&[&哈希表优化]

1.1 前缀和介绍

前缀和(prefix Sum)定义:前缀和是一种重要的预处理,能大大降低查询的时间复杂度。结合Hash缓存,能够进一步提升算法执行效率。
对数组nums进行前缀和初始化需要时间O(n)时间:
新建数组prefixSum,数组长度定义为nums.length+1,确保第nums.length个元素存储了前面0到nums.length-1个元素和。将数组nums的累加依次放入数组prefixSum中
PrefixSum[0] = 0[备注:此处不要定义prefix[0]=nums[0,这种定义违背前缀和的意义]
prefixSum[1] = prefixSum[0] + nums[0] = 0 + nums[0];

prefixSum[i] = prefixSum[i-1] + nums[i].

由此推导出两个变换公式:
(1) nums[某一项] = 两个相邻 前缀和 之差
nums[x] = prefixSum[x] – prefixSum[x-1];
(2) 从left到right的元素和等于refixSum[right+1] -prefix[left];

前缀和推导过程:
preSum[0] = 0
preSum[1] = nums[0] = preSum[0] + nums[0];
见上面

前缀和数组初始化过程伪代码示例:
划重点:
(1) 按照for循环的正常边界进行初始化,避免int I = 1或者<= len等等可能的各种调整
(2) 前缀和长度比数据长度多一个,前缀和第0个元素要初始化为0

拓展解惑:另外一种前缀和初始化方法:前缀和长度为nums.length,第0个元素存储自己的和

划重点:
(1) 预处理过程看似简单,但是考试计算容易出现混乱;
(2) prefixSum[i] – prefixSum[i-1];容易出现错误理解和计算丢失。
示例:prefixSum[1] – prefixSum[0] = nums[1],造成nums[0]丢失,出现后续错误
1.2 代表题目:和为K的子数组(#560中等)

6.3 触类旁通

6.3.1 连续的子数组和(#523)

6.3.2 和可被K整除的子数组(#974)

7 九阳神功第五式:差分

7.1差分介绍 基本套路

差分,是一种和前缀和相对的策略。这种策略是,令Bi=Ai-Ai-1,即相邻两数的差。在每一个点上记录变化数值,因为有增加有减少,通过求和和判断是否有超过指定容量的情况发生,超过则代表无法满足要求。

对于数组array[N]中的某一段进行增减操作,通过差分可在O(n)时间内完成。如
Trips=[[2,1,5],[3,3,7]]
第一步:更新array[1] = 2,array[5]=-2;
第一个站点上车2人占用两个座位,第5个站点下车2人,空出两个座位
第二步:更新array[3]=3,array[7]=-3
{0,2,0,3,0,-2,0,0,-3}
第三步:进行求和,得到结果array[]={0,2,2,5,5,3,3,0};

7.2代表题目:拼车(#1094)

代码实现

class Solution {
    private static final int MAX_TRIP = 1001;
    public boolean carPooling(int[][] trips, int capacity) {
        // 差分经典题目
        int[] changes = new int[1001];
        for (int[] trip : trips) {
            int passages = trip[0];
            // 上车乘客数量
            changes[trip[1]] += passages;
            // 下车乘客数量
            changes[trip[2]] -= passages;
        }
        int total = 0;
        for (int i = 0; i < MAX_TRIP; i++) {
            total += changes[i];
            if (total > capacity) {
                return false;
            }
        }
        return true;
    }
}

7.3触类旁通

航班预订统计(#1109)

思路与其代码实现
1.换一种思路理解题意,将问题转换为:某公交车共有 n 站,第 i 条记录 bookings[i] = [i, j, k] 表示在 i 站上车 k 人,乘坐到 j 站,在 j+1 站下车,需要按照车站顺序返回每一站车上的人数
2.根据 1 的思路,定义 counter[] 数组记录每站的人数变化,counter[i] 表示第 i+1 站。遍历 bookings[]:bookings[i] = [i, j, k] 表示在 i 站增加 k 人即 counters[i-1] += k,在 j+1 站减少 k 人即 counters[j] -= k
3.遍历(整理)counter[] 数组,得到每站总人数: 每站的人数为前一站人数加上当前人数变化 counters[i] += counters[i - 1]

买卖股票的最佳时机(#121)
买卖股票的最佳时机II(#122)
会议室(#253)

8 九阳神功第六式:拓扑排序(专业级)

8.1 拓扑排序介绍

https://blog.csdn.net/lisonglisonglisong/article/details/45543451
一、什么是拓扑排序
在图论中,拓扑排序(topological Sorting)是一个有向无环图(DAG,directed Acyclic graph)的所有顶点的线性序列。且该序列必须满足下面两个条件。
每个顶点出现且出现一次。
若存在一条从顶点A到顶点B的路径,那么在序列中顶点A出现在顶点B的前面
有向无环图(DAG)才有拓扑排序,非DAG图没有拓扑排序一说

8.1.1序列重建(#444会员)

8.2 代表题目

课程表II (#210)

8.3 触类旁通

8.3.1 火星词典(#269)

9 九阳神功第七式:字符串(高频 20~50)

10 九阳神功第八式:二分查找 (高频 10~20)

https://leetcode-cn.com/leetbook/detail/binary-search/

10.1 二分查找介绍

二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法,前提是数据结构必须排好序,可以在数据规模的对数时间复杂度内完成查找,二分查找要求线性表具有随机访问的特点(例如数组),也要求线性表能够根据中间元素的特点推测它两侧元素的性质,以达到缩减问题规模的效果
二分查找问题也是经常考到的问题,虽然它的思想很简单,但写好二分查找算法并不是一件很容易的事情
关键点:
(1) 二分查找的关键变量是low,high,mid三个元素,根据目标值和mid所在索引的数值和target目标值进行比对,根据[mid]中间值得大小重新确定查找区间
(2) 用途:二分法的基础是分治策略的基础,分治用的最多的是二分拆解计算
二分查找法有更安全的写法
mid = (l+r)/2; 可能整型溢出,上亿的数据
mid=l+(r-l)/2;
记录三个经典模板(必须掌握)
详情见leetcode:

10.1.1 模板一:

注意点:

  1. right是长度-1,而且左边小于右边
  2. mid的处理

10.1.2 模板二

10.1.3 模板三

10.2 代表题目:搜索二维矩阵II(#240)

https://leetcode-cn.com/problems/search-a-2d-matrix/solution/yi-wen-dai-ni-gao-ding-duo-ge-er-fen-cha-2hl9/
搞死所有的二分法

该题的难点在于二分查找法的处理过程
搜索二维矩阵(#240)

主要思路及难点:

  1. 二分法模板
  2. 二维数组到一维数组的降维
  3. 二分法中如果不降维,会出现问题

10.3 触类旁通

10.3.1寻找两个有序数组的中位数(#4)

10.3.2搜索旋转排序数组(#33)

#33题 :搜索旋转排序数组
#81题 :搜索旋转排序数组-ii
#153题: 寻找旋转排序数组中的最小值
#154题: 寻找旋转排序数组的最小值-ii
https://leetcode-cn.com/problems/search-in-rotated-sorted-array/solution/yi-wen-jie-jue-4-dao-sou-suo-xuan-zhuan-pai-xu-s-2/
该题是二分查找的变种,题型非常经典

10.3.2计算二分数组的上下边界条件(#34 )

11 九阳神功第十式:BFS广搜

11.1 BFS介绍

DFS(深度优先搜索)和BFS(广度优先搜索)就像孪生兄弟,提到一个总是想起另一个,然后在实际使用中,我们用DFS的时候远远多于BFS,那么,是不是BFS就没有用呢?

如果我们使用DFS/BFS知识为了遍历一棵树、一张图上所有结点的话,那么DFS和BFS的能力没什么差别,我们当然更倾向于更方便写、空间复杂度更低的DFS遍历。不过,某些使用场景是DFS做不到的,只能使用BFS遍历,这就是本文要介绍的两个场景:[层序遍历]、[最短路径]。
DFS与BFS
让我们先看看在二叉树上进行DFS遍历和BFS遍历的代码比较。
DFS遍历使用递归:
Java:

实际编码中,有的童学会增加一个!=null的判空,不太推荐这种写法,因为递归的终止条件已经进行了判断。只有在BFS外队列中添加元素时才会进行判空处理,避免后续从队列中取出来的数据存在空指针。

BFS遍历使用队列数据结构:
Java

只是比较两段代码的话,最直观的感受就是:DFS遍历代码比BFS简洁太多了!这是因为递归的方式隐藏含地使用了系统的栈,我们不需要自己维护一个数据结构。如果只是简单的将二叉树遍历一遍,那么DFS显然是更方便的选择
总结:
可以看到。BFS遍历,层序遍历,最短路径实际上是递进的关系。在BFS遍历的基础上区分遍历的每一层,就得到了层序遍历。在层序遍历的基础上记录层数,就得到了最短路径。
BFS遍历时一类很值得反复体会和练习的题目。一方面,BFS遍历时一个很经典的算法,需要重点掌握。另一方面,我们需要根据题意分析出题目是求最短路径,知道要做BFS遍历

BFS的几个步骤
1.肯定会用到 deque 的结构用来模拟队列,BFS精髓也在这里。
2.队列里肯定是有一个初始点
3.然后每次处理从队列中出队一个元素
4.对元素进行扩张(具体如何扩张需要根据题目要求,一般是上下左右四个方向,本题是算上斜向共8个方向)
5.对于扩张后满足某条件的点再进行处理,根据需要进入队列,进入队列的点就是扩到下一层的点(不同题目需要处理的方法不同,大家灵活运用)
6.然后接着循环处理 deque 中的元素,直到 deque 为空,则代表所有点都已经完成扩张
7.最后根据题目要求输出结果(当然这已经不属于 BFS 模板的范围了)

11.2 代表题目:单词接龙(#127)

11.3 触类旁通

11.3.1 单词拆分(#139)

11.3.2 打开转盘所(#752)

11.3.3 被围绕的区域(#130)

11.3.4 离建筑物最近的距离(#317)

11.3.5 迷宫II (#505)

11.3.6 扫雷游戏(#529)

11.3.7 推箱子(#1263)

11.3.8 进击的骑士(#1197)

11.3.9 公交路线(#1197)

11.3.10 最短的桥(#934)

11.3.11 腐烂的橘子(#994)

12 九阳神功第十一式:DFS深搜&回溯

12.1 DFS介绍

深度优先搜索算法(英语:Depth-First-Search,DFS)是一种用于遍历或者搜索树或者图的算法。这个算法会尽可能深的搜索树的分支。深度优先搜索是图论中的经典算法,利用深度优先搜索算法可以产生目标图的拓扑排序表,利用拓扑排序表可以方便的解决很多有关的图论问题,如无权最长路径问题等等。DFS基于递归思想,DFS实质就是一种枚举,不过借助递归实现
回溯搜索是深度优先搜索(DFS)的一种。对于某一个搜索树来说(搜索树是起记录路径和状态判断的作用),回溯和DFS,其主要的区别是,回溯法在求解过程中不保留完整的树结构,而深度优先搜索则记下完整的搜索树。回溯就是通过不同的尝试来生成问题的解,有点类似于穷举,但是和穷举不同的是回溯会”剪枝”.为了减少存储空间,在深度优先搜索中,用标志的方法记录访问过的状态,这种处理方法使得深度优先搜索法与回溯法没什么区别

DFS的基本模板:

回溯的一般结构:

12.2代表题目:最短的桥(#934)

结题思路:

  1. 通过深度优先遍历,将两个岛屿中的一个岛屿进行染色处理,打上标签2
  2. 通过广度优先遍历查找岛屿1,找出最短路径
  3. 关键点:广度优先遍历时,要用visited数组记录访问过的节点,避免重复访问造成超时TLE
    编程细节:
class Solution {
    public int shortestBridge(int[][] A) {
        int R = A.length, C = A[0].length;
        int[][] colors = getComponents(A);

        Queue<Node> queue = new LinkedList();
        Set<Integer> target = new HashSet();

        for (int r = 0; r < R; ++r)
            for (int c = 0; c < C; ++c) {
                if (colors[r][c] == 1) {
                    queue.add(new Node(r, c, 0));
                } else if (colors[r][c] == 2) {
                    target.add(r * C + c);
                }
            }

        while (!queue.isEmpty()) {
            Node node = queue.poll();
            if (target.contains(node.r * C + node.c))
                return node.depth - 1;
            for (int nei: neighbors(A, node.r, node.c)) {
                int nr = nei / C, nc = nei % C;
                if (colors[nr][nc] != 1) {
                    queue.add(new Node(nr, nc, node.depth + 1));
                    colors[nr][nc] = 1;
                }
            }
        }

        throw null;
    }

    public int[][] getComponents(int[][] A) {
        int R = A.length, C = A[0].length;
        int[][] colors = new int[R][C];
        int t = 0;

        for (int r0 = 0; r0 < R; ++r0)
            for (int c0 = 0; c0 < C; ++c0)
                if (colors[r0][c0] == 0 && A[r0][c0] == 1) {
                    // Start dfs
                    Stack<Integer> stack = new Stack();
                    stack.push(r0 * C + c0);
                    colors[r0][c0] = ++t;

                    while (!stack.isEmpty()) {
                        int node = stack.pop();
                        int r = node / C, c = node % C;
                        for (int nei: neighbors(A, r, c)) {
                            int nr = nei / C, nc = nei % C;
                            if (A[nr][nc] == 1 && colors[nr][nc] == 0) {
                                colors[nr][nc] = t;
                                stack.push(nr * C + nc);
                            }
                        }
                    }
                }

        return colors;
    }

    public List<Integer> neighbors(int[][] A, int r, int c) {
        int R = A.length, C = A[0].length;
        List<Integer> ans = new ArrayList();
        if (0 <= r-1) ans.add((r-1) * R + c);
        if (0 <= c-1) ans.add(r * R + (c-1));
        if (r+1 < R) ans.add((r+1) * R + c);
        if (c+1 < C) ans.add(r * R + (c+1));
        return ans;
    }
}

class Node {
    int r, c, depth;
    Node(int r, int c, int d) {
        this.r = r;
        this.c = c;
        depth = d;
    }
}

12.3 触类旁通

12.3.1 路径总和II(#113中等 重点看)

思路及算法

我们可以采用深度优先搜索的方式,枚举每一条从根节点到叶子节点的路径。当我们遍历到叶子节点,且此时路径和恰为目标和时,我们就找到了一条满足条件的路径。

class Solution {
List<List> ret = new LinkedList<List>();
Deque path = new LinkedList();

public List<List<Integer>> pathSum(TreeNode root, int sum) {
    dfs(root, sum);
    return ret;
}

public void dfs(TreeNode root, int sum) {
    if (root == null) {
        return;
    }
    path.offerLast(root.val);
    sum -= root.val;
    if (root.left == null && root.right == null && sum == 0) {
        ret.add(new LinkedList<Integer>(path));
    }
    dfs(root.left, sum);
    dfs(root.right, sum);
    path.pollLast();
}

}

12.3.2 二叉树中的最大路径和(#124 困难)

12.3.3 得分最高的路径(#1102 中等)

12.3.4 冗余连接II(#685困难)

12.3.5 孤独像素I(#531 中等)

12.3.6 孤独像素II(#533 中等)

12.3.7 重新安排行程(#332 中等)

12.3.8 打家劫舍III (#337 中等)

12.3.9 岛屿数量(#200 中等 重点琢磨)

杀光岛屿数量问题,一次搞定,该问题考的很多
• L200. 岛屿数量 (Easy)
• 463. 岛屿的周长 (Easy)
• 695. 岛屿的最大面积 (Medium)
• 827. 最大人工岛 (Hard)
https://leetcode-cn.com/problems/number-of-islands/solution/dao-yu-lei-wen-ti-de-tong-yong-jie-fa-dfs-bian-li-/

思路很重要:

岛屿的最大面积 695
见题目

12.4 树的其它题型

12.4.1二叉树遍历问题 (递归+非递归方式实现)

二叉树的前序遍历 (#144)
二叉树的中序遍历 (#94)
二叉树的后续遍历 (#145)
二叉树的层序遍历
上述题目都是一类题
二叉树遍历速记歌:
栈的方式来实现

  1. 二叉树返list,辅助正规dfs来救场
  2. 主要区别根节点前中后,返回全搞定
    后续遍历基本方法,里面只需要调动一下根节点的位置即可

非栈的方式来实现

前序遍历

13 九阳神功第十二式:动态规划 (共计11道母题)

13.1 动态规划介绍

Leetcode上有专门的章节来描述
https://blog.csdn.net/qq_37763204/article/details/79394397
https://blog.csdn.net/u013309870/article/details/75193592

13.2 代表题目:打家劫舍II(#213)

基本思路:

13.3 触类旁通

13.3.1 分隔数组以得到最大和(#1043)

13.3.2 分隔等和子集(#416)

13.3.3 买股票的最佳时机 III (#123)

13.3.4 不同路径(#62)

思路一:

思路二:
本题是个高中数据题

13.3.5 不同路径II(#63)

13.3.6 4键键盘(#651会员)

13.3.7 最小路径和

这道题很典型:

13.3.8 轰炸敌人(#361)

13.3.9 校园的自行车分配 II(#1066会员)

13.3.10 角矩阵的数量(#750会员)

13.3.11 抛掷硬币(#1230)

14 九阳神功第十三式:贪心算法

14.1 贪心算法介绍

所谓贪心算法是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,它所做出的仅是在某种意义上的局部最优解。也就是说在每一步中,选择当前最优的策略,而不是考虑全局是不是最优解的
贪心算法的前提:

  1. 原问题复杂度过高
  2. 求全局最优解的数学模型难以建立
  3. 求全局最优解的计算量过大
  4. 没有太大必要一定要求出全局最优解,”比较优”就可以。

贪心算法没有固定的算法框架,算法设计的关键是贪心策略的选择。必须注意的是,贪心算法不是对所有问题都能得到整体最优解,选择的贪心策略必须具备无后效性,即某个状态以后的过程不会影响以前的状态,只与当前状态有关。所以对所采取的贪心策略一定要仔细分析其是否满足无后效性
贪心算法实现步骤

  1. 建立数学模型来描述问题
  2. 把求解的问题分成若干个子问题
  3. 对每一个子问题求解,得到子问题的局部最优解
  4. 把子问题的解局部最优解合成原来解问题的一个接

实现该算法的过程:
从问题的某一初始解出发:
While(能朝给定总目标前进一步)
{
利用可行的决策,求出可行解的一个元素;
}
由所有解元素组合成问题的一个可行解

虽然没有固定模板提供贪心算法解决方案,但是可以参考一种可能的理解贪心算法的代码示例,进行学习和理解;

14.2 代表题目:用最少数量的箭引爆气球(#452)

基本思路
https://leetcode-cn.com/problems/minimum-number-of-arrows-to-burst-balloons/solution/yong-zui-shao-shu-liang-de-jian-yin-bao-qi-qiu-1-2/

14.3 触类旁通

14.3.1 两地掉地(#1029)

14.3.2 0/1背包问题

14.3.3 分享巧克力(#1231会员 困难)

14.3.4 交换字符使得字符串相同(#1247)

14.3.5 跳跃游戏II (#45)

14.3.6 任务调度器(#621)

14.3.7 摆动序列(#376)

15 九阳神功第十四式:字典树

15.1 字典树介绍

Trie(发音“TRY”,但是坐着称之为Tree)或者前缀树是一种数据结构,用于检索字符串数据集中的键。Trie树优于哈希表的另一个理由是,随着哈希表大小增加,会出现大量的冲突,时间复杂度可能会增加到O(n),其中n是插入的键的数量。与哈希表相比,Trie树存储多个具有相同前缀的键时可以使用较少的空间。此时Trie树只需要O(m)的时间复杂度,其中m为键长。而在平衡树种查找键值需要O(mlogn)时间复杂
Trie树的节点结构
Trie是一个有根的树,Trie树种最常见的两个操作是键的插入和查找。其节点具有以下字段:
最多R个指向子节点的链接,其中每个链接对应字母表数据集中的一个字母
本文中假定R为26,小写拉丁字母的数量
希尔字段,以指定节点是对应键的结尾还是只是键前缀
这一高效的数据结构有多种应用

  1. 自动补全
  2. 拼写检查
  3. IP路由(最长前缀匹配)

15.2 代表题目:单词的压缩编码(#820)

15.3 触类旁通

15.3.1 实现Trie前缀树(#208)

15.3.2 单词替换(#648)

16 九阳神功第十五式:位运算

16.1位运算介绍

https://www.zhihu.com/question/38206659
总结一些常用的位运算技巧
1.异或的特性

2.构造特殊 Mask,将特殊位置放 0 或 1。

3.有特殊意义的 & 位操作运算

16.2代表题目

异或类题目(#136)

主要用到了异或性质 思路
1.任何数和 000 做异或运算,结果仍然是原来的数,即 a⊕0=aa \oplus 0=aa⊕0=a。
2.任何数和其自身做异或运算,结果是 000,即 a⊕a=0a \oplus a=0a⊕a=0。
3.异或运算满足交换律和结合律,即 a⊕b⊕a=b⊕a⊕a=b⊕(a⊕a)=b⊕0=ba \oplus b \oplus a=b \oplus a \oplus a=b \oplus (a \oplus a)=b \oplus0=ba⊕b⊕a=b⊕a⊕a=b⊕(a⊕a)=b⊕0=b。

16.3触类旁通

17 专题强化

17.1 ASCII专题

17.1.1 最长回文子串(#409简单)

17.2 子序列问题

17.3 子数组专题

17.4 计算器专题

17.5 与或非位运算专题(二进制计算)

17.5.1 只出现一次的数字II(#137)

17.5.2 只出现一次的数字III

17.5.3 数组中两个数的最大异或值

17.5.4 重复的DNA序列

17.5.5 最大单词长度乘积

17.5.6 数字信号处理

17.6 打家劫舍专题

17.6.1 打家劫舍(#198)

思路:通过该问题可以看出,应该是有状态方程的

17.6.2 打家劫舍II (#213)

17.6.3 打家劫舍III(#337)

17.7 背包问题专题

17.7.1 0/1背包问题

17.7.2 完全背包问题

17.7.3 多重背包问题

17.7.4 实战练习

17.7.5 栈与队列的问题

用栈实现队列
主要是使用栈实现队列

用队列实现栈

17.8股票买卖的最佳时机专题
17.8.1买卖股票的最佳时机

基本思路:使用动态规划进行出路该题,非常清晰明了,建议背诵该题

17.8.2 买卖股票的最佳时机II

18 设计者模式思考
https://www.cnblogs.com/hongmoshui/p/10438719.html
https://blog.csdn.net/srk950606/article/details/50187721?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160628694119725264553504%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=160628694119725264553504&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v28-14-50187721.first_rank_ecpm_v3_pc_rank_v2&utm_term=%E4%B9%9D%E9%98%B3%E7%A5%9E%E5%8A%9F&spm=1018.2118.3001.4449
18.1 设计者模式的分类
速记口诀:
创建型模式:建造者按照工厂单例原型进行工厂方法抽象
结构型模式:代理组合适配,享元装饰桥(接)外观
行为型模式:
总体来说设计模式分为三大类:
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
18.2 设计模式的六大原则
口诀辅助记忆::
一个单身的吕氏拿着颠倒的半开半合的扇子,正在分析接口隔离问题,旁边站着米老鼠
1.
2
3
4
5
6
18.3 常见的几种设计模式(重点)

18.4 设计原则与设计模式的概念:
目的:所有的设计原则和设计模式都是为了更容易的实现高内聚低耦合
软件设计->设计模式->SOLID原则->正交四原则->高内聚低耦合

为了更容易达成高内聚低耦合,利用互相交互的维度独立设计一个事半功倍的方式,由此提出来正交四原则:
1.最小化重复
2.分离变化
3.缩小依赖范围
4向稳定方向依赖
每个原则都是和其他原则独立发展,互不重复

在面向对象发展过程中,提出更具体的SOLID原则:
1.单一职责(SRP)
2.向扩展开发/向修改封闭(OCP)
3.子类要能替换父类(LSP)
4.接口隔离/最小化接口依赖(ISP)
5.依赖倒置/只依赖接口(DIP)

19.2.1 反转链表

更新三个引用:主要理解清楚整个过程

19.3栈
19.4 堆
19.5 树

联系我们

如果您对我们的服务有兴趣,请及时和我们联系!

服务热线:18288888888
座机:18288888888
传真:
邮箱:888888@qq.com
地址:郑州市文化路红专路93号