第三天:一个视频教会你常用的8种解题方法和算法模版(简直不要太简单)

关于作者:

大家好,我是Leetcode 2020--2022,连续3年金牌获得者,和亚洲区域赛铜牌获得者,

先后在字节和大疆从事技术研发,现在是阿里达摩院的扫地僧,面试专家,CSDN博客专家。

对算法一定的见解,是一个刷题10年的算法爱好者 ,利用工作之余刷leetcode。成为leetcode官方答案贡献者之一。

7天课程目录,免费!踢馆抖音算法 (7天刷新法)

1. 第一天:一个视频教会你时间复杂度和空间复杂度                                             0912

2. 第二天:一个视频教会你必考的8种数据结构(视频,图文并茂)                     0913

3. 第三天:一个视频教会你常用的8中解题方法和算法模版(简直不要太简单)    0912

4. 第四天:一个视频教会你 6大高频考点 常用操作技巧,常用的字符,数组,类型(独家) 0911

5. 第五天: Top10,最高频题,99%命中面试题(字节,快手,shapee,大疆, 华为,蔚来  )  ok

6. 第六天: Hot 20 , 大厂面试算法真题,95%命中(精选: 京东,美团,小米,拼多多,网易)(非算法工程师误入) 0910

7. 第七天: Top5,  经典热题5,90%命中面试题(剑指offer)

要求

1.核心代码,记住代码模版

2.最具有代表的一道题目

3.记住各种的特点,使用场景

1.双指针        2个指针    有序      (2数之和)

2.二分查找    中间值      有序

3.滑动窗口     连续

4.递归     4要素

6.分治:   分块,  和二分一样,和归并排序一样,不同的是分治是全部二分    

7.回溯       返回   找到所以可能

8.  DFS     深度    用到栈                                   二叉树

9 . BFS     广度    用到队列:LinkList                二叉树

表格:8种解题方法表格:

指针相关解法对比

双指针:    有需要排序      一般是头尾2个指针,               然后进行交叉移动i++,j--

二分查找: 有序             一般是头尾2个指针,中间值。指针移动不同:移动i=m+1或者m-1

滑动窗口: 连续         

递归解法对比:重点(3者的代码对比)

1.分治:   分块,  和二分一样,和归并排序一样,不同的是分治是全部二分    

2.回溯       返回

3.  DFS     深度

DFS和回溯解法对比

回溯算法=DFS+剪枝(后面不走了)

回溯:递归后回上一层

DFS:一直走到底。不撞南墙不回头

DFS和BFS解法对比

共同点:一般题目都可以使用这2个一起解决

DFS :递归+栈

BFS: 2次循环+队列

双指针

双指针常用于数组、链表两种线性表(有序)数据结构相关的题,具体又分为

相向双指针:

两个指针一头一尾往中间移动

多应用于数组的连续子序列或两两组合,有规律的缩小范围

单向双指针

两个指针往同一个方向移动(没想到什么场景后续补充吧)

快慢指针:

通常慢指针向前走一步,快指针向前走两步

多用于链表、因为链表无法直接通过索引访问

通常利用快慢指针找到链表的中点或公共节点

二分法

常用于有序数组,取中点二分后按一定规则只取其中一边再继续二分,多用于查数

滑动窗口

常用于连续子序列的长度、统计量例如总和、计数等最优值问题

递归★

递归是指一个函数在运行时调用自己,框架如下

def recursion(params):           #1.函数输入参数

    if params==1:               #2.递归终止条件

        return 0

    params=params-1

    res=1+recursion(params)    #3.调用自身

    return res                 #4.返回值

递归有时不是直接的最优解题方法,但却是最基本、一定能解题的思想。

分治法

是一种特殊的递归,将问题进行分解,每个分解部分都有可能调用自己即递归到下一层,总结就是一个函数会同时多次或有选择性地调用自己、只是入参具体值不相同

回溯法★

一种通过探索所有可能的候选解来找出所有的解的算法。如果候选解被确认不是一个解(或者至少不是最后一个解),回溯算法会通过在上一步进行一些变化抛弃该解,即回溯并且再次尝试。(力扣定义)

是一种特殊的递归,常用于枚举组合+过滤或去重(可选)场景:

1.尝试一种路径,层层递归(调用自己)

2.找到答案并返回答案(返回值)

3.找不到答案返回上一层(终止条件)

4.尝试其他路径(调用自己)

去重前需保证枚举集有序

解决什么问题

回溯算法适用于以下的场景。

组合问题:N个数里面按一定规则找出k个数的集合

切割问题:一个字符串按一定规则有几种切割方式

子集问题:一个N个数的集合里有多少符合条件的子集

排列问题:N个数按一定规则全排列,有几种排列方式

棋盘问题:N皇后,解数独等等

深度优先搜索(Depth First Search, DFS)★

针对树结构,从根节点走一个分支到底后,返回最近的非叶子节点再走另一个分支走到底,这样直到把所有节点遍历完成

up主总结是回溯=DFS+剪枝,但我觉得回溯也不必须剪枝(上方回溯定义),所以是不是更合适的说DFS也是一种回溯

need-to-insert-img

need-to-insert-img

广度优先搜索(Breadth First Search, BFS)

针对树结构,从根节点一层一层遍历子节点,直到所有节点遍历完成。

比起DFS,BFS应用偏少,常用于层序遍历、最短路径场景。

一般来说,数据结构和算法会连在一起考,这里,我把面试核心知识点列了出来,大家可以参考学习,逐个击破。

栈与队列:先进先出、后进先出

线性链表

查找:顺序查找、二分查找

排序:交换类、插入类、选择类

树、二叉树、图:深度优先(DFS)、广度优先(BFS)

递归

分治

滑窗

三大牛逼算法:回溯、贪心、动态规划(DP)

算法模板

双指针模版

/*(1)定义两个边界指针*/

int left =0;//左边界

        int right = num.size() -1;//右边界

        while(left

/*(2)定义两个快慢指针*/

        ListNode*s = head;//慢指针

        ListNode*f = head->next;//快指针

        while (s != f){/*执行操作*/}

回溯算法

backtracking() {    if (终止条件) {        存放结果;    }    for (选择:选择列表(可以想成树中节点孩子的数量)) {        递归,处理节点;        backtracking();        回溯,撤销处理结果    }}

或者是这个:

public void helper(options, result) {

// 1. 在for循环之前做“判断”

        if (list.size() ...) {

do something ...

return;

        }

// for loop

        for loop {

// 可能在这里还需要做一些判断:1.操作是否合法;2.操作是否重复

// 3. 在递归之前做“选择”

        result.add(element);

        // 2. 在for循环里面做“递归”

        helper(options, result);

        // 4. 在递归之后做”撤销“

        result.removeLast();

        }

}

回溯的代码模版

private void backTracking(int n, List list, int left, int right, String curStr) {

if (left < right) {// (不符合退出条件)右边的括号大于左边的括号的时候,就需要终止了,终止一个地方

        return;

    }

if (left == n && right == n) {// 达到条件,终止条件

        list.add(curStr);  // 保存结果,并退出

        return;

    }

if (left < n) {//  移动指针, 回溯,

        backTracking(n, list, left +1, right, curStr +"(");

    }

if (right < left) {//  移动指针, 回溯,

        backTracking(n, list, left, right +1, curStr +")");

    }

}

二分查找法

二分查找模版

vector&nums

int left=0;//左边界

        int right=nums.size()-1;//右边界

        int mid=0;

        while(left<=right){

mid=(left+right)/2;

        if(target==nums[mid]){/*操作*/ }

if(target

right=mid-1;

        }

else{

left=mid+1;

        }

}

class Solution {public:    int searchInsert(vector& nums, int target) {        int n = nums.size();        int left = 0;        int right = n; // 我们定义target在左闭右开的区间里,[left, right)          while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间            int middle = left + ((right - left) >> 1);            if (nums[middle] > target) {                right = middle; // target 在左区间,因为是左闭右开的区间,nums[middle]一定不是我们的目标值,所以right = middle,在[left, middle)中继续寻找目标值            } else if (nums[middle] < target) {                left = middle + 1; // target 在右区间,在 [middle+1, right)中            } else { // nums[middle] == target                return middle; // 数组中找到目标值的情况,直接返回下标            }        }        return right;    }};

你可能感兴趣的:(第三天:一个视频教会你常用的8种解题方法和算法模版(简直不要太简单))