查找旋转数组最小值

算法介绍

求对于长度为N的数组A,求子数组的和接近0的子数组。
例如:

 求取算法介绍

定义n长度的空间sum[0…N-1],sum[i]是A的前i项和。

并且有sum[i+1]=sum[i]+A[i+1]。

首先对sum[i]进行排序,找到求和最接近的2个值。

同时记录使得值最小的数组最短的那一组。

如图:

 

 通过求取求和值最接近的一组数据可以找到零子数组对应的位置,之后判断是否是最短,即可求出最终零子数组的具体对应位置。

算法详解

第一步:逐位求和

第二步:对求和排序

第三步:寻找排序后相邻差最小值

第四步:记录位置

由于本文采用的是分治法排序,因此算法复杂度为O(NlogN)

void devide(int *A, int n) {
	int *sum;
	int *original;
	int firstPos = 0;
	int secondPos = 0;
    // 用于记录sum相减的第一个值
	int firstNum = 0;
    // 用于记录sum相减的第二个值
	int secondNum = 0;
    // 创建求和数组用于排序
	sum = (int*)malloc(sizeof(int)*n);
    // 用于存储原始求和数组,用以判断零子数组位置
	original = (int*)malloc(sizeof(int)*n);
    // 求取具体求和值
	for (int i = 0; i < n; i++) {
		sum[i]=A[i];
	}
	sum[0] = A[0];
	for (int i = 1; i < n; i++) {
		sum[i] = sum[i - 1] + A[i];
	}
    
    // 将求和值存储下来
	for (int i = 0; i < n; i++) {
		original[i] = sum[i];
	}
    
    // 进行排序,排序算法在后面给出,应用的是分治法
	sort(sum, 0, n - 1);


    // 定义sum排序后相邻值相减后的最小值
	int *min;
	int *originalMin;
	min = (int*)malloc(sizeof(int)*(n - 1));
	originalMin = (int*)malloc(sizeof(int)*(n - 1));
	min[0] = sum[1] - sum[0];
	for (int i = 2; i < n; i++) {
		min[i-1] = sum[i] - sum[i - 1];
	}

    // 记录使得sum相减最小时两个用来相减值得具体数据
	int less = min[0];
	for (int i = 0; i < n - 1; i++) {
		if (less > min[i]) {
			less = min[i];
			firstNum = sum[i];
			secondNum = sum[i + 1];
		}
	}

    // 获取零子数组的起始坐标
	for (int i = 0; i < n; i++) {
		if (original[i] == firstNum) {
			firstPos = i;
			break;
		}
	}

    // 获取零子数组的终止坐标
	for (int i = 0; i < n; i++) {
		if (i != firstPos && original[i] == secondNum) {
			secondPos = i;
			break;
		}
	}

    // 打印零子数组
	for (int i = firstPos + 1; i < secondPos + 1; i++) {
		printf("A[%d]=%d\n", i, A[i]);
	}

}

分治排序法:

void sort(int *A, int from, int to) {
	if (from < to) {
		int mid = (from + to) / 2;
        //对半分解
		sort(A, from, mid);
		sort(A, mid + 1, to);
        // 合并
		merge(A, from, mid, to);
	}
}

合并算法:

void merge(int *A, int from, int mid, int to) {
	int i = from;
	int j = mid + 1;
	int t = 0;
	int *tmp = (int*)malloc(sizeof(int)*(8));
	while (i <= mid && j <= to) {
		if (A[i] <= A[j]) {
			tmp[t++] = A[i++];
		}
		else {
			tmp[t++] = A[j++];
		}
	}

	while (i <= mid) {
		tmp[t++] = A[i++];
	}

	while (j <= to) {
		tmp[t++] = A[j++];
	}

	t = 0;

	while (from <= to) {
		A[from++] = tmp[t++];
	}
}

参考资料:

七月算法:https://www.julyedu.com/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值