编程-线段树

729. 我的日程安排表 I

实现一个 MyCalendar 类来存放你的日程安排。如果要添加的时间内没有其他安排,则可以存储这个新的日程安排。

MyCalendar 有一个 book(int start, int end)方法。它意味着在 start 到 end 时间内增加一个日程安排,注意,这里的时间是半开区间,即 [start, end), 实数 x 的范围为,  start <= x < end

当两个日程安排有一些时间上的交叉时(例如两个日程安排都在同一时间内),就会产生重复预订。

每次调用 MyCalendar.book方法时,如果可以将日程安排成功添加到日历中而不会导致重复预订,返回 true。否则,返回 false 并且不要将该日程安排添加到日历中。

请按照以下步骤调用 MyCalendar 类: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)

示例 1:

MyCalendar();
MyCalendar.book(10, 20); // returns true
MyCalendar.book(15, 25); // returns false
MyCalendar.book(20, 30); // returns true
解释: 
第一个日程安排可以添加到日历中.  第二个日程安排不能添加到日历中,因为时间 15 已经被第一个日程安排预定了。
第三个日程安排可以添加到日历中,因为第一个日程安排并不包含时间 20 。

说明:

  • 每个测试用例,调用 MyCalendar.book 函数最多不超过 1000次。
  • 调用函数 MyCalendar.book(start, end)时, start 和 end 的取值范围为 [0, 10^9]

解法1:

typedef struct tag_time_zone {
    int start;
    int end;
    tag_time_zone(int i1, int i2) {
        start = i1;
        end = i2;
    }
} time_zone;

class MyCalendar {
public:
    vector<time_zone> vec1;

    bool book(int start, int end) {
        for (vector<time_zone>::iterator it1 = vec1.begin(); it1 != vec1.end(); ++it1) {
            if (start >= it1->start && start < it1->end) {
                return false;
            } else if (end > it1->start && end <= it1->end) {
                return false;
            } else if (start <= it1->start && end > it1->end) {
                return false;
            }
        }

        vec1.push_back(time_zone(start,end));
        return true;
    }
};

/**
 * Your MyCalendar object will be instantiated and called as such:
 * MyCalendar* obj = new MyCalendar();
 * bool param_1 = obj->book(start,end);
 */

int main()
{
    MyCalendar myCalendar;
    vector<vector<int>> shuchu = {{97,100},{33,51},{89,100},{83,100},{75,92},{76,95},{19,30},{53,63},{8,23},{18,37},{87,100},{83,100},{54,67},{35,48},{58,75},{70,89},{13,32},{44,63},{51,62},{2,15}};
    for (int i = 0; i < shuchu.size(); ++i) {
        cout<<myCalendar.book(shuchu[i][0], shuchu[i][1]); // returns true
    }
    cout<<endl;

    for(auto c : myCalendar.vec1) {
        cout << c.start << " " << c.end <<endl;
    }

    return 0;
}

 

解法2:

class MyCalendar {
public:
    map<int, int> map1;

    bool book(int start, int end) {
        //for (map<int, int>::iterator it1 = map1.begin(); it1 != map1.end(); ++it1) {
        for (auto &c : map1) {
            if (start >= c.first && start < c.second) {
                return false;
            } else if (end > c.first && end <= c.second) {
                return false;
            } else if (start <= c.first && end > c.second) {
                return false;
            }
        }

        map1.insert(make_pair(start, end));
        return true;
    }
};

 

 

 

307. 区域和检索 - 数组可修改

给你一个数组 nums ,请你完成两类查询,其中一类查询要求更新数组下标对应的值,另一类查询要求返回数组中某个范围内元素的总和。

实现 NumArray 类:

  • NumArray(int[] nums) 用整数数组 nums 初始化对象
  • void update(int index, int val) 将 nums[index] 的值更新为 val
  • int sumRange(int left, int right) 返回子数组 nums[left, right] 的总和(即,nums[left] + nums[left + 1], ..., nums[right]

 

示例:

输入:
["NumArray", "sumRange", "update", "sumRange"]
[[[1, 3, 5]], [0, 2], [1, 2], [0, 2]]
输出:
[null, 9, null, 8]

解释:
NumArray numArray = new NumArray([1, 3, 5]);
numArray.sumRange(0, 2); // 返回 9 ,sum([1,3,5]) = 9
numArray.update(1, 2);   // nums = [1,2,5]
numArray.sumRange(0, 2); // 返回 8 ,sum([1,2,5]) = 8

 

提示:

  • 1 <= nums.length <= 3 * 104
  • -100 <= nums[i] <= 100
  • 0 <= index < nums.length
  • -100 <= val <= 100
  • 0 <= left <= right < nums.length
  • 最多调用 3 * 104 次 update 和 sumRange 方法


线段树是一种非常灵活的数据结构,它可以用于解决多种范围查询问题,比如在对数时间内从数组中找到最小值、最大值、总和、最大公约数、最小公倍数等。

解法1: c构造线段树类

class SegTree
{
public:
    vector<int> nums;
    vector<int> treesum;
    int n;

    SegTree(vector<int>  nums) {
        this->nums = nums;
        this->n = nums.size();
        treesum.resize(4 * n, 0);
        if (n > 0)
            _build(0, 0, n - 1);
    }

    void _build(int root, int l, int r) {
        if (l == r) {
            treesum[root] = nums[r];
            return;
        }
        int left = 2 * root + 1;
        int right = 2 * root + 2;
        int mid = (l + r) >> 1;
        _build(left, l, mid);
        _build(right, mid + 1, r);
        treesum[root] = treesum[left] + treesum[right];
    }

    void update(int ID, int newValue) {
        _update(0, 0, n - 1, ID, newValue);
    }
    void _update(int root, int l, int r, int ID, int newValue) {
        if (l == ID && r == ID) {
            treesum[root] = newValue;
            return;
        }
        int left = 2 * root + 1;
        int right = 2 * root + 2;
        int mid = (l + r) >> 1;
        if (ID <= mid)
            _update(left, l, mid, ID, newValue);
        else
            _update(right, mid + 1, r, ID, newValue);
        treesum[root] = treesum[left] + treesum[right];
    }

    int query(int ql, int qr) {
        return _query(0, 0, n - 1, ql, qr);
    }
    int _query(int root, int l, int r, int ql, int qr) {
        if (l == ql && r == qr)
            return treesum[root];
        int left = 2 * root + 1;
        int right = 2 * root + 2;
        int mid = (l + r) >> 1;
        if (qr <= mid)
            return _query(left, l, mid, ql, qr);
        else if (mid + 1 <= ql)
            return _query(right, mid + 1, r, ql, qr);
        return _query(left, l, mid, ql, mid) + _query(right, mid + 1, r, mid + 1, qr);
    }
};


class NumArray
{
public:
    SegTree * ST;

    NumArray(vector<int>& nums) {
        ST = new SegTree(nums);
    }

    void update(int index, int val) {
        ST->update(index, val);
    }

    int sumRange(int left, int right) {
        return ST->query(left, right);
    }
};

/**
 * Your NumArray object will be instantiated and called as such:
 * NumArray* obj = new NumArray(nums);
 * obj->update(index,val);
 * int param_2 = obj->sumRange(left,right);
 */

 

c++线段树简易版

class NumArray
{
public:

    vector<int> tree;
    int n;

    NumArray(vector<int> &nums) {
        if (nums.size() > 0) {
            n = nums.size();
            tree.resize(n * 2);
            buildTree(nums);
        }
    }
    
    void buildTree(vector<int> &nums) {
        for (int i = n, j = 0;  i < 2 * n; i++,  j++)
            tree[i] = nums[j];
        for (int i = n - 1; i > 0; --i)
            tree[i] = tree[i * 2] + tree[i * 2 + 1];
    }

    void update(int pos, int val) {
        pos += n;
        tree[pos] = val;
        while (pos > 0) {
            int left = pos;
            int right = pos;
            if (pos % 2 == 0) {
                right = pos + 1;
            } else {
                left = pos - 1;
            }
            // parent is updated after child is updated
            tree[pos / 2] = tree[left] + tree[right];
            pos /= 2;
        }
    }

     int sumRange(int l, int r) {
        // get leaf with value 'l'
        l += n;
        // get leaf with value 'r'
        r += n;
        int sum = 0;
        while (l <= r) {
            if ((l % 2) == 1) {
                sum += tree[l];
                l++;
            }
            if ((r % 2) == 0) {
                sum += tree[r];
                r--;
            }
            l /= 2;
            r /= 2;
        }
        return sum;
    }
};

 

 

posted @ 2021-05-22 19:38  aaronwell  阅读(77)  评论(0)    收藏  举报