1.
给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。
注意:如果对空文本输入退格字符,文本继续为空。
题解:
由于#(退格符)只会消除左边的一个字符,对右边的字符没有影响,所以从后向前遍历S,T字符串。
操作:
1.设置两个指针i,j分别指向S,T的末位字符。准备两个变量skipS,skipT分别存放S,T字符串中的#数量
2.从后向前遍历S,会遇到的情况有三:
①若当前字符是#,则skipS自增1.
②若当前字符不是#,且skipS不为0,则skipS自减1.
③若当前字符不是#,且skipS为0,则代表当前字符不会被消除。则可以用来和T中的当前字符作比较。
在对比过程中,只要出现当前字符不匹配,则遍历结束,返回false。若S,T都遍历结束且字符一一匹配,则返回true。
class Solution {
public boolean backspaceCompare(String S, String T) {
int i=S.length()-1, j=T.length()-1; //i,j分别指向S,T的尾节点
int skipS=0,skipT=0;
while(i>=0||j>=0){
while(i>=0){
if(S.charAt(i)=='#'){ //若S当前节点为退格
skipS++;
i--;
}else if(skipS>0){
skipS--;
i--;
}else{
break;
}
}
while(j>=0){
if(T.charAt(j)=='#'){ //若T当前节点为退格
skipT++;
j--;
}else if(skipT>0){
skipT--;
j--;
}else{
break;
}
}
if(i>=0 && j>=0){
if(S.charAt(i) != T.charAt(j)){
return false;
}
}else{
if(i>=0 || j>=0){
return false;
}
}
i--;
j--;
}
return true;
}
}
注:
charAt()方法返回指定索引位置的char值。索引范围为0~length()-1,如: str.charAt(0)检索str中的第一个字符,str.charAt(str.length()-1)检索最后一个字符。
2.
给定两个由一些 闭区间 组成的列表,firstList 和 secondList ,其中 firstList[i] = [starti, endi] 而 secondList[j] = [startj, endj] 。每个区间列表都是成对 不相交 的,并且 已经排序 。
返回这 两个区间列表的交集 。
形式上,闭区间 [a, b](其中 a <= b)表示实数 x 的集合,而 a <= x <= b 。
两个闭区间的 交集 是一组实数,要么为空集,要么为闭区间。例如,[1, 3] 和 [2, 4] 的交集为 [2, 3] 。
题解:
方法:归并区间
如果A[0]拥有最小的末端点,那么它只可能与B[0]相交。然后我们可以删除区间A[0],因为它已经不能再与任何区间相交了。
如果B[0]拥有最小的末端点,则类似。
用两个指针i,j来模拟完成删除A[0]和B[0]的操作。
class Solution {
public int[][] intervalIntersection(int[][] A, int[][] B) {
/*
双指针:
指针i表示A集合中区间的索引,那么A[i][0]和A[i][1]分别表示区间A[i]的左右边界
指针j表示B集合中区间的索引,那么B[j][0]和B[j][1]分别表示区间B[j]的左右边界
左边界start取两个区间左边界较大值,右边界end取两个区间右界较小值
若start<=end则可以形成区间,将[start,end]加入结果
指针移动:看谁的右边界较小,较小的右边界后面不可能有交集了,因此根据右边界大小移动i与j指针
具体地:A[i][1]>B[j][1],j++;A[i][1]<B[j][1],i++
循环至两个区间组都到达末尾就结束
*/
List<int[]> list = new ArrayList<>();
int i = 0, j = 0;
int lenA = A.length, lenB = B.length;
// 两个区间组索引都有效时开启循环
while(i < lenA && j < lenB) { //想一下为什么不能用等号? 若lenA=A.length-1,lenB=B.length-1则要加上等号
// 求出A区间组与B区间组中较大的左边界和较小的右边界
int start = Math.max(A[i][0], B[j][0]);
int end = Math.min(A[i][1], B[j][1]);
// 若结果合法就加入结果
if(start <= end) {
list.add(new int[]{start, end});
}
// 移动指针:哪个区间组右边界小的就移动哪个区间组的指针
if(A[i][1] < B[j][1]) {
i++;
} else {
j++;
}
}
// 将列表转化为二维数组输出结果
return list.toArray(new int[list.size()][]);
}
}
3.
给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
题解:
能盛下多少水取决于短板!
设置双指针,i指向左端点,j指向右端点。
若向内移动高度更短的板,则短板可能会变高,水槽面积就可能更大。
若向内移动高度更高的板,短板可能不变或者变小,所以水槽的面积一定变小。
所以,每次左右两板的高度,将短板向内移动一次。并记录面积的最大值。
class Solution {
public int maxArea(int[] height) {
int i=0,j=height.length-1,res=0;
while(i<j){
res = height[i]<height[j]?
Math.max(res,(j-i)*height[i++]):
Math.max(res,(j-i)*height[j--]);
}
return res;
}
}
复杂度分析:
时间复杂度 O(N)O(N) : 双指针遍历一次底边宽度 NN 。
空间复杂度 O(1)O(1) : 变量 ii , jj , resres 使用常数额外空间。