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

开篇

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

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

相关推荐
肥猪猪爸15 分钟前
使用卡尔曼滤波器估计pybullet中的机器人位置
数据结构·人工智能·python·算法·机器人·卡尔曼滤波·pybullet
linux_carlos15 分钟前
环形缓冲区
数据结构
readmancynn27 分钟前
二分基本实现
数据结构·算法
萝卜兽编程29 分钟前
优先级队列
c++·算法
Bucai_不才31 分钟前
【数据结构】树——链式存储二叉树的基础
数据结构·二叉树
盼海37 分钟前
排序算法(四)--快速排序
数据结构·算法·排序算法
一直学习永不止步1 小时前
LeetCode题练习与总结:最长回文串--409
java·数据结构·算法·leetcode·字符串·贪心·哈希表
Rstln1 小时前
【DP】个人练习-Leetcode-2019. The Score of Students Solving Math Expression
算法·leetcode·职场和发展
芜湖_2 小时前
【山大909算法题】2014-T1
算法·c·单链表
珹洺2 小时前
C语言数据结构——详细讲解 双链表
c语言·开发语言·网络·数据结构·c++·算法·leetcode