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

开篇

本篇文章旨在求解向量中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类型,这个是我实现的过程中的疏漏,还请谅解了。

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

相关推荐
库玛西6 分钟前
现代 C++ 智能指针全景指南:从 RAII 思想到工业级实践
c语言·开发语言·c++·笔记·面试
AC赳赳老秦13 分钟前
风控岗应用:OpenClaw 采集公开司法与经营异常数据,自动生成企业风险评估报告
大数据·c语言·数据库·人工智能·python·php·openclaw
qeen871 小时前
【数据结构】自平衡二叉搜索树各种旋转算法原理解析及AVL树的C++实现
数据结构·c++·算法
lucas_AI1 小时前
1.2B 小模型赢过 235B 大模型:NaviDC-OCR 把文档解析卷明白了
人工智能·深度学习·算法
程序员与背包客_CoderZ2 小时前
Linux D-Bus通信协议详解:从入门到C/C++编码实战
linux·服务器·c语言·c++·嵌入式硬件·嵌入式软件·dbus
冻柠檬飞冰走茶2 小时前
PTA基础编程题目集 7-35有理数均值(C++语言实现)
开发语言·数据结构·c++·算法·均值算法
民乐团扒谱机2 小时前
【微实验】倒谱算法(Cepstrum)深度解析:原理、数学推导与代码实现
人工智能·算法·语音识别
嵌入式阿蔡3 小时前
HAL库 vs LL库 vs 寄存器:到底用哪个?
c语言·stm32·单片机·嵌入式硬件·嵌入式实时数据库
Yyyyyy~3 小时前
【C】C语言常见概念
c语言
Nil2083 小时前
leetcode 189轮转数组
数据结构·算法·leetcode