【七月算法】day05 双指针

一觉惊醒 6:40,md,断了。

392. 判断子序列

题目描述:

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

进阶:

如果有大量输入的 S,称作 S1, S2, ... , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?

思路:

用两个指针i,j分别指向字符串s和t;

因为要在t中找s的字符,所以如果s[i]和t[j]不相等时候,j往后走,相等则一起往后走;

最后判断i是否走到s字符串末尾,如果是,则返回true,否则返回false;

class Solution {
public:
    bool isSubsequence(string s, string t) {
        int i = 0, j = 0;
        while (s[i] && t[j]) {
            if (s[i] == t[j]) {
                i++;
            }
            j++;
        }
        return s[i] == '\0';
        
        // int i = 0, j = 0;
        // while (i < s.size() && j < t.size()) {
        //     if (s[i] == t[j]) {
        //         ++i;
        //     } 
        //     ++j;
            
        // }
        // if (i == s.size()) {
        //     return true;
        // }
        // return false;
        

    }
};

541. 反转字符串 II

题目描述:

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

思路:

根据题目意思,首先无论是否能计数到2k个数,前小于等于k个数肯定是要翻转的,那么重要的是判断需要翻转多少个数即可;

翻转函数可以自己写,也可以用库函数 reverse函数yyds;

class Solution {
    void swap(char &a, char &b) {
        char tmp = a;
        a = b;
        b = tmp;
    }
public:
    string reverseStr(string s, int k) {
        int i;
        int n = s.length();
        int start, end;
        for (i = 0; i < n; i += 2*k) {
            start = i;
            end = min(i + k - 1, n-1);
            while (start < end) {
                swap(s[start++], s[end--]);
            } 
        }
        return s;

        // int n = s.length();
        // for (int i = 0; i < n; i += 2*k) {
        //     reverse(s.begin() + i, s.begin() + min(i + k, n));
        // }
        // return s;
    }
};

面试题 16.24. 数对和

题目描述:

设计一个算法,找出数组中两数之和为指定值的所有整数对。一个数只能属于一个数对。

思路:

典型双指针题目;记得要先排序

class Solution {
public:
    vector<vector<int>> pairSums(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        int i = 0, j = nums.size() - 1;
        vector<vector<int>> ans;
        while (i < j) {
            int sum = nums[i] + nums[j];
            if (sum > target) {
                j--;
            } else if (sum < target) {
                i++;
            } else {
                ans.push_back({nums[i], nums[j]});
                i++;
                j--;
            }
        }
        return ans;

    }
};

696. 计数二进制子串

题目描述:

给定一个字符串 s,统计并返回具有相同数量 0 和 1 的非空(连续)子字符串的数量,并且这些子字符串中的所有 0 和所有 1 都是成组连续的。

重复出现(不同位置)的子串也要统计它们出现的次数。

思路:

可以用双指针,也可用dp;

双指针:

首先找到第一个不与前面字符s[i]相等的字符s[j],记录下位置k;

然后找到最后一个不与前面字符相等的字符s[j],这个时候可以统计次数,这个次数取决于前后两个不相等字符串短的那个串的长度,即min(k-i,j-k)k-i表示前面那个字符串的长度,j-k表示后面那个字符串的长度;

dp:

先遍历字符串,用dp[i]表示统计出的前面到第i个位置能够得到的最长相等子串的长度;

然后令l = dp[i],表示第i个位置的有l个长度相等的子串,那么i-l位置处的字符必定于i处字符不相等,即s[i] != s[i-l],ll = dp[i-l]表示到i-l这个位置有ll个长度相等的字符串,当ll>l时,计数器加一;

class Solution {
     // int dp[100010];
public:
    int countBinarySubstrings(string s) {
        int ans = 0;
        int i = 0, j = 0;
        while (j < s.length()) {
            while (s[i] == s[j] && j < s.length()) {
                ++j;
            }
            int k = j;
            while (s[i] != s[j] && j < s.length()) {
                ++j;
            }
            ans += min(j - k, k - i);
            i = k;
        }
        return ans;
        // int ans = 0;
        // s = '#' + s;
        // for (int i = 1; i < s.length(); ++i) {
        //     if (s[i] == s[i-1]) {
        //         dp[i] = dp[i-1] + 1;
        //     } else {
        //         dp[i] = 1;
        //     }
        // }
        // for (int i = 1; i < s.length(); ++i) {
        //     int l = dp[i]; // 前面有l个字符与s[i]字符相等
        //     int ll = dp[i - l]; // 字符s[i-l]与字符s[i]不相等
        //     if (ll >= l) {
        //         ans ++;
        //     }
        // }
        // return ans;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值