leet 算法基础 day4 双指针

本文介绍了三种使用双指针解决字符串退格比较和区间交集问题的算法。对于字符串退格比较,从后向前遍历,处理退格字符,判断字符是否匹配;对于区间交集问题,采用归并区间的方法,找到两个区间列表的交集。最后,讨论了求解二维数组中两个区间最大交集的双指针策略,通过移动短板来最大化容量。这些方法都体现了双指针在处理数组和字符串问题中的高效性。
摘要由CSDN通过智能技术生成

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 使用常数额外空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值