算法总结(双指针)

引言

题目一:给定一个字符串 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;
    }
};

总结

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

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

相关推荐
花间相见1 小时前
【LeetCode01】—— 无重复字符的最长子串:滑动窗口经典题详解
python·算法·leetcode
wabs6661 小时前
关于动态规划【力扣96.不同的二叉搜索树的递推公式怎么理解?】
算法·动态规划
QiLinkOS1 小时前
极客与商业思维的融合实践(1)
c语言·数据库·c++·人工智能·算法·开源协议
fu的博客1 小时前
【数据结构16】图:基于邻接矩阵、邻接表实现DFS/BFS
数据结构·算法
阿正的梦工坊2 小时前
【Rust】17-Send、Sync 与并发安全抽象
算法·安全·rust
plainGeekDev2 小时前
算法刷题笔记:一维DP没那么难,状态想清楚就赢了一半
java·算法·面试
菩提树下的凡夫2 小时前
新版OpenCV5.0在ONNX模型的推理应用
opencv·算法
坚果派·白晓明2 小时前
鸿蒙PC】libuv适配:AtomCode Skills一站式指南
c语言·c++·华为·ai编程·harmonyos·atomcode
c++之路2 小时前
CMake 系列教程(五):进阶技巧
c语言·开发语言·c++