算法总结(双指针)

引言

题目一:给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。 例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。

283. 移动零 - 力扣(LeetCode)

844. 比较含退格的字符串 - 力扣(LeetCode)

题目一

这一题也是双指针的思想,题目的目的就是要替换数字变成单词。这个涉及到了对于线性数据结构的填充或者删除。如果我们按照正常的遍历顺序(正序遍历)每次插入一个数据,就必须要把原来的位置全部移动到后面去,也就是双循环O(n^2)的时间复杂度。

所以我们对于这一类问题,我们选择在开辟了空间之后用后序遍历的做法,这种做法的优势就是我们不需要移动任何的元素。首先我们对于原来的数组和现在的新数组都是后续遍历,也就是说原来的数组最后一个字母一定移动到新数组的最后一个,然后不断地往前面推,这样直接就可以确定位置,而不需要向前序遍历一样,每一次那个位置我们都需要不断地往后面进行调整。

cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

int main() {
    string s;
    int count = 0;
    while(cin >> s) {
        int oldIndex = s.size() - 1;
        for(int i = 0; i < s.size(); i++) {
            if(s[i] >= '0' && s[i] <= '9') {
                count++;
            }
        }
        s.resize(s.size() + count * 5);
        int newIndex = s.size() - 1;
        while(newIndex >= 0) {
            if(s[oldIndex] >= '0' && s[oldIndex] <= '9') {
                s[newIndex--] = 'r';
                s[newIndex--] = 'e';
                s[newIndex--] = 'b';
                s[newIndex--] = 'm';
                s[newIndex--] = 'u';
                s[newIndex--] = 'n';
            } else {
                s[newIndex--] = s[oldIndex];
            }
            oldIndex--;
        }
        cout << s << endl;
    }
    return 0;
}

第二题

这一题就是把所有的0移动到最后面去,这一题依然是双指针的思想,双指针的一般解法有两种,第一种是两个指针同向行驶,还有一种是一个在左边,一个在右边,面对面夹逼。

对于第一种情况,我们一般是快慢指针,慢指针用来更新数组,快指针用来遍历数组,而快慢指针真正分开的条件也就是我们要找的值。这里我们分开的条件是快指针遇到了0。如果一直没有遇到0,那其实这两个指针一直都是在一起的,直到遇到了0,那慢指针就开始更新数组了,这个更新数组的方式其实就是快指针把数据通过swap送过来,而快指针依然向后遍历,随着0的越来越多,两个指针越来越远。

cpp 复制代码
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int slow = 0;
        for(int fast = 0; fast < nums.size(); fast++) {
            if(nums[fast] != 0) {
                swap(nums[fast], nums[slow]);
                slow++;
            }
        }
    }
};
// 1 2 3 0 5 0 6 7

题目三

相比于栈,这个题目用双指针的空间复杂度更小,时间复杂度相同。对于两个字符串的比较,我们也可以考虑双指针。这一题'#'会影响一个数组的前面的数,所以我们肯定不可以正序遍历,相比于回忆过去,我们更喜欢预测未来。所以我们选择后序遍历,这个好处就是我们可以把因为'#'而消除的结点直接去掉,反正最后也不参加我们的比较。当去掉了之后,如果某一次的移动,发现有不相等,那么就返回false。注意一下,我们说的移动是正常的移动,而不是因为'#'而被迫的移动,所以我们每一次比较的都是最后留在数组里面的数,只不过是从后面往前面比较而已。不过还是要注意一下子就是,不要比较越界了,还是要加一些判断条件的。

cpp 复制代码
class Solution {
public:
    bool backspaceCompare(string s, string t) {
        int str1 = s.size() - 1;
        int str2 = t.size() - 1;
        int skip1 = 0;
        int skip2 = 0;
        while(str1 >= 0 || str2 >= 0) {
            while(str1 >= 0) {
                if(s[str1] == '#') {
                    skip1++;
                    str1--;
                } else if(skip1 > 0) {
                    str1--;
                    skip1--;
                } else {
                    break;
                }
            }
            while(str2 >= 0) {
                if(t[str2] == '#') {
                    skip2++;
                    str2--;
                } else if(skip2 > 0) {
                    str2--;
                    skip2--;
                } else {
                    break;
                }
            }
            if(str1 >= 0 && str2 >= 0) {
                if(s[str1] != t[str2]) {
                    return false;
                }
            } else {
                if(str1 >= 0 || str2 >= 0) {
                    return false;
                }
            }
            str1--;
            str2--;
        }
        return true;
    }
};

总结

本篇文章介绍了双指针对两个数组,同边和不同边的做法,三种做法都是双指针,但是思想完全不一样,大家还是要多多体会!

本篇文章就到这里结束了!!!希望这篇文章可以帮助到大家~~~

相关推荐
吴佳浩8 小时前
DeepSeek DSpark:Confidence-Scheduled Speculative Decoding 技术解析
人工智能·算法·deepseek
触底反弹9 小时前
🧠 搞懂 Token,才算真正入门大模型——从分词原理到 Embedding 语义实战
javascript·人工智能·算法
vivo互联网技术14 小时前
ICLR 2026 | 基于后验采样的图像恢复方法LearnIR:人脸去阴影、去雾
人工智能·算法·aigc
浮生望15 小时前
JS字符串与回文算法:从包装类到双指针的面试进阶之路
javascript·算法
黄敬峰15 小时前
面试必刷:从JS底层包装类到双指针,彻底搞懂字符串与回文算法
算法
地平线开发者1 天前
J6B vio scenario sample
算法
BothSavage2 天前
Trae远程开发中DeepSeek自定义模型4054错误的排查与修复
算法
小林ixn2 天前
从暴力到KMP:一道题彻底搞懂字符串匹配的前世今生
算法
烬羽2 天前
字符串算法入门:从反转字符串到回文判断,面试不再慌
算法·面试