合并时间区间(建议时间复杂度 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;
}