【OfferX】矩形和矩阵

1.矩阵的变换

题目48. Rotate Image

将一个矩形顺时针翻转90°

:先将矩形按行翻转,然后进行mirror操作

class Solution {
    public void rotate(int[][] matrix) {
        reverse(matrix);
        mirrorRotate(matrix);
    }
    
    public void reverse(int[][] matrix){
        for(int i=0,j=matrix.length-1;i<j;++i,--j){
            int[] tmp = matrix[i];
            matrix[i]=matrix[j];
            matrix[j]=tmp;
        }
    }
    
    public void mirrorRotate(int[][] matrix){
        for(int i=0;i<matrix.length;++i){
            for(int j=i+1;j<matrix.length;++j){
                swap(matrix,i,j);
            }
        }
    }
    
    public void swap(int[][] matrix,int i,int j){
        int tmp=matrix[i][j];
        matrix[i][j]=matrix[j][i];
        matrix[j][i]=tmp;
    }
}

2.线段树(TODO 提交代码)

Range Sum Query

题目307. Range Sum Query - Mutable(Medium)

解1:使用递归实现buildTree, update和sumRange

class NumArray {
    
    int[] nums;
    int[] tree;
    int n;

    public NumArray(int[] nums) {
        this.nums = nums;
        //System.out.printf("nums=%s\n",Arrays.toString(nums));
        n = nums.length;
        //[0]:        [0,3]
        //       [0,1]       [2,3]
        //        1  2      3 4
        // tree[n+i] = nums[i]
        tree  = new int[4*n+1];
        if(n>0){
            buildTree(nums,1,0,n-1);
        }
        //System.out.printf("tree=%s\n",Arrays.toString(tree));
    }
    
    public void buildTree(int[] nums,int idx,int left,int right){
     //   System.out.printf("idx=%s,left=%s,right=%s\n",idx,left,right);
        if(left==right){
            tree[idx]=nums[left];
        }else{
            int m=left + (right-left)/2;
            buildTree(nums,idx<<1,left,m);
            buildTree(nums, (idx<<1)|1,m+1,right);
            
            tree[idx] = tree[idx<<1] + tree[(idx<<1)|1];
        }
    }
    
    public void update(int i, int val) {
        int diff = val - nums[i];
        nums[i]=val;
        updateSub(1,0,n-1,i,diff);
        /*
              18
           16    2
         9  7   2 0
        7 2

              24
            16   8
          9 7   2 6
         7 2  
        */
        // System.out.printf("after update %s,%s,tree=%s\n",i,val,Arrays.toString(tree));
    }
    // update i, from top to bottom
    // left,right is the range that idx holds, i is problem being asked
    // invariant: left<=i<=right
    private void updateSub(int idx,int left,int right,int i,int diff){
        tree[idx]+=diff;
        if(left==right){
            return;
        }
        int m = left + (right-left)/2;
        if(i<=m){
            updateSub(idx<<1,left,m,i,diff);
        }else{
            updateSub((idx<<1)|1,m+1,right,i,diff);
        }
    }
    
    public int sumRange(int i, int j) {
        return sumRangeSub(1,0,n-1,i,j);
    }
    
    // invariant: left,right contains i,j
    private int sumRangeSub(int idx,int left,int right,int i,int j){
        if(i==left && j==right){
            return tree[idx];
        }
        // 0 4
        // 0,2,4,2
        // 3,4,4,4
        int m = left + (right - left)/2;
        // sum(i,L,R,x,y)
        // i has range L,R, query x,y
        // if L,R==x,y return tree[i]
        // if L,R intersects x,y
        
        //  [L,m      R]
        //     [i,j]
        if(m<i){
            return sumRangeSub( (idx<<1)|1,m+1,right,i,j);
        }else if(m>=j){
            return sumRangeSub(idx<<1,left,m,i,j);
        }else{
            // i<=m<j
            return sumRangeSub(idx<<1,left,m,i,m) + sumRangeSub((idx<<1)|1, m+1,right,m+1,j);
        }
    }
}

/**
 * Your NumArray object will be instantiated and called as such:
 * NumArray obj = new NumArray(nums);
 * obj.update(i,val);
 * int param_2 = obj.sumRange(i,j);
 */

解2:update操作不需要原数组nums,只需要重新计算所有受影响的路径即可

class NumArray {
    
    int[] nums;
    int[] tree;
    int n;

    public NumArray(int[] nums) {
         // ... 同上
    }
    
    public void buildTree(int[] nums,int idx,int left,int right){
        // ... 同上
    }
    
    public void update(int i, int val) {
        // IMPORTANT: not necessary
        // int diff = val - nums[i];
        // nums[i]=val;
        updateSub(1,0,n-1,i,val);
    }
    private void updateSub(int idx,int left,int right,int i,int val){
        if(left==right){
            // IMPORTANT: assign directly
            tree[idx] = val;
            return;
        }
        int m = left + (right-left)/2;
        if(i<=m){
            updateSub(idx<<1,left,m,i,val);
        }else{
            updateSub((idx<<1)|1,m+1,right,i,val);
        }
        // IMPORTANT: recompute
        tree[idx] = tree[idx<<1] + tree[(idx<<1)|1];
    }
    
    public int sumRange(int i, int j) {
        return sumRangeSub(1,0,n-1,i,j);
    }
    
    // invariant: left,right contains i,j
    private int sumRangeSub(int idx,int left,int right,int i,int j){
        // ... 同上
    }
}

其他优化

支持区间添加值

将tree的值定义为区间的累加和,可以在O(logn)的时间内实现区间添加,如下:

tree=[] # init added[v]=0 when build tree
update(int idx,int l,int r,int add):
     if l,r is the range:
          tree[idx]+=add
     ....

sumRange(int idx,int l,int r):
    return tree[idx] + sumRange(left) + sumRange(right)

支持区间的值设置

增加额外的标记数组和push操作,push操作定义为将marked标记清空,使得复制向下传递, update时,只需要设置一次marked[v]=true即可,get时,需要调用push来获得必要的值

void push(int v):
    if marked[v]:
        t[v.left]=t[v.right]=t[v]
        marked[v.left]=marked[v.right]=true
        marked[v]=false

get(int v, int L,int R,int i):
    if L==R:return t[v]
    push(v)
    int m =(L+R)/2
    if i<=m:
        return get(v.left,L,m,i)
    else
        return get(v.right,m+1,R,i)

# 设置值
update(int v,int L,int R,int i,int j,int val):
    if i>j:return
    if(L==i&&R==j):
        t[v]=val
        marked[v]=true
        return
    push(v)
    ... #update sub ranges

3.矩形的面积和

题目

求给定矩形的面积,给定的矩形与X轴和Y轴平行

矩形覆盖

题目

给定n个矩形R1,…,Rn, 求R0是否被R1,…,Rn完全覆盖

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值