双指针习题

   💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。



非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨
 

前言

本栏目将记录博主暑假从0开始刷力扣的算法题,每一条题目我都会把知识点抽丝剥茧地进行分析,以便大家更好的理解和学习,话不多说,肝!

序号标题力扣序号
1移除元素27
2删除有序数组中的重复项26
3移动零283
4比较含退格的字符串844

 1.移除元素

题目:

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

  • 更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
  • 返回 k

示例 :

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2,_,_]
解释:你的函数函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。

解题思路:双指针法(快慢指针法)

要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置

代码(Java)

class Solution {
    public int removeElement(int[] nums, int val) {
        // 快慢指针
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.length; fastIndex++) {
            if (nums[fastIndex] != val) {
                nums[slowIndex] = nums[fastIndex];
                slowIndex++;
            }
        }
        return slowIndex;
    }
}

2.删除有序数组中的重复项

题目:

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 。

示例 :

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]

解题思路:

设置两个指针,一个在前记作 p,一个在后记作 q

如果相等,q 后移 1 位
如果不相等,将 q 位置的元素复制到 p+1 位置上,p 后移一位,q 后移 1 位
重复上述过程,直到 q 等于数组长度。

代码(Java)

class Solution {
    public int removeDuplicates(int[] nums) {
        if(nums == null || nums.length == 0) return 0;
        int p = 0;
        int q = 1;
        while(q < nums.length){
            if(nums[p] != nums[q]){
                nums[p + 1] = nums[q];
                p++;
            }
            q++;
        }
        return p + 1;
    }
}

3.移动零

题目:

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 :

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

解题思路:

两次遍历,采用双指针的思想,第一次把非0挪到前面,剩下的继续第二次遍历,把剩下的元素赋值为0

代码(Java)

class Solution {
    public void moveZeroes(int[] nums) {
      if(nums == null) {
        return;
      }
        int j = 0;
        for(int i = 0; i < nums.length; i++){
            if(nums[i] != 0) {
                nums[j++] = nums[i];
            }
        }

        for(int i = j; i < nums.length; i++){
            nums[i] = 0;
        }

    }
}

4.比较含退格的字符串

题目:

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。(#就是删掉的意思)

注意:如果对空文本输入退格字符,文本继续为空。

示例 1:

输入:s = "ab#c", t = "ad#c"
输出:true
解释:s 和 t 都会变成 "ac"。

示例 2:

输入:s = "a#c", t = "b"
输出:false
解释:s 会变成 "c",但 t 仍然是 "b"。

思路解析:

由于 # 号只会消除左边的一个字符,所以对右边的字符无影响,所以我们选择从后往前遍历 S,T 字符串。

准备两个指针 i, j 分别指向 S,T 的末位字符,再准备两个变量 skipS,skipT 来分别存放 S,T 字符串中的 # 数量。
从后往前遍历 S,所遇情况有三,如下所示:
2.1 若当前字符是 #,则 skipS 自增 1;
2.2 若当前字符不是 #,且 skipS 不为 0,则 skipS 自减 1;
2.3 若当前字符不是 #,且 skipS 为 0,则代表当前字符不会被消除,我们可以用来和 T 中的当前字符作比较。
若对比过程出现 S, T 当前字符不匹配,则遍历结束,返回 false,若 S,T 都遍历结束,且都能一一匹配,则返回 true。

                                                                                                             思路参考的作者:御三五 🥇

代码(Java)

class Solution {  
    public boolean backspaceCompare(String S, String T) {  
        int i = S.length() - 1, j = T.length() - 1; // 从两个字符串的末尾开始遍历  
        int skipS = 0, skipT = 0; // 分别记录S和T中需要跳过的字符数  
  
        while (i >= 0 || j >= 0) { // 当两个字符串中至少有一个还有未遍历的字符时继续  
            // 处理字符串S  
            while (i >= 0) {  
                if (S.charAt(i) == '#') { // 遇到退格字符  
                    skipS++; // 需要跳过的字符数加1  
                    i--; // 继续向前遍历  
                } else if (skipS > 0) { // 如果前面有退格字符需要跳过  
                    skipS--; // 跳过当前字符  
                    i--; // 继续向前遍历  
                } else {  
                    break; // 没有退格字符需要跳过,跳出内层循环  
                }  
            }  
            // 处理字符串T,逻辑与S相同  
            while (j >= 0) {  
                if (T.charAt(j) == '#') {  
                    skipT++;  
                    j--;  
                } else if (skipT > 0) {  
                    skipT--;  
                    j--;  
                } else {  
                    break;  
                }  
            }  
            // 比较两个字符串当前位置的字符  
            if (i >= 0 && j >= 0) { // 两个字符串当前位置都有字符  
                if (S.charAt(i) != T.charAt(j)) { // 如果字符不相等  
                    return false; // 返回false  
                }  
            } else { // 如果只有一个字符串还有未遍历的字符  
                if (i >= 0 || j >= 0) { // 只要有一个字符串还有字符,就返回false  
                    return false;  
                }  
            }  
            i--; // 继续向前遍历S  
            j--; // 继续向前遍历T  
        }  
        return true; // 两个字符串都遍历完毕,且对应位置的字符都相等,返回true  
    }  
}


❤️❤️❤️小郑是普通学生水平,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

  • 48
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值