数据结构与算法(三)-算法技巧与概念

1.分治法

工作原理:

找到基线条件 => 不断分解问题 => 直到符合基线条件得出题干解

思路:
1.基线分割
2.完成单个模块功能
3.递归

例题:
将数组元素由小到大排序

//分割之后分别比较,再递归
const quickSort = function(arr) {
    // 检测,停止递归
    if (arr.length <= 1) {
        return arr;
    }
    
    // 绝对的二分之一
    let pivotIndex = Math.floor(arr.length / 2);
    let pivot = arr.splice(pivotIndex, 1)[0];
    let left = [];
    let right = [];

    for(let i = 0; i < arr.length; i++) {
        if (arr[i] < pivot) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }

    return quickSort(left).concat([pivot], quickSort(right));
}

2.贪婪

利益最大化,始终查找最大项目,尽可能快的去满足

思路:

  1. 最大子序列和为sum,结果是ans
  2. 遍历 => 判断sum是否有buff => 如果没有直接抛弃 => 比较sum和ans
  3. nums => ans

面试题:
给定一个整数数组nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和
[1, 2, 3, 4, -4, 3, 6] => 10

// 一直加,加之后比较加之前,大的保存,如果小于0了,从下一个数组元素开始累加
const maxSubArray = function(nums) {
    let ans = nums[0];
    let sum = 0;

    for(const num of nums) {
        if(sum > 0) {
            sum += num;
        } else {
            sum = num;
        }
        ans = Math.max(ans, sum);
    }
    return ans;
}

3.动态规则

走一步看一步

思路:

  1. 找到落脚点
  2. 通过落脚点之外的内容,找到关联
  3. 关联统一递归or循环

面试题:
实现当前算法求和
数组,每一项等于前两项之和
[0,1,1,2,3,5,8]
F(0) = 0, F(1) = 1, F(3) = 1, F(4) = 2, ……, F(n) = F(n-1) + F(n-2) 其中n>1


const fib = function(n) {
    if (n < 2) {
        return n;
    }

    let pre = 0;
    let next = 0;
    let result = 1;

    for(let i = 2; i <= n; i++) {
        pre = next;
        next = result;
        result = pre + next;
    }

    return result;
}

4.图与 图算法

构成:边集合 和 顶点集合
分类:有向图、无向图、构造图

// 试题 实现图类
class Graph {
    constructor(v) {
        this.vertices = v; // 顶点数
        this.edges = 0; // 边集合
        this.arr = [];
        // 初始化元素集合 => 多少个顶点就有多少个元素
        for(let i = 0; i < this.vertices; i++) {
            this.arr[i] = [];
        }
    }
    showGraph() {
        for (let i = 0; i < this.vertices; i ++) {
            let str = i + '->';
            for(let j = 0; j < this.vertices; j++) {
                if(this.arr[i][j] !== undefined) {
                    str += this.arr[i][j] + '';
                }
            }
        }
        console.log(str);
    }
    addEdge(v, w) {
        this.arr[v].push(w);
        this.arr[w].push(v);
        this.edges++;
    }
    // traverse() {}
}

// 图解决深度优先问题
// 起始点开始搜索,直到最终顶点 => 再返回追溯 => 没有路径

// 1. 结构化补充
constructor() {
    // super()
    this.marked = []; // 已经访问过的节点
    for(let i = 0; i < this.vertices; i++) {
        this.marked[i] = false;
    }
}

// 2. 深度优先开始
dfs(v) {
    this.marked[v] = true;
    if (this.arr[v] !== undefined) {
        console.log('visited' + v);
    }
    this.arr[v].forEach(w => {
        if(!this.marked[w]) {
            this.dfs(w);
        }
    })
}

// 3. 广度优先
// 1. 查找当前节点相邻的顶点,依次访问,由近及远
// 2. 取出下一个顶点,加入到marked已访问列表
// 3. 相邻未访问顶点添加到组织队列
bfs(s) {
    let queue = [];
    this.marked[s] = true;
    queue.push(s);
    while(queue.length > 0) {
        let v = queue.shift();

        if(v !== undefined) {
            console.log('visited' + v);
        }
        this.arr[v].forEach(w => {
            if (!this.marked[w]) {
                this.marked[w] = ture;
                queue.push(w);
            }
        })
    }
}

// 面试题 最短路径方法
// 利用广度优先天然查找路径的方式

// 1. 保存记录一个顶点到另一个顶点的所有边 - edgeTo
// 2. 每遇到一个未标记的顶点,除了标记,还需要从列表中添加边,从顶点连到当前顶点

constructor() {
    // super()
    this.edgeTo = [];
}

bfs(s) {
    let queue = [];
    this.marked[s] = true;
    queue.push(s);
    while(queue.length > 0) {
        let v = queue.shift();

        if(v !== undefined) {
            console.log('visited' + v);
        }
        this.arr[v].forEach(w => {
            if (!this.marked[w]) {
                this.marked[w] = ture;
                this.edgeTo[w] = v; // 做一个顶点连接记录
                queue.push(w);
            }
        })
    }
}

pathTo(t, v) {
    let source = t;
    
    // 检测
    for (let i = 0; i < this.vertices; i++) {
        this.marked[i] = false;
    }

    this.bfs(source);
    if (!this.marked[v]) {
        return undefined;
    }

    let path = [];
    let str = '';

    for(let i = v; i !== source; i = this.edgeTo[i]) {
        path.unshift(i);
    }
    path.unshift(source);

    for (let i in path) {
        if(i < path.length - 1) {
            str += path[i] + '->';
        } else {
            str += path[i];
        }
    }
    console.log(str);
    return path;
}

// %%%%%%%%%%%%%%%%%%%%%%%%
const g = new Graph(5);
g.addEdge(0, 1);
g.addEdge(0, 2);
// ……

g.pathTo(0, 4);

// 1. 图类 - 路径问题
// 2. 实现图类 - 边 + 顶点
// 3. 处理路径问题


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值