算法总结(双指针)

引言

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

总结

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

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

相关推荐
毕竟是shy哥1 小时前
计算YOLO数据集中每个类的目标数
算法·yolo·机器学习
M78佐菲1 小时前
Linux学习笔记:TCP协议
linux·笔记·学习·tcp/ip·算法
恋恋西风1 小时前
C++ 理解 std::thread 在单核和多核上的行为差异
开发语言·c++
Brilliantwxx1 小时前
【Linux】 进程(9)程序与进程地址空间(基础+进阶+面试题)
linux·运维·服务器·开发语言·c++
BizzZ_2 小时前
C++(22)——类型转换和IO流
开发语言·c++
晊晌_h2 小时前
嵌入式从0到精通——数据结构总结[特殊字符]
数据结构·算法·排序算法
我找到地球的支点啦3 小时前
Matlab系列(009) 一CRC循环冗余校验详解
开发语言·数据结构·算法·matlab·信息与通信
罗西的思考3 小时前
【OpenClaw具身硬件】ZeroClaw 源码阅读笔记(3)--- RAG
人工智能·算法·机器学习
浪里镖客4 小时前
位姿转换矩阵写法-个人习惯(计算机理解其实是相反的)
线性代数·算法·矩阵
青梅味猪大肠5 小时前
【深入浅出C++】为什么虚表指针可以解决菱形继承
开发语言·c++