線性查詢法
阿新 • • 發佈:2021-01-22
字首和與差分
一維字首和:
定義:
字首和是指某序列的前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]
應用場景:
對於二維矩陣可以快速的求解某一個矩陣的面積
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 , 而不是原陣列複製一遍
所以,我們最後要寫回去!