leet 算法基础 day4 双指针

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
探险家小扣的行动轨迹,都将保存在记录仪中。expeditions[i] 表示小扣第 i 次探险记录,用一个字符串数组表示。其中的每个「营地」由大小写字母组成,通过子串 -> 连接。例:"Leet->code->Campsite",表示到访了 "Leet"、"code"、"Campsite" 三个营地。expeditions[0] 包含了初始小扣已知的所有营地;对于之后的第 i 次探险(即 expeditions[i] 且 i > 0),如果记录中包含了之前均没出现的营地,则表示小扣 新发现 的营地。 请你找出小扣发现新营地最多且索引最小的那次探险,并回对应的记录索引。如果所有探险记录都没有发现新的营地,回 -1。注意: 大小写不同的营地视为不同的营地; 营地的名称长度均大于 0。用python实现。给你几个例子:示例 1: 输入:expeditions = ["leet->code","leet->code->Campsite->Leet","leet->code->leet->courier"] 输出:1 解释: 初始已知的所有营地为 "leet" 和 "code" 第 1 次,到访了 "leet"、"code"、"Campsite"、"Leet",新发现营地 2 处:"Campsite"、"Leet" 第 2 次,到访了 "leet"、"code"、"courier",新发现营地 1 处:"courier" 第 1 次探险发现的新营地数量最多,因此回 1。示例 2: 输入:expeditions = ["Alice->Dex","","Dex"] 输出:-1 解释: 初始已知的所有营地为 "Alice" 和 "Dex" 第 1 次,未到访任何营地; 第 2 次,到访了 "Dex",未新发现营地; 因为两次探险均未发现新的营地,回 -1
04-23
我的理解是,你想让我编写一段 Python 代码,实现一个算法,用于在给定的探险记录中找到发现新营地最多且索引最小的探险记录。 那么首先,我需要解析题目中的输入输出要求。 输入要求: - expeditions:一个字符串数组,表示小扣第一次到访的所有营地,和之后的每次探险记录(一个记录就是一个字符串,其中营地通过子串 -> 连接)。 输出要求: - 如果所有的探险记录都没有发现新的营地,则回 -1; - 否则,回发现新营地最多且索引最小的探险记录的索引。注:探险记录的索引从 0 开始计数。 接下来,我可以考虑如何编写代码来解决这个问题。 我的思路是,首先用一个集合记录所有已知的营地名称,然后遍历每个探险记录,依次将其中的营地名称加入到集合中,并判断是否有新的营地被发现。 如果某个探险记录中发现了新的营地,那么我就记录下发现了多少个新营地,以及这个探险记录的索引。最后,遍历所有的探险记录,找到发现新营地最多且索引最小的记录。 代码如下: ```python def find_new_camp(expeditions): known_camps = set() # 已知的营地集合 max_new_camps = 0 # 最多的新营地数量 max_new_camps_index = -1 # 最多新营地数量的探险记录的索引 for i in range(len(expeditions)): sub_camps = expeditions[i].split("->") # 提取探险记录中所有的营地名称 num_new_camps = 0 # 记录这个探险记录发现的新营地数量 for camp in sub_camps: if camp not in known_camps: # 如果这个营地是新的,就记录一下 known_camps.add(camp) num_new_camps += 1 if num_new_camps > max_new_camps: # 如果发现了更多的新营地,就更新最大值和索引 max_new_camps = num_new_camps max_new_camps_index = i return max_new_camps_index if max_new_camps > 0 else -1 ``` 我使用了两个变量 `max_new_camps` 和 `max_new_camps_index` 来记录已经遍历过的探险记录中,发现了最多的新营地数量,以及具有最多新营地数量的探险记录的索引。然后我遍历所有的探险记录,统计其中发现的新营地数量,如果大于当前的最大值,就更新 `max_new_camps` 和 `max_new_camps_index` 变量。最后,如果发现了新的营地,就回 `max_new_camps_index`。如果所有的探险记录都没有发现新营地,就回 -1。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值