leecode 解题总结:307. Range Sum Query

来源:互联网 发布:lol韩服mac版 编辑:程序博客网 时间:2024/06/16 04:21
#include <iostream>#include <stdio.h>#include <vector>#include <string>#include <unordered_map>using namespace std;/*问题:Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive.The update(i, val) function modifies nums by updating the element at index i to val.Example:Given nums = [1, 3, 5]sumRange(0, 2) -> 9update(1, 2)sumRange(0, 2) -> 8Note:The array is only modifiable by the update function.You may assume the number of calls to update and sumRange function is distributed evenly.分析:此题是需要统计范围区间的值,但是会修改某个下标。因此一旦进行更新操作,就会需要重新统计范围的值更新的index位置处的值,将会影响统计[i,j],其中 j >= index。diff=nums.at(index) - value,其中value是nums在index原始位置处的值range(i ,j) = {range(i,j) + diff , if i <= index <= j              {range(i,j) , if i > index 或者 j < index如果再次涉及到新的更新index2,那么需要再次判断是否需要累加新的diff。因此实际上只需要:每次遍历新更新的位置,判断给定的区间中是否包含该更新位置,如果包含,就加上差值即可。遍历时间复杂度为O(n),总的复杂度为O(n)此时最简单的方法是都更新计算一遍sum,时间复杂度为O(n)输入:3(数组元素个数) 9(操作次数)1 3 5sumRange 0 2update 1 2sumRange 0 2update 1 1sumRange 0 2sumRange 0 0sumRange 2 2update 2 2sumRange 0 22 59 -8update 0 3sumRange 1 1sumRange 0 1update 1 -3sumRange 0 1输出:987154-8-50关键:报错:超时。参考解法:http://blog.csdn.net/fly_yr/article/details/502764871 当有新的位置i上的元素更新为val时,计算diff = val - nums.at(i)。同时更新第i下标位置元素为val,然后从i到size-1都更新原来计算的sum(i)实现更新。统计的时候正常统计即可。我采用的方法是:元素不更新,记录差值和对应下标,但是忽略了当前更新的元素对于后续计算累加和的影响。因此我的方法是错误的。对应超时。2 采用线段树来做。参考:http://lib.csdn.net/article/datastructure/18479原理:对数字转化为二进制,按照数字最低位的1将值分层。从右向左增加一位,数字翻一倍。求最低位的1,lowbit(val) = -val & val,这个根据补码的性质:负数的补码等于正数补码加1因此一个数与其相反数取与是得到最低位的1,比如8:0000 1000-8:1111 1111 1111 ...1111 1000 8:00000000 0000 ...0000 1000 lowbit(8)= 8 (实际为1000) 索引4位置保存了数组1,2,3位置元素的4. 下述v表示下标对应层数,每一行代表lowbit分层, 每一列代表数组索引,较高lowbit的索引位置存储其本身 和其左边比其低的数值的和 lowbit 8v 4v 2vv 1vvvvv 下标123456789 线段树更新:数值更新需要更新父节点,寻找父节点 某索引的父节点索引=该索引本身+lowbit(该索引) 例如3的父节点索引=3+lowbit(3)=3+lowbit(-3&3)=3+1=4 注意:线段树下标从1开始。*/class NumArray {public:    NumArray(vector<int> nums) {        if(nums.empty()){return;}int size = nums.size();_nums = vector<int>(nums.begin() , nums.end());_sum = vector<int>(size + 1 , 0);//线段树下标必须从1开始for(int i = 0 ; i < size ; i++){add(i + 1 , nums.at(i));}    }//返回数num从右到左第一个1对应的数值,例如8,对应最低位的值1000,就是8//lowbit=-num & numint lowbit(int num){return ( (-num) & num) ;}//向下标index添加value,其父节点也需要添加,父节点=当前结点+lowbit(当前结点)void add(int index , int value){int size = _sum.size();while(index < size ){_sum.at(index) += value;index += lowbit(index);//寻找其父节点的下标}}    //更新元素,也是通过更改当前结点和当前结点的父节点的值    void update(int i, int val) {if(_nums.empty() || _sum.empty() || i < 0 || i >= _nums.size()){return;}int diff = val - _nums.at(i);add(i + 1 , diff);//累加后,需要更新原数组,注意下标累加_nums.at(i) = val;    }//查询从1到index所有元素的和,采用:以当前结点作为父节点,减去当前结点的lowbit得到其左边的父节点int sum(int index){int answer = 0;while(index > 0){answer += _sum.at(index);index -= lowbit(index);//寻找当前结点右边的父节点}return answer;}    //统计区间的元素    int sumRange(int i, int j) {if(_nums.empty() || _sum.empty() || i < 0 || j >= _nums.size()){return 0;}int sum1 = sum(j + 1);int sum2 = sum(i);int answer = sum1 - sum2;return answer;    }private:vector<int> _sum;vector<int> _nums;};void print(vector<int>& result){if(result.empty()){cout << "no result" << endl;return;}int size = result.size();for(int i = 0 ; i < size ; i++){cout << result.at(i) << " " ;}cout << endl;}void process(){ vector<int> nums; int value; int num; int commandNum; string command; int rangeMin; int rangeMax; int changeIndex; int changeValue; while(cin >> num >> commandNum ) { nums.clear(); for(int i = 0 ; i < num ; i++) { cin >> value; nums.push_back(value); } NumArray numArray(nums); for(int i = 0 ; i < commandNum ; i++) { cin >> command; if("update" == command) { cin >> changeIndex >> changeValue; numArray.update(changeIndex , changeValue); } else if("sumRange" == command) { cin >> rangeMin >> rangeMax; int answer = numArray.sumRange(rangeMin , rangeMax); cout << answer << endl; } } }}int main(int argc , char* argv[]){process();getchar();return 0;}/*class NumArray {public:    NumArray(vector<int> nums) {        if(nums.empty()){return;}//_nums.insert(_nums.begin() , nums.begin() , nums.end());//直接拷贝,用匿名vector_nums = vector<int>(nums.begin() , nums.end());int size = nums.size();_sum.push_back((long long)nums.at(0));for(int i = 1  ; i < size ; i++){_sum.push_back(_sum.at(i - 1) + (long long)nums.at(i));}    }    //更新元素    void update(int i, int val) {if(_nums.empty() || _sum.empty() || i < 0 || i >= _nums.size()){return;}        long long diff = (long long)val - (long long)_nums.at(i) ;//更新当前元素_nums.at(i) = val;//后续累加和都需要加上差值int size = _nums.size();for( ; i < size ; i++){_sum.at(i) += diff;}    }        int sumRange(int i, int j) {if(_nums.empty() || _sum.empty() || i < 0 || j >= _nums.size()){return 0;}long long result;if(i >= 1)// i = 1是可以取到的{//这里如果影响了i-1那么整个值都会影响result = _sum.at(j) - _sum.at(i-1);}else{result = _sum.at(j);}return ((int) result);    }private:vector<long long> _sum;vector<int> _nums;};*/

0 0
原创粉丝点击