1. 程式人生 > 其它 >線性查詢法

線性查詢法

技術標籤:演算法資料結構c語言c++

字首和與差分

一維字首和:

定義:

​ 字首和是指某序列的前n項和

公式:
輸入:
	s[i] = arr[0]  		i = 0

​	s[i]=s[i−1]+arr[i]     i > 0 
輸出:
[left - right];

s[right] - s [left - 1];
應用場景:

可以快速的查詢某一個區間的和

Code

#include <stdio.h>
int main()
{
    int total;
    int left , right ; //求left - right 範圍的和
    scanf
("%d",&total); int arr[total] = {0}; int sum[total] = {0}; for( int i = 0 ; i < total ; i++ ) //資料寫入陣列,原陣列arr { scanf("%d",&arr[i]); } //求字首和 for( int i = 0 ; i < total ; i++ ) { if( i == 0 ) { sum[i] = arr[
i]; // 0下標等於0 } else { sum[i] = sum[i-1] + arr[i]; //字首和 } } scanf("%d%d",&left,&right); // [left right]的和 printf("%d" , sum[right] - sum[left - 1] ); return 0; }

二維字首和

定義:

矩陣的和

公式:
求sum:
	 s [ i ] [ j ] = s [ i ] [ j − 1 ] + s [ i − 1 ] [ j ] − s [ i − 1 ] [ j − 1 ] + a [ i ] [ j ] 
輸出:
 sum[x2 ] [y2] - sum[ x2 ] [y1-1] - sum[ x1-1 ] [ y2] + sum[x1-1] [y1-1] 
應用場景:

對於二維矩陣可以快速的求解某一個矩陣的面積

img

code

#include <Stdio.h>
int n = 3 , m = 4;
int arr[n][m] = { {1 , 5 , 6 , 8 }
				  {9 , 6  , 7 , 3 }
				  {5 , 3  , 2 ,  4}
								};
int sum[m][n];

void pre_sum()
{
//初始化開始	
	sum[0][0] = arr[0][0]; 	//0特殊位置 初始化
	//豎著的初始化
	for(int i = 1 ; i < n ; i++ )
	{
		sum[i][0] = sum[i-1][0] + arr[i][0];
	}
	//橫著的初始化
	for(int j = 1 ; j < m ; j++ )
	{
		sum[0][j] = sum[0][j-1] + arr[0][j];
	}
	for(int i = 1 ; i < n ; i++ )
	{
		for(int j = 1 ; j < m ; j++ )
		{
			sum[i][j] = sum[i-1][j] + sum[i][j-1] + arr[i][j] - sum[i-1][j-1];
		}
	}
//初始化結束
}
int getsum(int x1 ,int y1, int x2 ,int y2)
{
	//情況1: x1,y1在(0,0),矩陣很舒服,直接返回就ok 
	if( x1 == 0 && x2 == 0 )
	{
		return sum[x2][y2];	
	}
	//情況2:x1 為 0 ,左上角行為0 抽象為多行的一維字首和
    if( x1 == 0 )
    {
		return sum[x2][y2] - sum[x2][y1-1];
	}
	//情況3:y1 為 0 ,左上角列為0 ,抽象為多列的一維字首和
	if( y1 == 0 )
	{
		return sum[x2][y2] - sum[x1-1][y2];
	}
	
	return sum[x2][y2] - sum[x2][y1-1] - sum[x1-1][y2] + sum[x1-1][y1-1];
	

}

int main()
{
	
	//int n , m; //陣列規模
	//scanf("%d%d",&n,&m);
	//初始化的操作和二維動態規劃很像!	
	int x1 ,y1,x2,y2;
	scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
	pre_sum();
	int ans = getsum(x1,y2,x2,y2);
	printf("%d",ans);
	return 0;
}

差分

定義:

​ 差分就是將數列中的每一項分別與前一項做差

​ 一般認為:差分是字首和的逆運算

​ 差分序列第一個數原來的第一個數一樣

​ 開陣列的時候,要比原來的 arr 陣列多開一個大小

性質

​ 差分序列求字首和可得原序列

公式
求差分陣列:

​ 只需要對範圍[left , right ]

d[left] += val;
d[right + 1 ] -= val; 

​ 使差分陣列在left, right範圍內實現+ val ;

差分求字首和:
a[i]=a[i]+a[i−1]

差分求字首和為原陣列

應用場景

當求序列的某個區間 + / - val 時

Code

#include <Stdio.h>

void add(int left ,int right , int val)
{
	d[left] += val;
	d[right + 1] -= val; 
}
int main()
{
	int total , line;
	scanf("%d%d",&total,&line);
	for(int i = 0 ; i < total ; i++ )
	{
		scanf("%d",&arr[i]);	
	}
	int left , right,val;
	//假設1次
	scanf("%d%d%d",&left,&right,&val);
	add(left,right,val);
	
	//差分求字首和
	for(int i = 0 ; i < total; i++ )
	{
		d[i] += d[i-1];
	}
	
	//原序列和差分合並完成 + / - val
	for(int i = 0 ; i < total ; i++ )
	{
		arr[i] += d[i]; 
		printf("%d",arr[i]);
	}
	return 0;
}

對於下面這行

arr[i] += d[i]; 

因為我們差分陣列開的時全是0 , 而不是原陣列複製一遍

所以,我們最後要寫回去!