《程式設計珠璣》程式碼之路13:陣列如何線上性時間內實現多次區間修改

心理學演算法工程師發表於2018-11-26

給一個陣列,每次對某個區間增加某個值,如何線上性時間內完成。

比如一個陣列,剛開始都是0吧,如下表,第一行是下標:

0 1 2 3 4 5 6 7
0 0 0 0 0 0 0 0

操作 1 3 5,代表給下標1-3的元素都加5,有很多次這樣的操作。

正常來說,這個演算法複雜度為n^2。

要實現線性時間,就只能通過某種記錄方式,然後再通過記錄,還原出最後的資料。

我們開闢一個csum陣列,對每一波操作(left, right, value)有:

csum[left -1] -= value;

csum[right] += value;

然後對每一對三元操作都以同樣的方式記錄。

例如1 3 5操作完成後,csum陣列為:

0 1 2 3 4 5 6 7
-5 0 0 5 0 0 0 0

最後按照如下方式還原:

x[i] = x[i + 1] + csum[i];

0 1 2 3 4 5 6 7
0 5 5 5 0 0 0 0

就得到了區間修改後的陣列。

完整程式碼如下:

#include <iostream>
#include <cstdio>
#include <vector>

using namespace std;

vector<int> nums, csum;
const int NUMS = 10;
const int NINTERVAL = 3;
int main(){

	freopen("in.txt", "r", stdin);
	int value = 4;

	for (int i = 0; i < NUMS + 1; ++i){
		nums.push_back(0);
		csum.push_back(0);
	}
	
	int leftV[NINTERVAL] = {2, 3, 7};
	int rightV[NINTERVAL] = {4, 6, 9};

	for (int i = 0; i < NINTERVAL; ++i){
		if (leftV[i] - 1 >= 0){
			csum[leftV[i] - 1] -= value;
		}

		csum[rightV[i]] += value;
	}

	for (int i = NUMS - 1; i >= 0; --i){
		nums[i] = nums[i + 1] + csum[i];
	}

	for (int i = 0; i < NUMS; ++i){
		cout << nums[i] << endl;
	}

	return 0;
}

 

相關文章