子数组的最大累加和问题

输入一个整形数组,求数组中连续的子数组使其和最大。比如,数组x

应该返回 x[2..6]的和187.

这四个代码完成的功能都是求最大子数组(注意用词准确,子数组连续,子序列可以不连续)。

1)

for(i = 1; i <= n; i++)scanf("%d", &num[i]);
ans = num[1];
for(i = 1; i <= n; i++)
{for(j = i; j <= n; j++) {s = 0;for(k = i; k <= j; k++)s += num[k];if(s > ans)ans = s;}
}

分别枚举每一个子数组的起点和终点,也就是i和j,对于每一个起点和终点,对中间部分求和,也就是k循环。显然有n个起点n个终点(去重减半,不影响复杂度),所以子数组数量为O(N^2),对于每个子数组,我们要遍历一下求和,子数组长度1-n不等,遍历一遍平均O(N),乘起来O(N^3).(注意可能产生时间更大的错觉)。找出所有子数组中最大的即可。

2)

for(i = 1; i <= n; i++)scanf("%d", &num[i]);
sum[0] = 0;
for(i = 1; i <= n; i++) {sum[i] = num[i] + sum[i - 1];
}
ans = num[1];
for(i = 1; i <= n; i++) {for(j = i; j <= n; j++) {s = sum[j] - sum[i - 1];if(s > ans) ans = s;}
}

预处理出每一个以第一个元素开始,第i个元素结尾的子数组和,还是枚举每个起点终点,但是我们求和时直接减就可以了,不用遍历。对于每个子数组,操作为O(1),子数组数量O(N^2),所以总时间O(N^2).

3)

int solve(int left, int right)
{if(left == right)return num[left];mid = (left + right) / 2;lans = solve(left, mid);rans = solve(mid + 1, right);sum = 0, lmax = num[mid], rmax = num[mid + 1];for(i = mid; i >= left; i--) {sum += num[i];if(sum > lmax) lmax = sum;}sum = 0;for(i = mid + 1; i <= right; i++) {sum += num[i];if(sum > rmax) rmax = sum;}ans = lmax + rmax;if(lans > ans) ans = lans;if(rans > ans) ans = rans;return ans;
}int main(void)
{scanf("%d", &n);for(i = 1; i <= n; i++)scanf("%d", &num[i]);printf("%d\n", solve(1, n));return 0;
}

二分,求左右两边最大子数组,取最大。但是还有一种情况:包含断点的那些子数组也要考虑,请思考那两个那两个循环为什么那么写?最后逻辑为何正确?

4)动态规划入门思想

没有枚举,num[i]的含义是以下标i结尾的所有子数组中最大的。

遍历数组,对于第i个元素,它的所有子数组下标范围有[1,i],[2,i].....[i-1,i],还有它自己,我们看i-1个元素,他的子数组为[1,i-1],[2,i-1].....[i-1]。请想num[i]的含义,我们求i结尾的,只要把i-1结尾的最大加上i就好了,当然如果i-1结尾最大子数组是负的,i结尾最大子数组就是它本身。

为什么O(N)?时间省在哪里了?我们省掉了许多没必要的计算,计算i时,之前的数组和已经都计算过,朴素算法并没有记录下来,而是重复计算,造成时间浪费。算法优化的过程就是去掉重复计算的过程。

for(i = 1; i <= n; i++)scanf("%d", &num[i]);num[0] = 0;
ans = num[1];
for(i = 1; i <= n; i++)
{if(num[i - 1] > 0) num[i] += num[i - 1];elsenum[i] += 0;if(num[i] > ans) ans = num[i];
}

子矩阵的最大累加和问题

给一个矩阵,请找出一个矩阵中,和最大的子矩阵。

如果大家看懂了之前的讲解,我给个提示:利用第二个代码和第四个代码思想的结合

解释:

1   2  3   4

-1 -2  1   2

1   3   -2  1

-1  -2  -1  -3

如图是前三行整体最大

怎么做呢?

先用第二个代码的思想,我们进行预处理

每个数代表这一列到这个数位置截止,累加和。

1  2  3  4

0  0  4  6

1  3  2  7

0  1  1  4

然后,我们枚举每一列的起点和终点分别为第0,1,2,3行

然后压缩成一维来做

比如求1-3行的这个矩形,我们拿0和3行减一下就行了

0-1,1-2,1-3,4-4=-1,-1,-2,0就是1-3行压缩后的结果

然后按一维dp来做就好

public class SubMatrixMaxSum {public static int maxSum(int[][] m) {if (m == null || m.length == 0 || m[0].length == 0) {return 0;}int max = Integer.MIN_VALUE;int cur = 0;int[] s = null; // 累加数组for (int i = 0; i != m.length; i++) {s = new int[m[0].length];for (int j = i; j != m.length; j++) {cur = 0;for (int k = 0; k != s.length; k++) {s[k] += m[j][k];cur += s[k];max = Math.max(max, cur);cur = cur < 0 ? 0 : cur;}}}return max;}public static void main(String[] args) {int[][] matrix = { { -90, 48, 78 }, { 64, -40, 64 }, { -81, -7, 66 } };System.out.println(maxSum(matrix));}}

子数组的最大累乘积

题目:

给定一个double类型的数组arr,其中的元素可正、可负、可为0。返回子数组累乘的最大乘积。

思路:

假设以arr[i-1]结尾的数组最小累乘积为min,最大累乘积为max,那么以arr[i]结尾的数组的最大累乘积可能有三种情况。

  • max*arr[i]//本身乘之前的最大累乘
  • min*arr[i]//可能是负负得正变成最大的
  • arr[i]//可能就是它本身,比如之前的max小于1

public class SubArrayMaxProduct {public static double maxProduct(double[] arr) {if (arr == null || arr.length == 0) {return 0;}double max = arr[0];double min = arr[0];double res = arr[0];double maxEnd = 0;double minEnd = 0;for (int i = 1; i < arr.length; ++i) {maxEnd = max * arr[i];minEnd = min * arr[i];max = Math.max(Math.max(maxEnd, minEnd), arr[i]);min = Math.min(Math.min(maxEnd, minEnd), arr[i]);res = Math.max(res, max);}return res;}public static void main(String[] args) {double[] arr = { -2.5, 4, 0, 3, 0.5, 8, -1 };System.out.println(maxProduct(arr));}}

数组精选题目三连(5)相关推荐

  1. 数组精选题目三连(6)

    题目一:调整有序的arr数组,使得左半部分有序且不重复,不用保证右边是否有序. 思路:               u : 左边的最后位置,即0---u为答案               i : 从u ...

  2. 01背包和完全背包 的完整讲解版 包含 一维数组实现 和二维数组实现题目

    (二)01背包和完全背包 的完整讲解版 包含 一维数组实现 和二维数组实现题目 //有N件物品和一个容量为V的背包.第i件物品的体积是c[i],价值是w[i].求解将哪些物品装入背包可使价值总和最大. ...

  3. 数组(二):大厂面试不得不看的高频数组类型题目

    数组篇(二) LeetCode905:按奇偶排序数组 解题思路 代码实现 LeetCode11:盛水最多的容器 解题思路 代码实现 LeetCode66:加一 解题思路 代码实现 LeetCode12 ...

  4. 【C语言刷题】牛客网编程入门130精选题目(二)

    牛客网编程入门130题–精选(二) 本篇文章衔接博客:牛客网编程入门130–精选(一) 文章目录 牛客网编程入门130题--精选(二) 题目OJ链接 1.图形相似度 2.有序数组中插入一个数 3.有序 ...

  5. 算法总结——堆栈、字符串、数组类题目

    先说stack的题目 stack的实现:链表,数组 题目: (1)简单的:min stack,一个数组实现三个stack (2)经典的stack问题:经典汉诺塔问题,逆波兰式计算或者产生逆波兰式,简化 ...

  6. LeetCode 805数组切割题目

    题目链接:805. 数组的均值分割  (借用思路来自leetode大佬heren1229 - 力扣(LeetCode)) 题目要求将nums分为两个数组A和B,且A和B的平均数相等,那么就可以得出A和 ...

  7. python笔记之1-简单读入+循环、判断+数组+函数调用+题目Resistors in Parallel(18焦作)

    ....本来博主想一心一意搞算法和C++的,但今天的大数用C++写真的...心态爆炸,然后学了一波python...多路周折终于A了这题 python的语言在有了c语言的基础上其实还挺好学的...虽然 ...

  8. C语言关于字符串和字符数组的题目(差别)

    1.题目: 已有定义:char a[]="she",b[]={'s','h','e'};,以下叙述中正确的是(  )   C A)数组a和b的长度相同      B)a数组长度小于 ...

  9. 【二分查找延伸--实际算法应用】数组类题目

    声明:博主是基于labuladong微信公众号文章模板驱动刷题,进行的自我刷题感悟和记录在此. 模板详情见labuladong微信公众号文章文末:原创于自己在此基础上的笔记.感悟.整合其它文献和自己的 ...

最新文章

  1. SAP Business Explorer 初探
  2. Vue中用TypeScript改写JavaScript及装饰器使用
  3. python网站用什么数据库_使用python读取mysql数据库并进行数据的操作
  4. 判断release模式_AbstractQueuedSynchronizer共享模式与基于Condition的等待/通知
  5. web前端入门到实战:CSS3两大实用属性,以及网页制作技巧
  6. 数据库接口实验--php实现--
  7. div+css总结—FF下div不设置…
  8. 数据结构(王道计算机考研笔记)
  9. 服务器单核性能天梯图,台式机cpu性能排行(cpu单核性能天梯图)
  10. QQ游戏基本通信机制(QQ游戏外挂编写)
  11. 2008服务器系统开启ftp,2008服务器开启ftp服务
  12. Codeforces Round #444 (Div. 2)-贪心尺取-Ratings and Reality Shows
  13. 磕技术、筑平台,浪潮存储如何持续破局?
  14. HI3861学习笔记(17)——NFC标签NT3H1201使用
  15. JAVA加密--JCA、JCE、CSP概念、体系架构与使用示例
  16. 数据结构哈夫曼树(C语言版)
  17. jcyzoj1505: 原地tp
  18. uva 10808 - Rational Resistors
  19. 财路网每日原创推送:隐私计算让人工智能更智能
  20. Linux文件或者文件夹的管理

热门文章

  1. js for循环_JS 函数的执行时机(深入理解6个6)
  2. ARM汇编ADR,LDR等伪指令
  3. 基于C8051F040单片机的CAN总线测试模式研究
  4. 山西计算机网络技术专升本分数线_2020山西成考专升本招生补录第一批公告!附补录院校专业缺额表!...
  5. js 获取鼠标在画布的位置_云凤蝶如何打造媲美 sketch 的自由画布
  6. 【转】FPGA到底是啥?
  7. select switch语句总是搞混,总结如下
  8. 【转】2.3SharePoint服务器端对象模型 之 访问网站和列表数据(Part 3)
  9. sharepoint 2013 网站集解锁
  10. est.java 2 错误 找不到符号_找不到Cython/Python符号PyString\u Typ