lintcode-线段树

来源:互联网 发布:网络直播需要什么设备 编辑:程序博客网 时间:2024/06/06 04:02

本文对线段树做总结,主要给出基本概念以及相应的实际问题。
主要参考了这篇博客[一步一步理解线段树]

基本概念

线段树

线段树,类似区间树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(logn)。

线段树的每个节点表示一个区间,子节点则分别表示父节点的左右半区间,例如父亲的区间是[a,b],那么(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b]。

例子

下面我们从一个经典的例子来了解线段树,问题描述如下:从数组arr[0…n-1]中查找某个数组某个区间内的最小值,其中数组大小固定,但是数组中的元素的值可以随时更新。

一般解法

对这个问题一个简单的解法是:遍历数组区间找到最小值,时间复杂度是O(n),额外的空间复杂度O(1)。当数据量特别大,而查询操作很频繁的时候,耗时可能会不满足需求。

另一种解法:

另一种解法:使用一个二维数组来保存提前计算好的区间[i,j]内的最小值,那么预处理时间为O(n^2),查询耗时O(1), 但是需要额外的O(n^2)空间,当数据量很大时,这个空间消耗是庞大的,而且当改变了数组中的某一个值时,更新二维数组中的最小值也很麻烦。

我们可以用线段树来解决这个问题:

复杂度如下:

  • 预处理耗时O(n),因为对于含有N元素的线段树而言,大概要生成2n个节点。
  • 查询、更新操作O(logn),这是优于O(N)的。
  • 需要额外的空间O(n)

操作

创建线段树

题目:[创建线段树-I]

/** * Definition of SegmentTreeNode: * class SegmentTreeNode { * public: *     int start, end; *     SegmentTreeNode *left, *right; *     SegmentTreeNode(int start, int end) { *         this->start = start, this->end = end; *         this->left = this->right = NULL; *     } * } */class Solution {public:    /**     *@param start, end: Denote an segment / interval     *@return: The root of Segment Tree     */    SegmentTreeNode * build(int start, int end) {        // write your code here        if( start > end ) return NULL;        SegmentTreeNode* root = new SegmentTreeNode( start, end );        if(start == end) return root;        int mid = (start+end)/2;        root->left = build( start, mid );        root->right = build( mid + 1, end );        return root;    }};

题目:[创建线段树-II]

/** * Definition of SegmentTreeNode: * class SegmentTreeNode { * public: *     int start, end, max; *     SegmentTreeNode *left, *right; *     SegmentTreeNode(int start, int end, int max) { *         this->start = start; *         this->end = end; *         this->max = max; *         this->left = this->right = NULL; *     } * } */class Solution {public:    /**     *@param A: a list of integer     *@return: The root of Segment Tree     */    SegmentTreeNode * build(vector<int>& A) {        // write your code here        int sz = A.size();        if(!sz) return NULL;        return build(A,  0, sz-1 );    }private:    SegmentTreeNode* build(vector<int>& A, int start, int end ){        if(start > end) return NULL;        SegmentTreeNode* root = new SegmentTreeNode(start, end, 0);        if( start == end ){            root->max = A[start];        }        else{            int mid = (start + end)/2;            root->left = build(A, start, mid);            root->right = build(A, mid+1, end);            root->max = std::max( root->left->max, root->right->max );        }        return root;    }};
0 0
原创粉丝点击