数据结构高级算法

 

目录

最小生成树

Kruskal(克鲁斯卡尔)(以边为核心)

9) 不相交集合(并查集合)

基础

Union By Size

图-相关题目

4.2 Greedy Algorithm

1) 贪心例子

Dijkstra

Prim

Kruskal

最优解(零钱兑换)- 穷举法 Leetcode 322

最优解(零钱兑换)- 贪心法 Leetcode 322

3) Huffman 编码问题

问题引入

Huffman 树

Huffman 编解码

4) 活动选择问题

无重叠区间-Leetcode 435

5) 分数背包问题

贪心法

6) 0-1 背包问题

贪心法

7) Set cover problem

4.3 Dynamic-Programming

1) Fibonacci

降维

2) 最短路径 - Bellman-Ford

3) 不同路径-Leetcode 62

降维

4) 0-1 背包问题

5) 完全背包问题

降维

6) 零钱兑换问题-Leetcode322

零钱兑换 II-Leetcode 518

7) 钢条切割问题

降维

类似题目 Leetcode-343 整数拆分

8) 最长公共子串

类似题目 Leetcode-718 最长重复子数组

两个字符串的删除操作-Leetcode 583

10) 最长上升子序列-Leetcode 300

11) Catalan 数

Leetcode-22 括号生成

买票找零问题

其它问题

12) 打家劫舍-Leetcode 198

13) Travelling salesman problem

其它题目

组合总和 IV-Leetcode 377


最小生成树

Prim
public class Prim {   public static void main(String[] args) {       Vertex v1 = new Vertex("v1");       Vertex v2 = new Vertex("v2");       Vertex v3 = new Vertex("v3");       Vertex v4 = new Vertex("v4");       Vertex v5 = new Vertex("v5");       Vertex v6 = new Vertex("v6");       Vertex v7 = new Vertex("v7");
​       v1.edges = List.of(new Edge(v2, 2), new Edge(v3, 4), new Edge(v4, 1));       v2.edges = List.of(new Edge(v1, 2), new Edge(v4, 3), new Edge(v5, 10));       v3.edges = List.of(new Edge(v1, 4), new Edge(v4, 2), new Edge(v6, 5));       v4.edges = List.of(new Edge(v1, 1), new Edge(v2, 3), new Edge(v3, 2),               new Edge(v5, 7), new Edge(v6, 8), new Edge(v7, 4));       v5.edges = List.of(new Edge(v2, 10), new Edge(v4, 7), new Edge(v7, 6));       v6.edges = List.of(new Edge(v3, 5), new Edge(v4, 8), new Edge(v7, 1));       v7.edges = List.of(new Edge(v4, 4), new Edge(v5, 6), new Edge(v6, 1));
​       List<Vertex> graph = List.of(v1, v2, v3, v4, v5, v6, v7);
​       prim(graph, v1);
​   }
​   static void prim(List<Vertex> graph, Vertex source) {       ArrayList<Vertex> list = new ArrayList<>(graph);       source.dist = 0;
​       while (!list.isEmpty()) {//选取当前顶点           Vertex min = chooseMinDistVertex(list);
//更新当前顶点           updateNeighboursDist(min);
//移除当前顶点           list.remove(min);           min.visited = true;           System.out.println("---------------");           for (Vertex v : graph) {               System.out.println(v);           }       }
​
​   }
​   private static void updateNeighboursDist(Vertex curr) {       for (Edge edge : curr.edges) {           Vertex n = edge.linked;           if (!n.visited) {               int dist = edge.weight;               if (dist < n.dist) {                   n.dist = dist;                   n.prev = curr;               }           }       }   }
​   private static Vertex chooseMinDistVertex(ArrayList<Vertex> list) {       Vertex min = list.get(0);       for (int i = 1; i < list.size(); i++) {           if (list.get(i).dist < min.dist) {               min = list.get(i);           }       }       return min;   }
}
 

初始

 DIJKSTRA算法

Kruskal(克鲁斯卡尔)(以边为核心)

public class Kruskal {   static class Edge implements Comparable<Edge> {       List<Vertex> vertices;       int start;       int end;       int weight;
​       public Edge(List<Vertex> vertices, int start, int end, int weight) {           this.vertices = vertices;           this.start = start;           this.end = end;           this.weight = weight;       }
​       public Edge(int start, int end, int weight) {           this.start = start;           this.end = end;           this.weight = weight;       }
​       @Override       public int compareTo(Edge o) {           return Integer.compare(this.weight, o.weight);       }
​       @Override       public String toString() {           return vertices.get(start).name + "<->" + vertices.get(end).name + "(" + weight + ")";       }   }
​   public static void main(String[] args) {       Vertex v1 = new Vertex("v1");       Vertex v2 = new Vertex("v2");       Vertex v3 = new Vertex("v3");       Vertex v4 = new Vertex("v4");       Vertex v5 = new Vertex("v5");       Vertex v6 = new Vertex("v6");       Vertex v7 = new Vertex("v7");
​       List<Vertex> vertices = List.of(v1, v2, v3, v4, v5, v6, v7);       PriorityQueue<Edge> queue = new PriorityQueue<>(List.of(               new Edge(vertices,0, 1, 2),               new Edge(vertices,0, 2, 4),               new Edge(vertices,0, 3, 1),               new Edge(vertices,1, 3, 3),               new Edge(vertices,1, 4, 10),               new Edge(vertices,2, 3, 2),               new Edge(vertices,2, 5, 5),               new Edge(vertices,3, 4, 7),               new Edge(vertices,3, 5, 8),               new Edge(vertices,3, 6, 4),               new Edge(vertices,4, 6, 6),               new Edge(vertices,5, 6, 1)       ));
​       kruskal(vertices.size(), queue);   }
​   static void kruskal(int size, PriorityQueue<Edge> queue) {       List<Edge> result = new ArrayList<>();       DisjointSet set = new DisjointSet(size);       while (result.size() < size - 1) {           Edge poll = queue.poll();           int s = set.find(poll.start);           int e = set.find(poll.end);           if (s != e) {//未相交               result.add(poll);               set.union(s, e);//相交           }       }
​       for (Edge edge : result) {           System.out.println(edge);       }   }
}

9) 不相交集合(并查集合)

基础

public class DisjointSet {   int[] s;   // 索引对应顶点   // 元素是用来表示与之有关系的顶点   /*       索引  0  1  2  3  4  5  6       元素 [0, 1, 2, 3, 4, 5, 6] 表示一开始顶点直接没有联系(只与自己有联系)
​   */
​   public DisjointSet(int size) {       s = new int[size];       for (int i = 0; i < size; i++) {           s[i] = i;       }   }
​   // find 是找到老大   public int find(int x) {       if (x == s[x]) {           return x;       }       return find(s[x]);   }
​   // union 是让两个集合“相交”,即选出新老大,x、y 是原老大索引   public void union(int x, int y) {       s[y] = x;   }
​   @Override   public String toString() {       return Arrays.toString(s);   }
​
}

路径压缩 直接改成老大

 public int find(int x) { // x = 2
    if (x == s[x]) {
        return x;
    }
    return s[x] = find(s[x]); // 0    s[2]=0
}

UnionBySize 

Union By Size
public class DisjointSetUnionBySize {   int[] s;   int[] size;//顶点个数多的当作老大比较合适 新的数组记录个数   public DisjointSetUnionBySize(int size) {       s = new int[size];       this.size = new int[size];       for (int i = 0; i < size; i++) {//初始化           s[i] = i;           this.size[i] = 1;       }   }
​   // find 是找到老大 - 优化:路径压缩   public int find(int x) { // x = 2       if (x == s[x]) {           return x;       }       return s[x] = find(s[x]); // 0    s[2]=0   }
​   // union 是让两个集合“相交”,即选出新老大,x、y 是原老大索引   public void union(int x, int y) {
//x 新老大 y新小弟
//        s[y] = x;       if (size[x] < size[y]) {
//y 老大 x小弟
//  s[x] = y;
//        size[y] = size[x] + size[y];//更新老大的元素个数           int t = x;           x = y;           y = t;       }       s[y] = x;       size[x] = size[x] + size[y];//更新老大的元素个数   }
​   @Override   public String toString() {       return "内容:"+Arrays.toString(s) + "\n大小:" + Arrays.toString(size);   }
​   public static void main(String[] args) {       DisjointSetUnionBySize set = new DisjointSetUnionBySize(5);
​       set.union(1, 2);       set.union(3, 4);       set.union(1, 3);       System.out.println(set);   }
​
​
}

图-相关题目

题目编号题目标题算法思想
547省份数量DFS、BFS、并查集
797所有可能路径DFS、BFS
1584连接所有点的最小费用最小生成树
743网络延迟时间单源最短路径
787K 站中转内最便宜的航班单源最短路径
207课程表拓扑排序
210课程表 II拓扑排序

4.2 Greedy Algorithm

1) 贪心例子

称之为贪心算法或贪婪算法,核心思想是

  1. 将寻找最优解的问题分为若干个步骤

  2. 每一步骤都采用贪心原则,选取当前最优解(局部最优->全局最优)

  3. 因为没有考虑所有可能,局部最优的堆叠不一定让最终解最优

贪心算法是一种在每一步选择中都采取在当前状态下最好或最优(即最有利)的选择,从而希望导致结果是最好或最优的算法。这种算法通常用于求解优化问题,如最小生成树、背包问题等。

贪心算法的应用:

  1. 背包问题:给定一组物品和一个背包,每个物品有一定的重量和价值,要求在不超过背包容量的情况下,尽可能多地装入物品。

  2. 活动选择问题:在一个活动集合中,每次只能参加一个活动,问如何安排时间以最大化所有活动的收益。

  3. 编辑距离问题:给定两个字符串,求它们之间的最小编辑距离(即将一个字符串转换为另一个字符串所需的最少操作次数)。

  4. 网络流问题:给定一张有向图和一些起点和终点,求最大流量。

  5. 找零问题:给定一定数量的硬币和需要找零的金额,求使用最少的硬币数。

常见问题及解答:

  1. 贪心算法一定会找到最优解吗? 答:不一定。贪心算法只保证在每一步选择中都是最优的,但并不能保证整个问题的最优解。例如,背包问题中的贪心算法可能会导致最后一个物品没有被装入背包。

  2. 如何判断一个问题是否适合用贪心算法解决? 答:一个问题如果可以用递归的方式分解成若干个子问题,且每个子问题都有明确的最优解(即局部最优),那么这个问题就可以用贪心算法解决。

  3. 贪心算法的时间复杂度是多少? 答:贪心算法的时间复杂度取决于问题的规模和具体实现。一般来说,对于规模较小的问题,贪心算法的时间复杂度可以达到O(nlogn)或O(n^2);对于规模较大的问题,可能需要O(n^3)或更高。

几个贪心的例子

Dijkstra
// ...
while (!list.isEmpty()) {   // 选取当前【距离最小】的顶点   Vertex curr = chooseMinDistVertex(list);   // 更新当前顶点邻居距离   updateNeighboursDist(curr);   // 移除当前顶点   list.remove(curr);   // 标记当前顶点已经处理过   curr.visited = true;
}
  • 没找到最短路径的例子:负边存在时,可能得不到正确解

  • 问题出在贪心的原则会认为本次已经找到了该顶点的最短路径,下次不会再处理它(curr.visited = true)

  • 与之对比,Bellman-Ford 并没有考虑局部距离最小的顶点,而是每次都处理所有边,所以不会出错,当然效率不如 Dijkstra

Prim
// ...
while (!list.isEmpty()) {   // 选取当前【距离最小】的顶点   Vertex curr = chooseMinDistVertex(list);   // 更新当前顶点邻居距离   updateNeighboursDist(curr);   // 移除当前顶点   list.remove(curr);   // 标记当前顶点已经处理过   curr.visited = true;
}
Kruskal
// ...
while (list.size() < size - 1) {   // 选取当前【距离最短】的边   Edge poll = queue.poll();   // 判断两个集合是否相交   int i = set.find(poll.start);   int j = set.find(poll.end);   if (i != j) { // 未相交       list.add(poll);       set.union(i, j); // 相交   }
}

其它贪心的例子

  • 选择排序、堆排序

  • 拓扑排序

  • 并查集合中的 union by size 和 union by height

  • 哈夫曼编码

  • 钱币找零,英文搜索关键字

    • change-making problem

    • find Minimum number of Coins

  • 任务编排

  • 求复杂问题的近似解

### 2) 零钱兑换问题#### 有几个解(零钱兑换 II)Leetcode 518```java
publi

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/670304.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

opensuse安装百度Linux输入法

前言 Linux下有输入法&#xff0c;拼音&#xff0c;百度的都有&#xff0c;但是用起来总感觉不如在windows下与安卓中顺手。 目前搜狗与百度都出了Linux的输入法&#xff0c;但是没有针对OpenSUSE的&#xff0c;只有ubuntu/deepin/UOS的安装包。 本文主要讲的如何把百度Linux输…

Java 获取 Linux服务器主机名称、内网ip、cpu使用率、内存使用率、磁盘使用率、JVM使用率

下面的代码直接打包带走使用 1、pom文件依赖 <dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.55</version> <!-- 请根据实际情况检查最新版本 --></dependency>2、代码 package…

51-22 BEVFormer、BEVFormer v2,Occupancy占用网络灵感源泉 论文精读

今天要读论文的是BEVFormer&#xff0c;有人说这是新一代自动驾驶感知融合的基石&#xff0c;有人说是后续Occupancy Network占用网络工作的灵感源泉。我们从题目《通过时空transformer从多摄像头图像中学习BEV表示》来看&#xff0c;这应该是BEV开山之作LSS论文的姊妹篇。 本…

什么是TCP三次握手、四次挥手?

&#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是小徐&#x1f947;☁️博客首页&#xff1a;CSDN主页小徐的博客&#x1f304;每日一句&#xff1a;好学而不勤非真好学者 &#x1f4dc; 欢迎大家关注&#xff01; ❤️ 1、三次握手 你(客户端)给一个朋友(服务器)打电…

数学建模:数据相关性分析(Pearson和 Spearman相关系数)含python实现

相关性分析是一种用于衡量两个或多个变量之间关系密切程度的方法。相关性分析通常用于探索变量之间的关系&#xff0c;以及预测一个变量如何随着另一个变量的变化而变化。在数学建模中&#xff0c;这是常用的数据分析手段。   相关性分析的结果通常用相关系数来表示&#xff…

Google C++编码规范

1、 头文件 所有头文件要能够自给自足(封装的足够完美)&#xff0c;用户和重构工具不用为特定的场合包含额外的头文件所有的头文件都应该有#define保护来阻止头文件被多重包含&#xff0c;命名格式当是: H尽量使用包含头文件的形式&#xff0c;而不是用前置声明的形式内联那些…

【LangChain-04】利用权重和偏差跟踪和检查LangChain代理的提示

利用权重和偏差跟踪和检查LangChain代理的提示 一、说明 考虑到&#xff08;生成&#xff09;人工智能空间&#xff0c;&#xff08;自主&#xff09;代理现在无处不在&#xff01;除了更强大且幸运的是开放的大型语言模型&#xff08;LLM&#xff09;之外&#xff0c;LangCh…

k8s学习-Service Account和RBAC授权

1.1 ServiceAccount 介绍 首先Kubernetes中账户区分为&#xff1a;User Accounts&#xff08;用户账户&#xff09; 和 Service Accounts&#xff08;服务账户&#xff09; 两种&#xff0c;它们的设计及用途如下&#xff1a; UserAccount是给kubernetes集群外部用户使用的&am…

【计算机二级考试C语言】C内存管理

C 内存管理 本章将讲解 C 中的动态内存管理。C 语言为内存的分配和管理提供了几个函数。这些函数可以在 <stdlib.h> 头文件中找到。 在 C 语言中,内存是通过指针变量来管理的。指针是一个变量,它存储了一个内存地址,这个内存地址可以指向任何数据类型的变量,包括整…

测试用例流程设计

测试用例流程设计 简介 测试用例流程设计是指在进行软件测试时&#xff0c;对测试用例的整体规划和组织的过程。它涉及到制定一系列测试用例&#xff0c;以确保对软件系统的各个方面进行全面、系统和有效的测试。 现有测试用例的问题 可维护性不高 低模块化性&#xff1a;测…

re:从0开始的CSS学习之路 2. 选择器超长大合集

0. 写在前面 虽然现在还是不到25的青年人&#xff0c;有时仍会感到恐慌&#xff0c;害怕不定的未来&#xff0c;后悔失去的时间&#xff0c;但细细想来&#xff0c;只有自己才知道&#xff0c;再来一次也不会有太多的改变。 CSS的选择器五花八门&#xff0c;而且以后在JavaScr…

docker部署docker管理工具easydockerweb

重要提示 功能比较少,建议体验一下即可 安装 docker run -it -d -p 10041:3000 -e EDW_USERNAMEadmin -e EDW_PASSWORDadmin -v /var/run/docker.sock:/var/run/docker.sock qfdk/easydockerweb 使用 概览 镜像管理 容器管理

vue - 指令(一)

看文章可以得到什么&#xff1f; 1.可以快速的了解并会使用vue的指令 2.可以加深你对vue指令的理解&#xff0c;知道每个指令代表什么功能​​​​​​​ 目录 什么是vue的指令&#xff1f;​​​​​​​ vue常见指令的使用 v-html v-show v-if v-else 和v-else-…

java多线程实现(二)Java并发容器和框架

一、CouncurrentHashMap 二、ConcurrentLinkedQueue 三、java中的阻塞队列 jdk7提供了7个阻塞队列 四、Fork / Join框架

SpringBoot日志插件log4J和slf4J的使用和比较含完整示例

点击下载《SpringBoot日志插件log4J和slf4J的使用和比较含完整示例》 1. 前言 本文主要介绍了在 Spring Boot 框架中如何使用 Log4j 和 Slf4j&#xff0c;并通过对比分析它们的优缺点&#xff0c;帮助读者更好地选择合适的日志记录工具。文章中提供了完整的示例代码&#xff…

Spring Data Envers 数据审计实战

随着各行各业信息化发展&#xff0c;决策者们越来越意识到数据版本追踪的重要性&#xff0c;尤其是上市公司&#xff0c;数据对于他们尤为重要。考虑到研发成本&#xff0c;对重要表单数据支持页面级的修改历史查看、对所有业务数据支持DB级的版本查看是一个不错的选择。 对于…

有奖调查 | @所有人,MatrixOne 有一份问卷邀您填写~

MO社区系统调查问卷 活动时间&#xff1a;即日起至2月17日 前言 PREFACE 在“信创”国产化操作系统的号召下&#xff0c;随着 CentOS 7 的维护周期接近尾声&#xff0c;社区很多小伙伴都在积极调研新的操作系统进行测试和更换。为最大程度的保障 MatrixOne 在社区使用场景下…

设计模式学习笔记(一):基本概念;UML

文章目录 参考面向对象的设计原则创建型模式结构型模式行为型模式 UML视图图&#xff08;Diagram&#xff09;模型元素(Model Element)通用机制类之间的关系关联关系复杂&#xff01;&#xff01;聚合关系组合关系 依赖关系泛化关系接口与实现关系 参考 https://github.com/fa…

2.0 Zookeeper 安装配置

Linux 安装 zookeeper 下载地址为: Apache ZooKeeper。 选择一稳定版本&#xff0c;本教程使用的 release 版本为3.4.14&#xff0c;下载并安装。 打开网址 https://www.apache.org/dyn/closer.lua/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz&#xff0c;看到如下界…

c#cad 创建-圆(二)

运行环境 vs2022 c# cad2016 调试成功 一、代码说明 这段代码是一个AutoCAD插件&#xff0c;用于在模型空间中创建一个圆形。 首先&#xff0c;我们需要定义一个命令类CreateCircleCommand&#xff0c;并在命名空间CreateCircleInCad中声明。 在CreateCircleCommand类中&a…