区间问题以及双指针解法

合并时间区间(建议时间复杂度 O(n) )

给定⼀个按开始时间从⼩到⼤排序的时间区间集合,请将重叠的区间合并。时
间区间集合⽤⼀个⼆维数组表示,⼆维数组的每⼀⾏表示⼀个时间区间(闭区
间),其中 0 位置元素表示时间区间开始,1 位置元素表示时间区间结束。
例 1:输⼊:[ [1, 3], [2, 6], [8, 10], [15, 18] ]
返回: [ [1, 6], [8, 10], [15, 18]]
解释:时间区间 [1, 3] 和 [2, 6] 有部分重叠,合并之后为 [1, 6]
例 2:输⼊:[[1, 4], [4, 5]]
返回:[[1, 5]]
解释:时间区间[1,4] 和 [4,5]重叠了⼀个时间点,合并之后为 [1,5]
需要实现的⽅法原型:int[][] merge(int[][] intervals)

    public static int[][] merge(int[][] array){
        //特殊情况判断
        ArrayList<Object> res = new ArrayList<>();
        if(array.length==0||array==null){
            return res.toArray(new int[0][]);
        }
        //预排序
        Arrays.sort(array,(a,b)->a[0]-b[0]);
        
        int i=0;
        while(i<array.length){
            int left=array[i][0];
            int right=array[i][1];
            while(i<array.length-1&&right>array[i+1][0]){
                i++;
                right=Math.max(right,array[i+1][1]);
            }
            res.add(new int[]{left,right});
            i++;
        }
        return res.toArray(new int[0][]);
    }

插入区间

给出一个无重叠的 ,按照区间起始端点排序的区间列表。
在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。
示例 1:
输入:
intervals = [[1,3],[6,9]]
newInterval = [2,5]
输出:[[1,5],[6,9]]
示例 2:
输入:
intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]]
newInterval = [4,8]
输出:[[1,2],[3,10],[12,16]]
解释:这是因为新的区间 [4,8] 与 [3,5],[6,7],[8,10] 重叠。
需要实现的⽅法原型:
public int[][] insert(int[][] intervals, int[] newInterval)

package A.ppp;

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

public class p1 {
    public static void main(String[] args) {
      int[][] array={
              {1,2},
              {3,5},
              {6,7},
              {8,10},
              {12,16},
      };
      int[] str=new int[]{4,8};

        int[][] insert = new p1().insert(array, str);
        for (int[] ints : insert) {
            System.out.println(ints[0]+" "+ints[1]);
        }
    }



    public static int[][] merge(int[][] array){
        //特殊情况判断
        ArrayList<Object> res = new ArrayList<>();
        if(array.length==0||array==null){
            return res.toArray(new int[0][]);
        }
        //预排序
        Arrays.sort(array,(a,b)->a[0]-b[0]);

        int i=0;
        while(i<array.length){
            int left=array[i][0];
            int right=array[i][1];
            while(i<array.length-1&&right>array[i+1][0]){
                i++;
                right=Math.max(right,array[i+1][1]);
            }
            res.add(new int[]{left,right});
            i++;
        }
        return res.toArray(new int[0][]);
    }


    public int[][] insert(int[][] array, int[] newInterval){
        ArrayList<Object> res = new ArrayList<>();
        int i=0;
        while(i<array.length&&array[i][1]<newInterval[0]){
            res.add(array[i++]);
        }

        int mergeLeft=newInterval[0];
        int mergeRight=newInterval[1];

        //不重合的区域结束了,这里是重合的区域
        while(i<array.length&&array[i][0]<=newInterval[1]){
            mergeLeft=Math.min(mergeLeft,array[i][0]);
            mergeRight=Math.max(mergeLeft,array[i][1]);
            i++;
        }

        res.add(new int[]{mergeLeft,mergeRight});

        //把剩下的添加到list中
        while(i<array.length){
            res.add(array[i++]);
        }
        return res.toArray(new int[0][]);
    }
}

两道合并区间的题目,只要熟练使用while语句这两道都不是问题,第二题目可能需要细心一点,在临界值的判断上需要注意,另外就是在刷题的时候能用while就不要用if循环,while相比于if比较灵活一点,当然可以解决很多问题,达到意想不到的效果,当然下面这一道题目也是,不过用到了双指针法

缩写校验(建议时间复杂度 O(n) )

给定⼀个⾮空字符串 s 和⼀个缩写 abbr,请校验它们是否匹配。
假设字符串中只包含⼩写字⺟,缩写中只包含⼩写字⺟和数字。缩写中的数字
表示其缩略的字符数;连续多位数字表示⼀个多位数。
例如,字符串 “word” 的缩写有且仅有以下这些:[“word", “1ord”, “w1rd”,
“wo1d”, “wor1”, “2rd”, “w2d”, “wo2”, “1o1d”, “1or1”, “w1r1”, “1o2”, “2r1”, “3d”,
“w3”, “4"]。
例 1:输⼊:s = “internationalization",abbr = “i12iz4n”
返回:true
解释:abbr 中的 12 表示有⼗⼆个字符被缩略了。
例 2:输⼊:s = “apple",abbr = “a2e"
返回:false
需要实现的⽅法原型:boolean valid(String word, String abbr)

   /****
     * @param word   原串
     * @param abbr   匹配串
     * @return
     */
    boolean valid(String word,String abbr){
        int i=0,n=0,j=0;
        while(i<word.length()&&j<abbr.length()){
            n=0;
            if(abbr.charAt(j)=='0'){
                return false;
            }
            while(j<abbr.length()&&!Character.isLetter(abbr.charAt(j))){
                n=n*10+abbr.charAt(j++)-'0';
            }
            i+=n;
//            if(word.length()>i && j<abbr.length() && word.charAt(i)!=abbr.charAt(j))
//                return false;
//            else if((i<word.length()&&j>=abbr.length())||(i>=word.length()&&j<abbr.length()))
//                return false;
//            else if(i==word.length() && j==abbr.length())
//                return true;//这里加一条,可能以数字结尾,下面++,出了循环,最后条件不成立
            i++;
            j++;
        }
        return i==word.length() && j==abbr.length();
    }

代码巧妙之处在于结尾的return语句,可以把以语句全部省略,让代码更加精炼

合并两个有序数组

同样,合并两个有序的数组,使用双指针,效率就变得的非常高

    /***
     * 这个题目的特点是有序,利用有序的这一个特点,可以节省空间的开支,优化时间效率
     * @param A
     * @param m
     * @param B
     * @param n
     */
    public void merge01(int[] A,int m,int B[],int n){
        int k=n+m-1;
        int i=n-1;
        int j=m-1;

        while(i>=0&&j>=0){
            if(A[i]<B[i]){
                A[k--]=B[j--];
            }else{
                A[k--]=A[i--];
            }
        }
        while(j>=0)
            A[k--]=B[j--];
    }

说起双指针,还有一个更经典的问题
在这里插入图片描述

有效的山脉数组

题目链接:https://leetcode-cn.com/problems/valid-mountain-array/
题目意思也就是判断一个字符串是否存在机值,这个题目对应的就是最大值,代码如下,一个return很巧妙的简化了代码,这个就是双指针的经典应用

    public boolean validMountainArray(int[] A) {
        int len=A.length;
        int left=0;
        int right=len-1;
        while(left+1<len&&A[left]<A[left+1]){
             left++;
        }
        while(right-1>0&&A[right-1]>A[right]){
             right--;
        }
        return left>0&&right<len-1&&left==right;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值