c++矩阵连乘的动态规划算法并输出_你在Java中用过动态规划吗?

1. 介绍

动态规划典型的被用于优化递归算法,因为它们倾向于以指数的方式进行扩展。动态规划主要思想是将复杂问题(带有许多递归调用)分解为更小的子问题,然后将它们保存到内存中,这样我们就不必在每次使用它们时重新计算它们。

要理解动态规划的概念,我们需要熟悉一些主题:

  1. 什么是动态规划?
  2. 贪心算法
  3. 简化的背包问题
  4. 传统的背包问题
  5. LCS-最长的共同子序列
  6. 利用动态规划的其他问题
  7. 结论

本文所有代码均为java代码实现。

2. 什么是动态规划?

动态规划是一种编程原理,可以通过将非常复杂的问题划分为更小的子问题来解决。这个原则与递归很类似,但是与递归有一个关键点的不同,就是每个不同的子问题只能被解决一次。

为了理解动态规划,我们首先需要理解递归关系的问题。每个单独的复杂问题可以被划分为很小的子问题,这表示我们可以在这些问题之间构造一个递归关系。让我们来看一个我们所熟悉的例子:斐波拉契数列,斐波拉契数列的定义具有以下的递归关系:

d8efe30e068b27f1cb31291fd8d31836.png

注意:递归关系是递归地定义下一项是先前项的函数的序列的等式。Fibonacci序列就是一个很好的例子。

所以,如果我们想要找到斐波拉契数列序列中的第n个数,我们必须知道序列中第n个前面的两个数字。

但是,每次我们想要计算Fibonacci序列的不同元素时,我们在递归调用中都有一些重复调用,如下图所示,我们计算Fibonacci(5):

cb3abd3fd9818fa13d9572e915321626.png

例如:如果我们想计算F(5),明显的我们需要计算F(3)和F(4)作为计算F(5)的先决条件。然而,为了计算F(4),我们需要计算F(3)和F(2),因此我们又需要计算F(2)和F(1)来得到F(3),其他的求解诸如此类。

这样的话就会导致很多重复的计算,这些重复计算本质上是冗余的,并且明显的减慢了算法的效率。为了解决这种问题,我们介绍动态规划。

在这种方法中,我们对解决方案进行建模,就像我们要递归地解决它一样,但我们从头开始解决它,记忆到达顶部采取的子问题(子步骤)的解决方案。因此,对于Fibonacci序列,我们首先求解并记忆F(1)和F(2),然后使用两个记忆步骤计算F(3),依此类推。这意味着序列中每个单独元素的计算都是O(1),因为我们已经知道前两个元素。

当使用动态规划解决问题的时候,我们一般会采用下面三个步骤:

  1. 确定适用于所述问题的递归关系
  2. 初始化内存、数组、矩阵的初始值
  3. 确保当我们进行递归调用(可以访问子问题的答案)的时候它总是被提前解决。

遵循这些规则,让我们来看一下使用动态规划的算法的例子:

3. 贪心算法

下面来以这个为例子:

Given a rod of length n and an array that contains prices of all pieces of size smaller than n. Determine the maximum value obtainable by cutting up the rod and selling the pieces.

3.1. 对于没有经验的开发者可能会采取下面这种做法

这个问题实际上是为动态规划量身定做的,但是因为这是我们的第一个真实例子,让我们看看运行这些代码会遇到多少问题:

public class naiveSolution {  static int getValue(int[] values, int length) { if (length <= 0) return 0; int tmpMax = -1; for (int i = 0; i < length; i++) { tmpMax = Math.max(tmpMax, values[i] + getValue(values, length - i - 1)); } return tmpMax; } public static void main(String[] args) { int[] values = new int[]{3, 7, 1, 3, 9}; int rodLength = values.length; System.out.println("Max rod value: " + getValue(values, rodLength)); }}

输出结果:

Max rod value: 17

该解决方案虽然正确,但效率非常低,递归调用的结果没有保存,所以每次有重叠解决方案时,糟糕的代码不得不去解决相同的子问题。

3.2.动态方法

利用上面相同的基本原理,添加记忆化并排除递归调用,我们得到以下实现:

public class dpSolution {  static int getValue(int[] values, int rodLength) { int[] subSolutions = new int[rodLength + 1]; for (int i = 1; i <= rodLength; i++) { int tmpMax = -1; for (int j = 0; j < i; j++) tmpMax = Math.max(tmpMax, values[j] + subSolutions[i - j - 1]); subSolutions[i] = tmpMax; } return subSolutions[rodLength]; } public static void main(String[] args) { int[] values = new int[]{3, 7, 1, 3, 9}; int rodLength = values.length; System.out.println("Max rod value: " + getValue(values, rodLength)); }}

输出结果:

Max rod value: 17

正如我们所看到的的,输出结果是一样的,所不同的是时间和空间复杂度。

通过从头开始解决子问题,我们消除了递归调用的需要,利用已解决给定问题的所有先前子问题的事实。

性能的提升

为了给出动态方法效率更高的观点的证据,让我们尝试使用30个值来运行该算法。一种算法需要大约5.2秒来执行,而动态解决方法需要大约0.000095秒来执行。

4. 简化的背包问题

简化的背包问题是一个优化问题,没有一个解决方案。这个问题的问题是 - “解决方案是否存在?”:

Given a set of items, each with a weight w1, w2... determine the number of each item to put in a knapsack so that the total weight is less than or equal to a given limit K.

给定一组物品,每个物品的重量为w1,w2 ......确定放入背包中的每个物品的数量,以使总重量小于或等于给定的极限K

首先让我们把元素的所有权重存储在W数组中。接下来,假设有n个项目,我们将使用从1到n的数字枚举它们,因此第i个项目的权重为W [i]。我们将形成(n + 1)x(K + 1)维的矩阵M。M [x] [y]对应于背包问题的解决方案,但仅包括起始数组的前x个项,并且最大容量为y

例如

假设我们有3个元素,权重分别是w1=2kg,w2=3kg,w3=4kg。利用上面的方法,我们可以说M [1] [2]是一个有效的解决方案。这意味着我们正在尝试用重量阵列中的第一个项目(w1)填充容量为2kg的背包。

在M [3] [5]中,我们尝试使用重量阵列的前3项(w1,w2,w3)填充容量为5kg的背包。这不是一个有效的解决方案,因为我们过度拟合它。

4.1. 矩阵初始化

当初始化矩阵的时候有两点需要注意:

Does a solution exist for the given subproblem (M[x][y].exists) AND does the given solution include the latest item added to the array (M[x][y].includes).

给定子问题是否存在解(M [x] [y] .exists)并且给定解包括添加到数组的最新项(M [x] [y] .includes)。

因此,初始化矩阵是相当容易的,M[0][k].exists总是false,如果k>0,因为我们没有把任何物品放在带有k容量的背包里。

另一方面,M[0][0].exists = true,当k=0的时候,背包应该是空的,因此我们在里面没有放任何东西,这个是一个有效的解决方案。

此外,我们可以说M[k][0].exists = true,但是对于每个k来说 M[k][0].includes = false。

注意:仅仅因为对于给定的M [x] [y]存在解决方案,它并不一定意味着该特定组合是解决方案。在M [10] [0]的情况下,存在一种解决方案 - 不包括10个元素中的任何一个。这就是M [10] [0] .exists = true但M [10] [0] .includes = false的原因。

4.2.算法原则

接下来,让我们使用以下伪代码构造M [i] [k]的递归关系:

if (M[i-1][k].exists == True):  M[i][k].exists = True M[i][k].includes = Falseelif (k-W[i]>=0):  if(M[i-1][k-W[i]].exists == true): M[i][k].exists = True M[i][k].includes = Trueelse:  M[i][k].exists = False

因此,解决方案的要点是将子问题分为两种情况:

  1. 对于容量k,当存在第一个i-1元素的解决方案
  2. 对于容量k-W [i],当第一个i-1元素存在解决方案

第一种情况是不言自明的,我们已经有了问题的解决方案。

第二种情况是指了解第一个i-1元素的解决方案,但是容量只有一个第i个元素不满,这意味着我们可以添加一个第i个元素,并且我们有一个新的解决方案!

4.3. 实现

下面这何种实现方式,使得事情变得更加容易,我们创建了一个类Element来存储元素:

public class Element {  private boolean exists; private boolean includes; public Element(boolean exists, boolean includes) { this.exists = exists; this.includes = includes; } public Element(boolean exists) { this.exists = exists; this.includes = false; } public boolean isExists() { return exists; } public void setExists(boolean exists) { this.exists = exists; } public boolean isIncludes() { return includes; } public void setIncludes(boolean includes) { this.includes = includes; }}

接着,我们可以深入了解主要的类:

public class Knapsack {  public static void main(String[] args) { Scanner scanner = new Scanner (System.in); System.out.println("Insert knapsack capacity:"); int k = scanner.nextInt(); System.out.println("Insert number of items:"); int n = scanner.nextInt(); System.out.println("Insert weights: "); int[] weights = new int[n + 1]; for (int i = 1; i <= n; i++) { weights[i] = scanner.nextInt(); } Element[][] elementMatrix = new Element[n + 1][k + 1]; elementMatrix[0][0] = new Element(true); for (int i = 1; i <= k; i++) { elementMatrix[0][i] = new Element(false); } for (int i = 1; i <= n; i++) { for (int j = 0; j <= k; j++) { elementMatrix[i][j] = new Element(false); if (elementMatrix[i - 1][j].isExists()) { elementMatrix[i][j].setExists(true); elementMatrix[i][j].setIncludes(false); } else if (j >= weights[i]) { if (elementMatrix[i - 1][j - weights[i]].isExists()) { elementMatrix[i][j].setExists(true); elementMatrix[i][j].setIncludes(true); } } } } System.out.println(elementMatrix[n][k].isExists()); }}

唯一剩下的就是解决方案的重建,在上面的类中,我们知道解决方案是存在的,但是我们不知道它是什么。

为了重建,我们使用下面的代码:

List solution = new ArrayList<>(n);if (elementMatrix[n][k].isExists()) {  int i = n; int j = k; while (j > 0 && i > 0) { if (elementMatrix[i][j].isIncludes()) { solution.add(i); j = j - weights[i]; } i = i - 1; }}System.out.println("The elements with the following indexes are in the solution:" + (solution.toString()));

输出:

Insert knapsack capacity: 12 Insert number of items: 5 Insert weights: 9 7 4 10 3 true The elements with the following indexes are in the solution: [5, 1]

背包问题的一个简单变化是在没有价值优化的情况下填充背包,但现在每个单独项目的数量无限。

通过对现有代码进行简单调整,可以解决这种变化:

// Old code for simplified knapsack problemelse if (j >= weights[i]) {  if (elementMatrix[i - 1][j - weights[i]].isExists()) { elementMatrix[i][j].setExists(true); elementMatrix[i][j].setIncludes(true); }}// New code, note that we're searching for a solution in the same// row (i-th row), which means we're looking for a solution that// already has some number of i-th elements (including 0) in it's solutionelse if (j >= weights[i]) {  if (elementMatrix[i][j - weights[i]].isExists()) { elementMatrix[i][j].setExists(true); elementMatrix[i][j].setIncludes(true); }}

5. 传统的背包问题

利用以前的两种变体,现在让我们来看看传统的背包问题,看看它与简化版本的不同之处:

Given a set of items, each with a weight w1, w2... and a value v1, v2... determine the number of each item to include in a collection so that the total weight is less than or equal to a given limit k and the total value is as large as possible.

在简化版中,每个解决方案都同样出色。但是,现在我们有一个找到最佳解决方案的标准(也就是可能的最大值)。请记住,这次我们每个项目都有无限数量,因此项目可以在解决方案中多次出现。

在实现中,我们将使用旧的类Element,其中添加了私有字段value,用于存储给定子问题的最大可能值:

public class Element {  private boolean exists; private boolean includes; private int value; // appropriate constructors, getters and setters}

实现非常相似,唯一的区别是现在我们必须根据结果值选择最佳解决方案:

public static void main(String[] args) {  // Same code as before with the addition of the values[] array System.out.println("Insert values: "); int[] values = new int[n + 1]; for (int i=1; i <= n; i++) { values[i] = scanner.nextInt(); } Element[][] elementMatrix = new Element[n + 1][k + 1]; // A matrix that indicates how many newest objects are used // in the optimal solution. // Example: contains[5][10] indicates how many objects with // the weight of W[5] are contained in the optimal solution // for a knapsack of capacity K=10 int[][] contains = new int[n + 1][k + 1]; elementMatrix[0][0] = new Element(0); for (int i = 1; i <= n; i++) { elementMatrix[i][0] = new Element(0); contains[i][0] = 0; } for (int i = 1; i <= k; i++) { elementMatrix[0][i] = new Element(0); contains[0][i] = 0; } for (int i = 1; i <= n; i++) { for (int j = 0; j <= k; j++) { elementMatrix[i][j] = new Element(elementMatrix[i - 1][j].getValue()); contains[i][j] = 0; elementMatrix[i][j].setIncludes(false); elementMatrix[i][j].setValue(M[i - 1][j].getValue()); if (j >= weights[i]) { if ((elementMatrix[i][j - weights[i]].getValue() > 0 || j == weights[i])) { if (elementMatrix[i][j - weights[i]].getValue() + values[i] > M[i][j].getValue()) { elementMatrix[i][j].setIncludes(true); elementMatrix[i][j].setValue(M[i][j - weights[i]].getValue() + values[i]); contains[i][j] = contains[i][j - weights[i]] + 1; } } } System.out.print(elementMatrix[i][j].getValue() + "/" + contains[i][j] + " "); } System.out.println(); } System.out.println("Value: " + elementMatrix[n][k].getValue());}

输出:

Insert knapsack capacity: 12 Insert number of items: 5 Insert weights: 9 7 4 10 3 Insert values: 1 2 3 4 5 0/0 0/0 0/0 0/0 0/0 0/0 0/0 0/0 0/0 1/1 0/0 0/0 0/0 0/0 0/0 0/0 0/0 0/0 0/0 0/0 2/1 0/0 1/0 0/0 0/0 0/0 0/0 0/0 0/0 0/0 3/1 0/0 0/0 2/0 6/2 1/0 0/0 5/1 9/3 0/0 0/0 0/0 0/0 3/0 0/0 0/0 2/0 6/0 1/0 4/1 5/0 9/0 0/0 0/0 0/0 5/1 3/0 0/0 10/2 8/1 6/0 15/3 13/2 11/1 20/4 Value: 20

6. Levenshtein Distance

另一个使用动态规划的非常好的例子是Edit Distance或Levenshtein Distance。

Levenshtein Distance就是两个字符串A,B,我们需要使用原子操作将A转换为B:

  1. 字符串删除
  2. 字符串插入
  3. 字符替换(从技术上讲,它不止一个操作,但为了简单起见,我们称之为原子操作)

这个问题是通过有条理地解决起始字符串的子串的问题来处理的,逐渐增加子字符串的大小,直到它们等于起始字符串。

我们用于此问题的递归关系如下:

c60e622a9a129bc91075310587b64979.png

如果a == b则c(a,b)为0,如果a = = b则c(a,b)为1。

实现:

public class editDistance {  public static void main(String[] args) { String s1, s2; Scanner scanner = new Scanner(System.in); System.out.println("Insert first string:"); s1 = scanner.next(); System.out.println("Insert second string:"); s2 = scanner.next(); int n, m; n = s1.length(); m = s2.length(); // Matrix of substring edit distances // example: distance[a][b] is the edit distance // of the first a letters of s1 and b letters of s2 int[][] distance = new int[n + 1][m + 1]; // Matrix initialization: // If we want to turn any string into an empty string // the fastest way no doubt is to just delete // every letter individually. // The same principle applies if we have to turn an empty string // into a non empty string, we just add appropriate letters // until the strings are equal. for (int i = 0; i <= n; i++) { distance[i][0] = i; } for (int j = 0; j <= n; j++) { distance[0][j] = j; } // Variables for storing potential values of current edit distance int e1, e2, e3, min; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { e1 = distance[i - 1][j] + 1; e2 = distance[i][j - 1] + 1; if (s1.charAt(i - 1) == s2.charAt(j - 1)) { e3 = distance[i - 1][j - 1]; } else { e3 = distance[i - 1][j - 1] + 1; } min = Math.min(e1, e2); min = Math.min(min, e3); distance[i][j] = min; } } System.out.println("Edit distance of s1 and s2 is: " + distance[n][m]); }}

输出:

Insert first string: man Insert second string: machine Edit distance of s1 and s2 is: 3

如果你想了解更多关于Levenshtein Distance的解决方案,我们在另外的一篇文章中用python实现了 Levenshtein Distance and Text Similarity in Python, 使用这个逻辑,我们可以将许多字符串比较算法归结为简单的递归关系,它使用Levenshtein Distance的基本公式

7. 最长共同子序列(LCS)

这个问题描述如下:

Given two sequences, find the length of the longest subsequence present in both of them. A subsequence is a sequence that appears in the same relative order, but not necessarily contiguous.

给定两个序列,找到两个序列中存在的最长子序列的长度。子序列是以相同的相对顺序出现的序列,但不一定是连续的.

阐明:

如果我们有两个字符串s1="MICE"和s2="MINCE

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

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

相关文章

spark中dataframe解析_SparkSql 中 JOIN的实现

Join作为SQL中一个重要语法特性&#xff0c;几乎所有稍微复杂一点的数据分析场景都离不开Join&#xff0c;如今Spark SQL(Dataset/DataFrame)已经成为Spark应用程序开发的主流&#xff0c;作为开发者&#xff0c;我们有必要了解Join在Spark中是如何组织运行的。SparkSQL总体流程…

含枚举类型的函数声明_02Golang基础类型

基础类型命名Go语言中的函数名、变量名、常量名、类型名、语句标号和包名等所有的命名&#xff0c;都遵循一个简单的命名规则&#xff1a;一个名字必须以一个字母&#xff08;Unicode字母&#xff09;或下划线开头&#xff0c;后面可以跟任意数量的字母、数字或下划线。大写字母…

将xscj指定为当前数据库_通过网络连接数据库模式Hive的搭建过程详解

最近在搭建通过网络直接连接数据库模式的Hive时总是在启动的时候报各种错误&#xff0c;所以今天&#xff0c;我们来总结一下这种模式的Hive的搭建过程。【数据库安装】安装mysqlyum install mysql-server -y配置&#xff1a;启动mysql服务&#xff1a;service mysqld start设置…

游戏脚本代码大全_按键精灵】一个很好学的脚本

这【按键精灵】一个很好学的脚本命令名称&#xff1a;GetPixelColor 得到指定点颜色命令功能&#xff1a;得到指定位置的点的颜色命令参数&#xff1a;参数1 整数型&#xff0c;屏幕X坐标参数2 整数型&#xff0c;屏幕Y坐标返 回 值&#xff1a;【按键精灵】一个很好学的脚本字…

标记三维点_便携式3D扫描仪全自动三坐标测量机三维扫描设计扫描测量摄影

项目简介客户产品该客户的产品是铝铸件&#xff0c;铸件的很多位置没有太高的精度要求&#xff0c;但是铸件加工出来的孔位需要严格对上装配的位置&#xff0c;精加工的面要求却又特别高&#xff0c;并且孔位之间相距较远。客户的困难 由于产品要求较高&#xff0c;一般卡尺量具…

python画图显示不了中文_Python使用matplotlib绘图无法显示中文问题的解决方法

本文实例讲述了Python使用matplotlib绘图无法显示中文问题的解决方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a; 在python中&#xff0c;默认情况下是无法显示中文的&#xff0c;如下代码&#xff1a; import matplotlib.pyplot as plt # 定义文本框和箭头格式 d…

软件测试语句覆盖,软件测试中的语句覆盖,分支覆盖,条件覆盖以及路径覆盖...

我举一个简单的例子来解释一下语句覆盖&#xff0c;分支覆盖&#xff0c;条件覆盖以及路径覆盖的相关知识&#xff0c;如果有不对的地方&#xff0c;恳请各位同行指正&#xff1a;举例说明&#xff1a;if Atrue and Btrue then Action1if Ctrue or Dtrue then Action2这是一个很…

按钮点击没有反应_时控开关按键没反应怎么办?

当时市场上时控开关大体分为两种&#xff1a;按键式时控开关和蓝牙时控开关。按键式定时开关不用多做介绍&#xff0c;市场上已经存在很多年了&#xff0c;无论是校时、手动控制开关、设置定时时间&#xff0c;都需要手动接触按键进行调试控制&#xff0c;操作起来相对繁琐一些…

postman替换快捷键ctrl加什么_电脑截图快捷键ctrl加什么

无论我们使用电脑聊天&#xff0c;打游戏还是看视频&#xff0c;都不可避免会使用到截图的功能。下面小编来告诉大家windows自带的截图组合键吧。希望可以帮助到大家。www.aiwin10.com电脑截图快捷键是【ctrl】加【PrScrn】&#xff0c;使用这个组合键截屏&#xff0c;获得的是…

代码整理工具_整理了 11 个好用的代码质量审核和管理工具

点击上方“Python编程时光”&#xff0c;选择“加为星标”第一时间关注Python技术干货&#xff01;来源&#xff1a;云智时代https://www.toutiao.com/i6771334551873520131如今&#xff0c;代码质量分析和审核已成为每个企业的基本流程。随着开源代码库使用的增加&#xff0c;…

vue点击其它侧边栏收缩_企业微信聊天侧边栏功能怎么开启?聊天侧边栏有什么用?...

腾讯的企业微信上线以来一直在默默的优化更新&#xff0c;今年8月份悄悄上新了聊天侧边栏功能。作为一款主打移动端办公的软件&#xff0c;企业微信上线聊天侧边栏有什么用&#xff1f;聊天侧边栏是啥聊天侧边栏是企业微信的一个全新功能&#xff0c;为了方便公司成员更好的与客…

侧边栏配置_企业微信上线“聊天侧边栏”功能,可在外部会话时快捷使用应用...

点击上方“蓝色字体”&#xff0c;选择 “设为星标”关键讯息&#xff0c;D1时间送达&#xff01;8月7日消息&#xff0c;企业微信发布全新2.8.10版本&#xff0c;新增“聊天侧边栏”功能&#xff0c;且同时支持PC端与移动端。成员在外部会话中&#xff0c;可通过侧边栏使用应用…

vlc文件服务器局域网,vlc流媒体服务器配置

vlc流媒体服务器配置 内容精选换一换本节操作以Windows Server 2012操作系统的弹性云服务器为例介绍实现多用户登录的操作步骤。Windows server2012服务器默认能够支持两个用户同时远程登录&#xff0c;而通过配置远程桌面会话主机和远程桌面授权&#xff0c;即可实现多用户远程…

db2导入发生错误显示不是绝对路径_python编程常见错误总结

对于python初学者,在编程过程中常犯的错误及解决办法进行汇总和解决。勇哥希望编写此文能帮到大家。下边是勇哥结合例子给大家现身说法&#xff1a; 第一例&#xff1a;缩进错误(IndentationError)图1python对缩进很敏感&#xff0c;python用缩进来划分语句块&#xff0c;对于同…

服务器通电显示黄灯,服务器内存亮黄灯

服务器内存亮黄灯 内容精选换一换本文介绍了裸金属服务器BMS产品新特性和对应的文档动态&#xff0c;新特性将在各个区域(Region)陆续发布&#xff0c;欢迎体验。当您购买的云服务器规格无法满足业务需要时&#xff0c;可参考本章节变更规格&#xff0c;升级vCPU、内存。对于部…

mybatis mysql 调用存储过程 多个返回值_图解MyBatis的SQL执行流程(干货)

前言MyBatis可能很多人都一直在用&#xff0c;但是MyBatis的SQL执行流程可能并不是所有人都清楚了&#xff0c;那么既然进来了&#xff0c;通读本文你将收获如下&#xff1a;1、Mapper接口和映射文件是如何进行绑定的2、MyBatis中SQL语句的执行流程3、自定义MyBatis中的参数设置…

华为手机显示解析服务器返回错误,ajax服务器返回错误

ajax服务器返回错误 内容精选换一换查询指定备份策略下的标签信息。URI格式GET /v2/{project_id}/backuppolicy/{policy_id}/tagsGET /v2/{project_id}/backuppolicy/{policy_id}/tags参数说明参数是否必选描述project_id是项目IDpolicy_id是策略ID请求示例GET /查询所有备份策…

pandas 对某一行标准化_Python中的神器Pandas,但是有人说Pandas慢...

如果你从事大数据工作&#xff0c;用Python的Pandas库时会发现很多惊喜。Pandas在数据科学和分析领域扮演越来越重要的角色&#xff0c;尤其是对于从Excel和VBA转向Python的用户。所以&#xff0c;对于数据科学家&#xff0c;数据分析师&#xff0c;数据工程师&#xff0c;Pand…

罗盘时钟编码代码_安全研究 | 利用macOS Dock实现代码的持久化执行

背景介绍近期&#xff0c;我一直在研究macOS上的一些持久化技术&#xff0c;尤其是如何利用低等级用户权限来修改文件以影响用户交互。对于macOS终端用户来说&#xff0c;交互最频繁的当属Dock了。在我的研究过程中&#xff0c;我发现了一个plist文件&#xff0c;它可以控制App…

xpress-mp优化实例精选_量化研究每周精选-20170711

本周为大家精选了5项机器学习/深度学习在量化投资中的相关资源&#xff0c;机器学习/深度学习是偏实践性学科&#xff0c;只有不断实践才能有所收获&#xff0c;纸上得来终觉浅&#xff0c;绝知此事要躬行&#xff01;BigQuant拥有海量的数据和主流开源框架&#xff0c;附能每一…