开篇
本篇文章旨在求解向量中n个连续子向量的最大和。题目来源是《编程珠玑》第8章《算法设计技术》。
问题描述
输入:具有n个浮点数的向量x;
输出:输入向量的任何连续子向量中的最大和;
例如:输入向量为31,-41,59,26,-53,58,97,-93,-23,84;
那么输出就是从59到97五个数的总和,即:187.
代码实现
简单算法–时间复杂度: O(n^3)
#include <stdio.h>
#define Max(a,b)((a)>(b)?(a):(b))
int main() {
int nums[10] = { 31,-41,59,26,-53,58,97,-93,-23,84 };
// 定义连续向量最大值
int maxsofar = 0;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
int sum = 0;
for (int k = i; k <= j; k++) {
sum += nums[k];
}
maxsofar = Max(maxsofar, sum);
}
}
printf("最大值为%d.\n", maxsofar);
return 0;
}
两个平方算法之一–时间复杂度O(n^2)
// 平方算法1---时间复杂度O(n^2)
int maxSubArraySumPro(int *nums, int length) {
int maxsofar = 0;
for (int i = 0; i < length; i++) {
int sum = 0;
for (int j = i; j < length; j++) {
sum += nums[j];
maxsofar = Max(maxsofar, sum);
}
}
return maxsofar;
}
两个平方算法之二–时间复杂度O(n^2)
// 平方算法2 --- 时间复杂度O(n^2)
int maxSubArraySumProPlus(int *nums, int length) {
int len = length + 1;
// 动态分配数组的内存
int *cumarr = (int *)malloc(len * sizeof(int));
if (cumarr == NULL) {
printf("内存分配失败!\n");
return -1;
}
cumarr[0] = 0;
for (int i = 1; i < len; i++) {
cumarr[i] = cumarr[i - 1] + nums[i - 1];
}
int maxsofar = nums[0];
for (int i = 0; i < length; i++) {
for (int j = i; j < length; j++) {
int sum = cumarr[j+1] - cumarr[i];
maxsofar = Max(maxsofar, sum);
}
}
free(cumarr);
return maxsofar;
}
分治算法–时间复杂度:O(logn)
// 分治算法实现 --- 时间复杂度O(logn)
int dnc(int l, int u, int *nums) {
if (l > u) { // 0元素数组
return 0;
}
if (l == u) { // 1元素数组
return Max(0, nums[l]);
}
int m = (l + u) / 2;
int lmax = 0; // 左边最大连续数组的和
int lsum = 0;
for (int i = m; i >= l; i--) {
lsum += nums[i];
lmax = Max(lmax, lsum);
}
int rmax = 0;
int rsum = 0;
for (int i = m + 1; i <= u; i++) {
rsum += nums[i];
rmax = Max(rmax, rsum);
}
return MaxT(lmax + rmax, dnc(l, m, nums), dnc(m + 1, u, nums));
}
Kadane’s算法实现–时间复杂度:O(n)
// Kadane's算法实现 --- 时间复杂度O(n)
int maxSubArraySumKadane(int* nums, int length) {
int maxsofar = nums[0]; // 初始化最大子数组和为数组的第一个元素
int currmax = nums[0]; // 当前子数组和初始化为数组的第一个元素
// 从第二个元素开始遍历数组
for (int i = 1; i < length; i++) {
// 当前子数组和为当前位置的元素与之前子数组和的和,如果当前元素本身更大,则重新开始一个子数组
currmax = (nums[i] > currmax + nums[i]) ? nums[i] : currmax + nums[i];
// 更新最大子数组和
maxsofar = (currmax > maxsofar) ? currmax : maxsofar;
}
return maxsofar;
}
代码总集
#include <stdio.h>
#include <stdlib.h>
#define Max(a,b)((a)>(b)?(a):(b))
// 辅助函数:返回三个数中的最大值
int MaxT(int a, int b, int c) {
int maxab = (a > b) ? a : b;
return (maxab > c) ? maxab : c;
}
// 简单算法--时间复杂度O(n^3)
int maxSubArraySum(int nums[], int length) {
// 定义连续向量最大值
int maxsofar = 0;
for (int i = 0; i < length; i++) {
for (int j = 0; j < length; j++) {
int sum = 0;
for (int k = i; k <= j; k++) {
sum += nums[k];
}
maxsofar = Max(maxsofar, sum);
}
}
return maxsofar;
}
// 平方算法1---时间复杂度O(n^2)
int maxSubArraySumPro(int *nums, int length) {
int maxsofar = 0;
for (int i = 0; i < length; i++) {
int sum = 0;
for (int j = i; j < length; j++) {
sum += nums[j];
maxsofar = Max(maxsofar, sum);
}
}
return maxsofar;
}
// 平方算法2 --- 时间复杂度O(n^2)
int maxSubArraySumProPlus(int *nums, int length) {
int len = length + 1;
// 动态分配数组的内存
int *cumarr = (int *)malloc(len * sizeof(int));
if (cumarr == NULL) {
printf("内存分配失败!\n");
return -1;
}
cumarr[0] = 0;
for (int i = 1; i < len; i++) {
cumarr[i] = cumarr[i - 1] + nums[i - 1];
}
int maxsofar = nums[0];
for (int i = 0; i < length; i++) {
for (int j = i; j < length; j++) {
int sum = cumarr[j+1] - cumarr[i];
maxsofar = Max(maxsofar, sum);
}
}
free(cumarr);
return maxsofar;
}
// Kadane's算法实现 --- 时间复杂度O(n)
int maxSubArraySumKadane(int* nums, int length) {
int maxsofar = nums[0]; // 初始化最大子数组和为数组的第一个元素
int currmax = nums[0]; // 当前子数组和初始化为数组的第一个元素
// 从第二个元素开始遍历数组
for (int i = 1; i < length; i++) {
// 当前子数组和为当前位置的元素与之前子数组和的和,如果当前元素本身更大,则重新开始一个子数组
currmax = Max(nums[i], currmax + nums[i]);
// 更新最大子数组和
maxsofar = Max(currmax, maxsofar);
}
return maxsofar;
}
// 分治算法实现 --- 时间复杂度O(logn)
int dnc(int l, int u, int *nums) {
if (l > u) { // 0元素数组
return 0;
}
if (l == u) { // 1元素数组
return Max(0, nums[l]);
}
int m = (l + u) / 2;
int lmax = 0; // 左边最大连续数组的和
int lsum = 0;
for (int i = m; i >= l; i--) {
lsum += nums[i];
lmax = Max(lmax, lsum);
}
int rmax = 0;
int rsum = 0;
for (int i = m + 1; i <= u; i++) {
rsum += nums[i];
rmax = Max(rmax, rsum);
}
return MaxT(lmax + rmax, dnc(l, m, nums), dnc(m + 1, u, nums));
}
int main() {
int nums[10] = { 31,-41,59,26,-53,58,97,-93,-23,84 };
int maxSum = maxSubArraySumKadane(nums, 10);
// int maxSum = dnc(0, 9, nums);
printf("最大值为%d.\n", maxSum);
return 0;
}
注
上面的代码总体来说比较简单,此处就不过多解释了。值得一提的是,题目中要求的是浮点型,而我用的是int类型,这个是我实现的过程中的疏漏,还请谅解了。
希望本文对您能有所帮助,感谢阅读。