动态规划 所有题型的总结

1 动态规划

1.1 定义

动态规划的核心是状态和状态转移方程。

在记忆化搜索中,可以为正在处理的表项声明一个引用,简化对它的读写操作;

动态规划解决的是多阶段决策问题;

初始状态→│决策1│→│决策2│→…→│决策n│→结束状态

和分治法最大的区别在于:适合于用动态规划的问题,经过分解以后得到的子问题往往不是相互独立的(即下一个子阶段的求解是建立在上一个子阶段的基础之上,进行进一步的求解,而不是相互独立的问题)

动态规划问题一般由难到易分为一维动态规划,二维动态规划,多维动态规划,以及多变量动态规划问题。其中多维动态规划问题又可以进行降维。动态规划问题求解的最重要的一步就是求解出 状态转移方程

1.2 特性

  • 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理.
  • 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关
  • 有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势,动态规划可以避免多次计算)

1.3 例子

还是做题最实在!

1.3.1 最长公共子序列

问题描述:给定两个序列:X[1...m]和Y[1...n],求在两个序列中同时出现的最长子序列的长度。

如果按照最普通的方法,就是遍历所有可能的情况(将较短字符串中所有的子串和较长字符串中的子串进行比较),取所有可能的情况中最长的子串;

int DP::LongestCommonSubsequence(string &X, string &Y, int m, int n) {if (m == 0 || n == 0) {return 0;}if (X[m-1] == Y[n-1]) {return LongestCommonSubsequence(X, Y, m-1, n-1) + 1;}else {return max(LongestCommonSubsequence(X, Y, m-1, n), LongestCommonSubsequence(X, Y, m, n-1));}
}void DP::testLongestCommonSubstring() {string x = "abcdefg", y = "efg";int result = LongestCommonSubsequence(x, y, (int)x.size(), (int)y.size());cout << "result:" << result;
}

很显然,这花费的时间是指数级的,非常慢;

那么采用动态规划是怎么做的?

63175617-file_1492076587320_4053.png

思路:我们可以想象成树,两个字符串都分别进行发散,对于一个结点来说,左边是左边的字符串进行改变,右边则是右边的字符串进行改变,直到两个字符串都相等。

  • 第一步应该是找出递推公式:

46579538-file_1492072969643_1260b.png

这里的 C[i,j] 代表的意思是字符串 X 中到达下标 i 和字符串 Y 中到达下标 j 的时候的最长子串个数;

  • 第二步是写出伪代码
LCS(x,y,i,j)if x[i] = y[j]then C[i,j] ← LCS(x,y,i-1,j-1)+1else C[i,j] ← max{LCS(x,y,i-1,j),LCS(x,y,i,j-1)}return C[i,j]
  • 最后是写出代码

上面的伪代码对于每一种情况都会往前重新计算一遍,完全没有必要,用一个数组保存之前计算的值即可;

int DP::LongestCommonSubsequence(string &X, string &Y, int m, int n) {vector<vector<int>> dp(X.size() + 1, vector<int>(Y.size() + 1, 0));for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {// 因为是从1开始的,所以字符串下标要减去1if (X[i-1] == Y[j-1]) {dp[i][j] = dp[i-1][j-1] + 1;}else {dp[i][j] = max(dp[i-1][j], dp[i][j-1]);}}}return dp[m][n];
}void DP::testLongestCommonSubsequence() {string x = "abcdefg", y = "efg";int result = LongestCommonSubsequence(x, y, (int)x.size(), (int)y.size());cout << "result:" << result;
}

看看dp数组:

 0 0 0 0 0 00 1 1 1 1 10 1 2 2 2 20 1 2 3 3 30 1 2 3 3 30 1 2 3 3 30 1 2 3 4 40 1 2 3 4 5

参考文章
动态规划(Dynamic Programming)

1.3.2 最长公共子串

和上面最长公共子序列不同的是,子串要求连续,不像子序列只要顺序保证是正确的就行了,所以使用一个变量来记录;

/*************************************** // 最长公共子串问题***************************************/
int DP::LongestCommonSubstring(string &X, string &Y, int m, int n) {vector<vector<int>> dp(X.size() + 1, vector<int>(Y.size() + 1, 0));int max = 0;for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {// 因为是从1开始的,所以字符串下标要减去1if (X[i-1] == Y[j-1]) {if (dp[i-1][j-1]) {dp[i][j] = dp[i-1][j-1] + 1;}else {dp[i][j] = 1;}if (dp[i][j] > max) {max = dp[i][j];}}}}for (int i = 0; i <= m; i++) {for (int j = 0; j <= n; j++) {cout << " " << dp[i][j];}cout << endl;}return max;
}void DP::testLongestCommonSubstring() {string x = "abcdefg", y = "abcfg";int result = LongestCommonSubstring(x, y, (int)x.size(), (int)y.size());cout << "result:" << result << endl;
}

看看dp数组:

 0 0 0 0 0 00 1 0 0 0 00 0 2 0 0 00 0 0 3 0 00 0 0 0 0 00 0 0 0 0 00 0 0 0 1 00 0 0 0 0 2

可以发现,对角线上连续大于0的值则为长度;最长的子串为abc,长度为3,次长为fg,长度为2;

1.3.3 最长递增子序列

问题描述:给定一个序列:X[1...m],求在这个序列中出现的最长递增子序列的长度。

/*************************************** // 最长递增子串问题***************************************/
int DP::LongestIncreasingSubstring(string &X, int m) {vector<int> dp(X.size(), 0);int max = 0;for (int i = 0; i < m; i++) { //到达dp[i] = 1;for (int j = 0; j < i; j++) {if (X[i] > X[j]) {dp[i] = dp[j] + 1;}else { //因为是连续的,所以只要不符合就重置dp[i] = 1;}}}for (int i = 0; i < m; i++) {cout << " " << dp[i];if (dp[i] > max) {max = dp[i];}}cout << endl;return max;
}void DP::testLongestIncreasingSubstring() {string x = "babcak";int result = LongestIncreasingSubstring(x, (int)x.size());cout << "result:" << result << endl;
}

1.3.4 矩阵链乘积

题目描述

给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2…,n-1。如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。

思路

对于矩阵连乘问题,最优解就是找到一种计算顺序,使得计算次数最少;

假设 dp[i, j] 表示第 i 个矩阵到达第 j 个矩阵这段的最优解;

将矩阵连乘积 简记为A[i:j] ,这里i<=j.假设这个最优解在第k处断开,i<=k<j,则A[i:j]是最优的,那么A[i,k]和A[k+1:j]也是相应矩阵连乘的最优解。把i到j分成两部分,看哪种分法乘的次数最少,而k就是i到j中断开的部分,也就是两个括号中间的部分;

  • 状态转移方程
当i=j时,A[i,j]=Ai, m[i,j]=0;(表示只有一个矩阵,如A1,没有和其他矩阵相乘,故乘的次数为0)当i<j时,m[i,j]=min{m[i,k]+m[k+1,j] +pi-1*pk*pj} ,其中 i<=k<j

也就是

47640058-file_1492139887385_176a.jpg

实现

/*************************************** // 矩阵链乘积,求最小乘积次数***************************************/
void DP::MatrixChainMultiplication(vector<int> data, int n,vector<vector<int>>& m_dp, vector<vector<int>>& s_dp) {//矩阵段长度为1,则 dp[][] 中对角线的值为0,表示只有一个矩阵,没有相乘的.for(int i = 1;i<=n;i++)m_dp[i][i] = 0;// 从第二个开始(第一个也是0),当前的乘次数取决于下一个的乘次数// 对角线循环,r表示矩阵的长度(2,3…逐渐变长)for(int r = 2;r<=n;r++) {// 行循环for(int i = 1; i<=n-r+1; i++) {// 列的控制,当前矩阵段(Ai~Aj)的起始为Ai,尾为Ajint j = r+i-1;//例如对(A2~A4),则i=2,j=4,下面一行的m[2][4] = m[3][4]+p[1]*p[2]*p[4],即A2(A3A4)m_dp[i][j] = m_dp[i+1][j] + data[i-1]*data[i]*data[j]; //计算次数s_dp[i][j] = i;//记录断开点的索引//循环求出(Ai~Aj)中的最小数乘次数,遍历所有可能的情况for(int k = i+1 ; k<j;k++) {//将矩阵段(Ai~Aj)分成左右2部分(左m[i][k],右m[k+1][j])//再加上左右2部分最后相乘的次数(p[i-1] *p[k]*p[j])int t = m_dp[i][k] + m_dp[k+1][j] + data[i-1] *data[k]*data[j];if(t < m_dp[i][j]) {m_dp[i][j] = t;s_dp[i][j] = k;  //保存最小的,即最优的结果}}}}
}void DP::testMatrixChainMultiplication() {vector<int> data = {30,35,15,5,10,20,25};//记录6个矩阵的行和列,注意相邻矩阵的行和列是相同的vector<vector<int>> m_dp(7, vector<int>(7, 0));//存储第i个矩阵到第j个矩阵的计算代价(以乘法次数来表示)vector<vector<int>> s_dp(7, vector<int>(7, 0));//存储第i个矩阵到第j个矩阵的最小代价时的分为两部分的位置int n=6;//矩阵个数MatrixChainMultiplication(data, n , m_dp, s_dp);cout << "---计算代价---" << endl;for (int i = 0; i < m_dp.size(); i++) {for (int j = 0; j < m_dp[0].size(); j++) {cout << " " << m_dp[i][j];}cout << endl;}cout << "---最小代价时分为两边的位置" << endl;for (int i = 0; i < s_dp.size(); i++) {for (int j = 0; j < s_dp[0].size(); j++) {cout << " " << s_dp[i][j];}cout << endl;}
}

运行结果为:

---计算代价---0 0 0 0 0 0 00 0 15750 7875 9375 11875 151250 0 0 2625 4375 7125 105000 0 0 0 750 2500 53750 0 0 0 0 1000 35000 0 0 0 0 0 50000 0 0 0 0 0 0
---最小代价时分为两边的位置0 0 0 0 0 0 00 0 1 1 3 3 30 0 0 2 3 3 30 0 0 0 3 3 30 0 0 0 0 4 50 0 0 0 0 0 50 0 0 0 0 0 0

表示第i个矩阵到第j个矩阵的计算代价矩阵m[i][j]和表示第i个矩阵到第j个矩阵的最小代价时的分为两部分的位置矩阵s[i][j]的结果如下图:

67577473-file_1492152626322_53c2.png

从上面左图的m矩阵可以看出任意第i个到第j个矩阵连乘的乘法次数。最终的加括号形式为:(A1(A2A3))((A4A5)A6)

参考文章
【算法导论】
动态规划之矩阵链乘法
0010算法笔记——【动态规划】矩阵连乘问题

1.3.5 数塔问题

问题描述:

数塔第i层有i个结点,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少?

73352147-file_1492106132432_113f6.png

用二维数组则为:

9
12  15
10  6   8
2    18 9   5
19  7   10  4   16

假设9首先被输入,是第 0 层,越往下层数不断递增;

思路

为了保证整条路径的和是最大的,下一层的走向取决于再下一层上的最大值是否已经求出才能决定,所以要做一个自顶向下的分析,自底向上的计算;

  • 状态转移方程
dp[i][j] = max(dp[i+1][j], dp[i+1][j+1]) + data[i][j]

dp[i+1][j] 为左结点,dp[i+1][j+1] 为右结点;

实现

/*************************************** // 数塔问题***************************************/
int DP::MaxSumTower(vector<vector<int>> nums, int m, int n) {vector<vector<int>> dp(m, vector<int>(n, 0));// 用底层的值来初始化dp,m为行,n为列for (int i = 0; i < n; i++) {dp[m-1][i] = nums[m-1][i];}// 自底向上,父结点的最大值取决于左结点或者右结点的最大值for (int i = m-2; i >= 0; i--) {for (int j = 0; j < n; j++) {if (i >= j) { //过滤多余的dp[i][j] = std::max(dp[i+1][j], dp[i+1][j+1]) + nums[i][j];}}}for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {cout << " " << dp[i][j];}cout << endl;}return dp[0][0];
}

1.3.6 01背包问题

题目描述

有编号分别为a,b,c,d,e的五件物品,它们的重量分别是2,2,6,5,4,它们的价值分别是6,3,5,4,6,现在给你个承重为10的背包,如何让背包里装入的物品具有最大的价值总和?

45091788-file_1492155910906_10809.png

思路

dp[x][y] 表示体积不超过 y 且可选前 x 种物品的情况下的最大总价值

递归关系:

  • mp[0][y] = 0
  • mp[x][0] = 0
  • 当 v[x] > y 时,mp[x][y] = mp[x-1][y]
  • 当 v[x] <= y 时,mp[x][y] = max{ mp[x-1][y], p[x] + mp[x-1][y-v[x]] }

解释如下:

  • 表示体积不超过 y 且可选前 0 种物品的情况下的最大总价值,没有物品可选,所以总价值为 0
  • 表示体积不超过 0 且可选前 x 种物品的情况下的最大总价值,没有物品可选,所以总价值为 0
  • 因为 x 这件物品的体积已经超过所能允许的最大体积了,所以肯定不能放这件物品, 那么只能在前 x-1 件物品里选了
  • x 这件物品可能放入背包也可能不放入背包,所以取前两者的最大值就好了, 这样就将前两种情况都包括进来了

实现

/*************************************** // 01背包问题***************************************/
int DP::ZeroOneBackpack(vector<Goods> goods, int limit_weight) {int m = goods.size();int n = limit_weight;vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));// 没有选择物品的时候价值为0for (int i = 1; i < n; i++) {dp[0][i] = 0;}// 重量为0的时候什么物品都选不了,价值自然也为0for (int i = 1; i < m; i++) {dp[i][0] = 0;}for (int i = 1; i <= m; i++) {for (int j = 1; j <= n; j++) {if (goods[i-1].weight > j) { //超出限制的重量dp[i][j] = dp[i-1][j];}else { //可能放入背包也可能不放入背包,取两者情况的最大值dp[i][j] = std::max(dp[i-1][j], dp[i-1][j - goods[i-1].weight] + goods[i-1].value);}}}for (int i = 0; i < m; i++) {for (int j = 0; j < n; j++) {cout << " " << dp[i][j];}cout << endl;}return dp[m][n];
}void DP::testZeroOneBackpack() {vector<Goods> goods;goods.emplace_back(0, 0);goods.emplace_back(60, 10);goods.emplace_back(100, 20);goods.emplace_back(120, 30);int result = ZeroOneBackpack(goods, 50);cout << "result:" << result << endl;
}

1.3.7 最大连续子序列之和

问题描述:给定一个序列:X[1...m],求在这个序列中出现的最大的连续子序列之和。

  • 状态转移方程
dp[i] = std::max(dp[i-1] + nums[i], nums[i]);
  • 实现
/*************************************** // 最大连续子序列和***************************************/
int DP::MaxContinusSubsequenceSum(int* nums, int m) {vector<int> dp(m, 0);int max = INT_MIN;dp[0] = nums[0];for (int j = 1; j < m; j++) {dp[j] = std::max(dp[j-1] + nums[j], nums[j]);}for (int i = 0; i < m; i++) {cout << " " << dp[i];if (dp[i] > max) {max = dp[i];}}cout << endl;return max;
}void DP::testMaxContinusSubsequenceSum() {int data[] = {1,-2,3,-1,7};int result = MaxContinusSubsequenceSum(data, 5);cout << "result:" << result << endl;
}

转载于:https://www.cnblogs.com/George1994/p/6710675.html

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

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

相关文章

美智库:马赛克战是人工智能与自主系统支撑的决策中心战

来源&#xff1a;国防科技要闻编者按2020年2月11日&#xff0c;美战略与预算评估中心发布报告《马赛克战&#xff1a;利用人工智能和自主系统实施决策中心战》。针对大国战略竞争&#xff0c;报告建议美国防部摒弃当前以消耗战为中心的理念&#xff0c;采用决策中心战。报告分析…

echarts山东地图_用 Python 绘制个人足迹地图

前两年&#xff0c;足迹地图小程序风靡朋友圈&#xff0c;一时间大家都流行晒自己的旅行地图。但是&#xff0c;笔者最近体验了好几款足迹地图的小程序&#xff0c;发现这些小程序虽然号称是足迹地图&#xff0c;但最多只是展示到省级别&#xff0c;无法精确到市级别&#xff0…

AI 芯片发展的前世今生

来源&#xff1a;《微纳电子与智能制造》期刊作者&#xff1a;任 源、潘 俊、刘京京、何燕冬、何 进现代电子产品和设备在诸如通信 、娱乐 、安全和医疗保健等许多方面改善了我们的生活质量 &#xff0c;这主要是因为现代微电子技术的发展极大地改变了人们的日常工作和互动方式…

用户解锁不存在_苹果推送iOS 13.5测试版,戴口罩解锁更顺畅

目前最新的 iOS 系统正式版为 13.4.1&#xff0c;之前苹果已经开始 iOS 13.4.5 的测试工作&#xff0c;并于 4 月 16 日推送了 Beta2 版本。令人意外的是&#xff0c;今日凌晨苹果为参与测试的设备直接推送了 iOS 13.5 的测试版更新&#xff0c;而且是 Beta3 版本(「iOS 13.5 B…

shell for循环1到100_浅谈Linux下shell 编程的for循环常用的6种结构

浅谈Linux下shell 编程的for循环常用的6种结构1、 常用for循环结构(1)for 变量 in 值1 值2 值3...do程序块儿done(2)for 变量 in 命令 (或者$())do程序块儿done(3)for 变量 in {1..100}do程序块儿done(4)for 变量 in "$"do程序块儿done(5)for 变量 in /etc/*.confdo程…

案例163:基于微信小程序的校园二手交易平台系统设计与开发

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

密歇根大学28页最新《GANs生成式对抗网络综述:算法、理论与应用》最新论文,带你全面了解GAN技术趋势...

来源&#xff1a;专知【导读】生成式对抗网络&#xff08;Generative Adversarial Networks&#xff0c;GANs&#xff09;作为近年来的研究热点之一&#xff0c;受到了广泛关注&#xff0c;每年在机器学习、计算机视觉、自然语言处理、语音识别等上大量相关论文发表。密歇根大学…

201521123035《Java程序设计》第八周学习总结

1. 本周学习总结 1.1 以你喜欢的方式&#xff08;思维导图或其他&#xff09;归纳总结集合与泛型相关内容。 1.2 选做&#xff1a;收集你认为有用的代码片段 //泛型方法&#xff0c;打印MyStack的所有元素的薪水&#xff0c;不管MyStack中的元素是Employee类型或者Employee的子…

x79主板bios设置详解_BIOS(主板)常用功能:设置启动磁盘

BIOS是什么&#xff1f;BIOS是英文"Basic Input Output System"的缩写&#xff0c;翻译成中文名称就是"基本输入输出系统"。BIOS是个人电脑启动时加载的第一个软件&#xff0c;是连接电脑硬件和软件的枢纽&#xff0c;有多重要就不言而喻了吧&#xff01;B…

《自然-神经科学》发表脑智卓越中心关于昼夜节律中枢的研究成果

来源&#xff1a;脑智卓越中心昼夜节律在生物体中广泛存在&#xff0c;对调节人们一天之中的运动、睡眠、代谢等诸多生理过程起着重要的作用。目前认为哺乳动物的昼夜节律是由位于大脑中的视交叉上核&#xff08;Suprachiasmatic Nucleus, SCN&#xff09;控制的。SCN能够接收视…

mybatis 打印sql_mybatis-plus 3.1.0 发布,划重点一大波升级

mybatis-plus 是一款 Mybatis 动态 SQL 自动注入 Mybatis 增删改查 CRUD 操作中间件&#xff0c; 减少你的开发周期优化动态维护 XML 实体字段&#xff0c;无入侵全方位 ORM 辅助层让您拥有更多时间吃鸡、陪家人、陪朋友。更新日志升级 mybatis 到 3.5.0 版本升级 mybatis-spri…

201521123059 《Java程序设计》第八周学习总结

1. 本周学习总结 1.1 以你喜欢的方式&#xff08;思维导图或其他&#xff09;归纳总结集合与泛型相关内容。 1.2 选做&#xff1a;收集你认为有用的代码片段 简单泛型定义&#xff1a; public class Pair<T> {public Pair(T first, T second) {this.first first; this.…

mysql driver 读写分离_Mysql主从复制和读写分离实践

1、主从复制原理MySQL之间数据复制的基础是二进制日志文件(binary log file)。一台MySQL数据库一旦启用二进制日志后&#xff0c;其作为master&#xff0c;它的数据库中所有操作都会以“事件”的方式记录在二进制日志中&#xff0c;其他数据库作为slave通过一个I/O线程与主服务…

二十世纪最伟大的10大算法

来源&#xff1a;数学中国发明十大算法的其中几位算法大师1、1946 蒙特卡洛方法[1946: John von Neumann, StanUlam, and Nick Metropolis, all at the Los Alamos Scientific Laboratory, cook upthe Metropolis algorithm, also known as the Monte Carlo method.]1946年&…

mybatis 动态字段与表中不一样_8.mybatis的基本工作流程(2.0)※

mybatis的基本工作流程1.读取配置文件&#xff0c;配置文件包含数据库连接信息和Mapper映射文件或者Mapper包路径。2.有了这些信息就能创建SqlSessionFactory&#xff0c;SqlSessionFactory的生命周期是程序级,程序运行的时候建立起来,程序结束的时候消亡3.SqlSessionFactory建…

判断表达式值是否为空_如何在 Python 中判断列表是否为空

在判断列表是否为空时&#xff0c;你更喜欢哪种方式&#xff1f;决定因素是什么&#xff1f;在 Python 中有很多检查列表是否是空的方式&#xff0c;在讨论解决方案前&#xff0c;先说一下不同方法涉及到的不同因素。我们可以把判断表达式可以分为两个阵营&#xff1a;对空列表…

《Lancet》发表全球学者联合声明!

来源&#xff1a;中国生物技术网 2020年2月18日&#xff0c;《LANCET》上发表通讯&#xff08;Correspondence&#xff09;文章&#xff0c;全球科学家发表声明反对阴谋论&#xff0c;全力支持奋战在疫情一线的中国科研技术工作者。就像病毒没有国界一样&#xff0c;科学也没有…

“哥德尔不完备定理”到底说了些什么?

来源&#xff1a; 赵昊彤科学网博客链接地址&#xff1a;http://blog.sciencenet.cn/blog-409681-1067019.html 【编者按&#xff1a;不知为何&#xff1f;一直不相信已有的数理、物理、生理、心理、管理……能够研究好人机融合智能系统。究其因&#xff0c;需要出现新的数/物…

ghost镜像浏览器_新电脑,GHOST装不进系统?不要急,跟我来

前几天&#xff0c;朋友转了台新电脑&#xff0c;用的是第十代CPU I3 10100&#xff0c;什么都安装好了&#xff0c;也按要求做了GPT分区&#xff0c;用GHOST安装了WIN10系统&#xff0c;可是重启时就是进不去&#xff0c;在BOOT选项里根本看不到硬盘。这是为什么呢&#xff1f…

python异步消费kafka_Kafka 通过python简单的生产消费实现

使用CentOS6.5、python3.6、kafkaScala 2.10 - kafka_2.10-0.8.2.2.tgz (asc, md5) 一、下载kafka 下载地址 https://kafka.apache.org/downloads 里面包含zookeeper二、安装Kafka 1、安装zookeeper mkdir /root/kafka/ tar -vzxf kafka_2.10-0.8.2.2cd /root/kafka/kafka_2.10…