插入区间[二分插入+问题分析(最好纸笔画画)]

前言

保持有序数组对二分法的紧密联系。问题分析最好用纸笔画画,弥补空间思维和记忆量小的不足。

一、插入区间

在这里插入图片描述

二、二分+区间确定

1、拆解问题、分类讨论

    /*
    target:给一个有序且不重叠的区间数组,把一个新区间合并进去。
    有序数组紧密关联这二分查找。
    合并区间需要考虑合并到那个位置?需要进行二分查找,找起点,找终点。
    找到的起点和终点对应interval的数组要和newInterval来比较,看是否需要合并区间。

    M1:找到插入数组左端,通过interval[left][1] >= newInterval[0]来判断是否要合并左端前一个数组,把前面的区间加到list,并确定新区间左端点。
       找到插入数组右端,通过interval[right][0] <= newInterval[1]来判断是否要合并right数组,确定新区间右端点。
       添加新区间,再添加右边的剩余区间。

       关键点:确定左边右边不需要合并的区间有多长;确定插入新区间的左右端点(因为可能涉及到合并区间,就要重设端点)。
       总结:二分法O(logN) + 是否合并区间,来确定两个东西。1-左右剩余区间;2-中间的新区间。

     */

2、code

package com.xhu.offer.everyday;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//插入区间
public class Insert {
    /*
    target:给一个有序且不重叠的区间数组,把一个新区间合并进去。
    有序数组紧密关联这二分查找。
    合并区间需要考虑合并到那个位置?需要进行二分查找,找起点,找终点。
    找到的起点和终点对应interval的数组要和newInterval来比较,看是否需要合并区间。

    M1:找到插入数组左端,通过interval[left][1] >= newInterval[0]来判断是否要合并左端前一个数组,把前面的区间加到list,并确定新区间左端点。
       找到插入数组右端,通过interval[right][0] <= newInterval[1]来判断是否要合并right数组,确定新区间右端点。
       添加新区间,再添加右边的剩余区间。

       关键点:确定左边右边不需要合并的区间有多长;确定插入新区间的左右端点(因为可能涉及到合并区间,就要重设端点)。
       总结:二分法O(logN) + 是否合并区间,来确定两个东西。1-左右剩余区间;2-中间的新区间。

     */
    public int[][] insert(int[][] intervals, int[] newInterval) {
        List<int[]> rs = new ArrayList<>();
        int left = binarySearch(intervals, newInterval[0], 0);
        if (left != 0) {
            if (intervals[left - 1][1] >= newInterval[0]) {
                --left;
                newInterval[0] = intervals[left][0];
            }
        }

        for (int i = 0; i < left; i++) rs.add(intervals[i]);

        int right = binarySearch(intervals, newInterval[1], 1);
        if (right != intervals.length && newInterval[1] >= intervals[right][0]) {
            newInterval[1] = intervals[right][1];
            ++right;
        }

        rs.add(newInterval);

        for (int i = right; i < intervals.length; i++) rs.add(intervals[i]);

        return rs.toArray(new int[0][]);
    }

    /**
     * 插入式,插左
     *
     * @param intervals
     * @param target
     * @param mark      mark == 0 表示按intervals元素中的左端点来找,反之按右端点来找。
     * @return
     */
    private int binarySearch(int[][] intervals, int target, int mark) {
        int low = 0, high = intervals.length;

        while (low < high) {
            int mid = low + (high - low >>> 1);
            int midVal = mark == 0 ? intervals[mid][0] : intervals[mid][1];

            if (target > midVal) low = mid + 1;
            else high = mid;
        }
        return high;
    }
}

总结

1)二分法与有序数组(或者把数组先排个序)
2)纸笔可减少头脑记忆的负担,专注思考和分析问题,方便情况分类和整理。
3)问题拆解,牢牢抓住关键点。

参考文献

[1] LeetCode 插入区间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值