求解向量中连续子向量的最大和

开篇

本篇文章旨在求解向量中n个连续子向量的最大和。题目来源是《编程珠玑》第8章《算法设计技术》。

问题描述

输入:具有n个浮点数的向量x;

输出:输入向量的任何连续子向量中的最大和;

例如:输入向量为31,-41,59,26,-53,58,97,-93,-23,84;

那么输出就是从59到97五个数的总和,即:187.

代码实现

简单算法--时间复杂度: O(n^3)

c 复制代码
#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)

c 复制代码
// 平方算法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)

c 复制代码
// 平方算法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)

c 复制代码
// 分治算法实现 --- 时间复杂度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)

c 复制代码
// 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;
}

代码总集

c 复制代码
#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类型,这个是我实现的过程中的疏漏,还请谅解了。

希望本文对您能有所帮助,感谢阅读。

相关推荐
刚学HTML12 分钟前
leetcode 05 回文字符串
算法·leetcode
Yan.love25 分钟前
开发场景中Java 集合的最佳选择
java·数据结构·链表
stm 学习ing28 分钟前
HDLBits训练5
c语言·fpga开发·fpga·eda·hdlbits·pld·hdl语言
AC使者31 分钟前
#B1630. 数字走向4
算法
冠位观测者35 分钟前
【Leetcode 每日一题】2545. 根据第 K 场考试的分数排序
数据结构·算法·leetcode
古希腊掌管学习的神1 小时前
[搜广推]王树森推荐系统笔记——曝光过滤 & Bloom Filter
算法·推荐算法
qystca1 小时前
洛谷 P1706 全排列问题 C语言
算法
浊酒南街1 小时前
决策树(理论知识1)
算法·决策树·机器学习
就爱学编程2 小时前
重生之我在异世界学编程之C语言小项目:通讯录
c语言·开发语言·数据结构·算法
学术头条2 小时前
清华、智谱团队:探索 RLHF 的 scaling laws
人工智能·深度学习·算法·机器学习·语言模型·计算语言学