zoukankan      html  css  js  c++  java
  • 线段树 数据结构的简介和 leetcode 307

    之前一直听说线段树是一个很高级很难的数据结构,今天简单了解了下, 感觉就是二叉树加几个全局变量啊,原来这么easy?(开个玩笑)

    简单说几个特点,

    1. 每个节点除了存放left,right指针之外,还存着一个范围(这个范围一般是构建线段树之前数组的索引范围), 就是以当前节点为根的情况下,对自己下面所有节点的求交集, 还可以根据你的需求 加一些别的特殊字段,sum,max,min等等

    2. 数据集都存在叶子节点上,非叶子节点只做归纳总结

    一般还有几个操作

    1. 初始化,就是把一个数组初始化成一个线段树(关键是修改你需求中的特殊字段 sum等)

    2. 修改某一个索引处的数值,同时保证他的祖先节点的特殊字段是对的

    3. 求某一个索引范围内的信息

    整体思路是分治,递归求解。 

    leetcode 307 是一个典型的线段树

    给定一个整数数组  nums,求出数组从索引 到 j  (i ≤ j) 范围内元素的总和,包含 i,  j 两点。

    update(i, val) 函数可以通过将下标为 的数值更新为 val,从而对数列进行修改。

    示例:

    Given nums = [1, 3, 5]
    
    sumRange(0, 2) -> 9
    update(1, 2)
    sumRange(0, 2) -> 8
    

    说明:

    1. 数组仅可以在 update 函数下进行修改。
    2. 你可以假设 update 函数与 sumRange 函数的调用次数是均匀分布的。
    这道题,看到题之后,最朴素的解法就是每次都从i到j遍历,更新就直接更新。 这样更新的时间复杂度是o1, 求和的时间复杂度是on
    这个时候,思考下有没有别的解决办法, 我们维护一个前n项和的数组,sum(n) = 0 到 n的累加和, range(i,j)= sum(j) - sum(i)
    这样的话range的时间复杂度就是o1了, 但是更新的时候你需要更新很多个前n项和,这样更新就成on了, 有没有更优的解法呢?
    用segment tree,这样的话更新和查找就都是logn的时间复杂度了,这样就优了不少, 比如n等于1000, 那么一个o1的时间复杂度一个on的时间复杂度那么总共就是1000+
    ,但是两个都是logn的话,就是20, 如果n比较大的话那么差别就更大了。
    talk is cheap, 上代码
    class NumArray {
        class SegmentTree {
            int start;
            int end;
            int sum;
            SegmentTree left;
            SegmentTree right;
            SegmentTree(int s, int e, int sum_temp, SegmentTree l, SegmentTree r) {
                start = s;
                end = e;
                sum = sum_temp;
                left = l;
                right = r;
            }
        }
        int[] n;
        SegmentTree head;
        public NumArray(int[] nums) {
            n = nums;
            head = init(nums, 0, nums.length - 1);
        }
        
        SegmentTree init (int[] nums, int start, int end) {
            if (start > end) return null;
            if (start == end) {
                return new SegmentTree(start, end, nums[start], null, null);
            }
            int mid = (start + end)/2;
            SegmentTree left = init(nums, start, mid);
            SegmentTree right = init(nums, mid + 1, end);
            return new SegmentTree(start, end, left.sum + right.sum, left, right);
        }
        
        public void update(int i, int val) {
            runUpdate(head, i, val);
        }
        
        void runUpdate(SegmentTree root, int i, int val) {
            if (root.start == root.end) {
                root.sum = val;   
                return;
            }
            int mid = (root.start + root.end)/2;
            if (i <= mid) {
                runUpdate(root.left, i, val);
            } else {
                runUpdate(root.right, i, val);
            }
            root.sum = root.left.sum + root.right.sum;
        }
        
        public int sumRange(int i, int j) {
            return runSumRange(head, i, j);
        }
        
        int runSumRange(SegmentTree root, int i, int j) {
            if (root.start == i&&root.end == j) {
                return root.sum;
            }
            int mid = (root.start + root.end)/2;
            if (j <= mid) {
                return runSumRange(root.left, i, j);
            }
            if (i > mid) {
                return runSumRange(root.right, i, j);
            }
            return runSumRange(root.left, i, mid) + runSumRange(root.right, mid + 1, j);
        }
    }
  • 相关阅读:
    二维树状数组的区间加减及查询 tyvj 1716 上帝造题的七分钟
    hdu5399
    WebLogicSSL解决苹果IOS itms下载问题
    怎样封装RESTful Web Service
    ie8下面版本号(包含ie8)的浏览器不支持html5标签属性解决方式(Modernizr 2.6.2插件的使用)
    在Linux平台使用VNC连接树莓派
    合作开发——设计阶段
    HDU-1165-Eddy&#39;s research II
    Iocomp控件教程之LinearGauge--线性刻度尺控件
    VB中的排序问题 15个
  • 原文地址:https://www.cnblogs.com/tobemaster/p/10474420.html
Copyright © 2011-2022 走看看