Aprendizaje de algoritmos de lenguaje C (suma de la subserie más grande)

La suma de la subserie más grande

Hoy, he aprendido mucho sobre la subsecuencia continua más grande en los blogs de otras personas, y me centraré en repetir dos algoritmos que me gustan.

1

Use la matriz sum [i] para representar la suma del número del primero al i-ésimo, y use sum [j] -sum [i-1] para representar la suma del número del i-ésimo al jth, eliminando el bucle más interno, el código en lenguaje C es el siguiente:

#include <stdio.h>

//N是数组长度,num是待计算的数组,sum是数组前缀和,放在全局区是因为可以开很大的数组
int N, num[16384], sum[16384];

int main()
{
    
    
    //输入数据
    scanf("%d", &N);
    for(int i = 1; i <= N; i++)
        scanf("%d", &num[i]);
    
    //计算数组前缀和
    sum[0] = 0;
    for(int i = 1; i <= N; i++) {
    
    
        sum[i] = num[i] + sum[i - 1];
    }

    int ans = num[1]; //ans保存最大子数列和,初始化为num[1]能保证最终结果正确
    //i和j分别是枚举的子数列的起点和终点
    for(int i = 1; i <= N; i++) {
    
    
        for(int j = i; j <= N; j++) {
    
    
            int s = sum[j] - sum[i - 1];
            if(s > ans) ans = s;
        }
    }
    printf("%d\n", ans);

    return 0;
}

De acuerdo con el significado del blogger, también puede optimizarlo un poco, use la matriz num para guardar directamente la suma en lugar del grupo de elementos de suma:

#include <stdio.h>
int N, num[16384];

int main() {
    
    
	//输入数据
	scanf("%d", &N);
	for(int i = 1; i <= N; i++) {
    
    
		scanf("%d", &num[i]);//计算数组前缀和
		num[i] = num[i] + num[i - 1];
	}
	
	int ans = num[1]; //ans保存最大子数列和,初始化为num[1]能保证最终结果正确
	//i和j分别是枚举的子数列的起点和终点
	for(int i = 1; i <= N; i++) {
    
    
		for(int j = i; j <= N; j++) {
    
    
			int s = num[j] - num[i - 1];
			if(s > ans) ans = s;
		}
	}
	printf("%d\n", ans);

	return 0;
}

2

Divide y vencerás, es decir, usa la llamada recursiva de funciones para resolver este problema.
Usa una función para dividir una matriz en dos partes con la posición central como punto de división. La respuesta se puede dividir en tres casos:
1. El más grande el subnúmero se enumera a la izquierda
2. A la derecha
3. Al otro lado del punto de división, cada uno a la izquierda y a la derecha ocupa una parte.
En el caso de uno o dos, puede recurrir hasta que ocurra el tercer caso.
Aborde el tercer caso:
1. Usando el punto de división como punto de partida, encuentre los valores máximos en los lados izquierdo y derecho (debido al punto de partida determinado, la complejidad no es alta) y súmelos.
La idea es tan clara, entonces lo que tenemos que hacer es juzgar qué situación es suficiente, esto no es un problema, podemos seguir usando llamadas recursivas para encontrar la subsecuencia más grande de 1, 2 y luego comparar con la valor máximo en los lados izquierdo y derecho del punto de división.

int solve(int left,int right,int *num) {
    
    //左值,右值,数组地址 
	if(left==right) {
    
    //递归结束 
		return num[right];
	}
	int mid=right+left>>1;
	int lans =solve (right,mid,num);//Left Answer,即left max 
	int rans = solve (mid+1,left,num);//Right Answer

	int sum = 0, lmax = num[mid], rmax = num[mid + 1];
	for(int i = mid; i >= left; i--) {
    
    
		sum += num[i];
		if(sum > lmax) lmax = sum;
	}
	sum = 0;
	for(int i = mid + 1; i <= right; i++) {
    
    
		sum += num[i];
		if(sum > rmax) rmax = sum;
	}

	//答案是三种情况的最大值
	int ans = lmax + rmax;
	if(lans > ans) ans = lans;
	if(rans > ans) ans = rans;

	return ans;
}

Supongo que te gusta

Origin blog.csdn.net/seekerzhz/article/details/112976493
Recomendado
Clasificación