基本思想:
该问题要求我们以较低的时间复杂度查询一段区间中的最值。最暴力的解法是将所有可能的区间序列化作为一个哈希表的键进行存储,值为区间内的最值,这样预处理的时间复杂度为O(n2),查询时间复杂度为O(1)。但这样不适用于对数组元素进行更新的操作,和getRangeSum的问题一样,这样子它的更新效率非常慢,对某个元素进行更新都要对所有包含该元素的区间进行更新,效率非常低下。这种情况下我们可以用线段树来解决。以查询最大值为例,线段树节点包含起始点和结束点以及区间内的最大值。递归调用build函数以二分的方式建立线段树,每当要更新元素时从根节点到叶子节点更新maximal,查询区间如果完全在当前节点左侧或右侧则循环,如果跨越中间位置则递归调用query函数,这种数据结构的更新和查询时间复杂度均为O(logn)。
1 struct SegmentTreeNode{ 2 SegmentTreeNode *left,*right; 3 int start,end; 4 int maximal; 5 SegmentTreeNode(int s,int e,int m):start(s),end(e),maximal(m){} 6 }; 7 8 class SegmentTree{ 9 public:10 SegmentTree(vector nums){11 root = build(nums,0,nums.size()-1);12 }13 SegmentTreeNode *getRoot(){14 return root;15 }16 private:17 SegmentTreeNode* build(vector &nums,int start,int end){18 if(start == end)19 return new SegmentTreeNode(start,end,nums[start]);20 SegmentTreeNode *left = build(nums,start,start+(end-start)/2);21 SegmentTreeNode *right = build(nums,start+(end-start)/2+1,end);22 SegmentTreeNode *r = new SegmentTreeNode(start,end,max(left->maximal,right->maximal));23 r->left = left;24 r->right = right;25 return r;26 }27 SegmentTreeNode *root;28 };29 30 class Solution{31 public:32 Solution(vector &nums):tree(nums){33 34 }35 void update(int index,int val){36 SegmentTreeNode *current = tree.getRoot();37 while(current->start != current->end){38 current->maximal = max(current->maximal,val);39 if(index > current->start+(current->end-current->start)/2)40 current = current->right;41 else42 current = current->left;43 }44 current->maximal = max(current->maximal,val);45 }46 int query(int begin,int end){47 SegmentTreeNode *current = tree.getRoot();48 while(begin != current->start || end != current->end){49 if(begin > current->start+(current->end-current->start)/2)50 current = current->right;51 else if(end <= current->start+(current->end-current->start)/2)52 current = current->left;53 else54 return max(query(begin,begin+(end-begin)/2),query(begin+(end-begin)/2+1,end));55 }56 return current->maximal;57 }58 private:59 SegmentTree tree;60 };