C++实现LeetCode(159.最多有两个不同字符的最长子串)

[LeetCode] 159. Longest Substring with At Most Two Distinct Characters 最多有两个不同字符的最长子串

Given a string s , find the length of the longest substring t  that contains at most 2 distinct characters.

Example 1:

Input: "eceba"
Output: 3
Explanation: tis "ece" which its length is 3.

Example 2:

Input: "ccaabbb"
Output: 5
Explanation: tis "aabbb" which its length is 5.

这道题给我们一个字符串,让求最多有两个不同字符的最长子串。那么首先想到的是用 HashMap 来做,HashMap 记录每个字符的出现次数,然后如果 HashMap 中的映射数量超过两个的时候,这里需要删掉一个映射,比如此时 HashMap 中e有2个,c有1个,此时把b也存入了 HashMap,那么就有三对映射了,这时 left 是0,先从e开始,映射值减1,此时e还有1个,不删除,left 自增1。这时 HashMap 里还有三对映射,此时 left 是1,那么到c了,映射值减1,此时e映射为0,将e从 HashMap 中删除,left 自增1,然后更新结果为 i - left + 1,以此类推直至遍历完整个字符串,参见代码如下:

解法一:

class Solution {
public:
    int lengthOfLongestSubstringTwoDistinct(string s) {
        int res = 0, left = 0;
        unordered_map<char, int> m;
        for (int i = 0; i < s.size(); ++i) {
            ++m[s[i]];
            while (m.size() > 2) {
                if (--m[s[left]] == 0) m.erase(s[left]);
                ++left;
            }
            res = max(res, i - left + 1);
        }
        return res;
    }
};

我们除了用 HashMap 来映射字符出现的个数,还可以映射每个字符最新的坐标,比如题目中的例子 "eceba",遇到第一个e,映射其坐标0,遇到c,映射其坐标1,遇到第二个e时,映射其坐标2,当遇到b时,映射其坐标3,每次都判断当前 HashMap 中的映射数,如果大于2的时候,那么需要删掉一个映射,还是从 left=0 时开始向右找,看每个字符在 HashMap 中的映射值是否等于当前坐标 left,比如第一个e,HashMap 此时映射值为2,不等于 left 的0,那么 left 自增1,遇到c的时候,HashMap 中c的映射值是1,和此时的 left 相同,那么我们把c删掉,left 自增1,再更新结果,以此类推直至遍历完整个字符串,参见代码如下:

解法二:

class Solution {
public:
    int lengthOfLongestSubstringTwoDistinct(string s) {
        int res = 0, left = 0;
        unordered_map<char, int> m;
        for (int i = 0; i < s.size(); ++i) {
            m[s[i]] = i;
            while (m.size() > 2) {
                if (m[s[left]] == left) m.erase(s[left]);
                ++left;
            }
            res = max(res, i - left + 1);
        }
        return res;
    }
};

后来又在网上看到了一种解法,这种解法是维护一个 sliding window,指针 left 指向起始位置,right 指向 window 的最后一个位置,用于定位 left 的下一个跳转位置,思路如下:

1. 若当前字符和前一个字符相同,继续循环。

2. 若不同,看当前字符和 right 指的字符是否相同

    (1) 若相同,left 不变,右边跳到 i - 1

    (2) 若不同,更新结果,left 变为 right+1,right 变为 i - 1

最后需要注意在循环结束后,还要比较结果 res 和 s.size() - left 的大小,返回大的,这是由于如果字符串是 "ecebaaa",那么当 left=3 时,i=5,6 的时候,都是继续循环,当i加到7时,跳出了循环,而此时正确答案应为 "baaa" 这4个字符,而我们的结果 res 只更新到了 "ece" 这3个字符,所以最后要判断 s.size() - left 和结果 res 的大小。

另外需要说明的是这种解法仅适用于于不同字符数为2个的情况,如果为k个的话,还是需要用上面两种解法。

解法三:

class Solution {
public:
    int lengthOfLongestSubstringTwoDistinct(string s) {
        int left = 0, right = -1, res = 0;
        for (int i = 1; i < s.size(); ++i) {
            if (s[i] == s[i - 1]) continue;
            if (right >= 0 && s[right] != s[i]) {
                res = max(res, i - left);
                left = right + 1;
            }
            right = i - 1;
        }
        return max(s.size() - left, res);
    }
};

还有一种不使用 HashMap 的解法,是在做 Fruit Into Baskets 这道题的时候在论坛上看到的,其实这两道题除了背景设定之外没有任何的区别,代码基本上都可以拷来直接用的。这里使用若干的变量,其中 cur 为当前最长子串的长度,first 和 second 为当前候选子串中的两个不同的字符,cntLast 为 second 字符的连续长度。遍历所有字符,假如遇到的字符是 first 和 second 中的任意一个,那么 cur 可以自增1,否则 cntLast 自增1,因为若是新字符的话,默认已经将 first 字符淘汰了,此时候选字符串由 second 字符和这个新字符构成,所以当前长度是 cntLast+1。然后再来更新 cntLast,假如当前字符等于 second 的话,cntLast 自增1,否则均重置为1,因为 cntLast 统计的就是 second 字符的连续长度。然后再来判断若当前字符不等于 second,则此时 first 赋值为 second, second 赋值为新字符。最后不要忘了用 cur 来更新结果 res,参见代码如下:

解法四:

class Solution {
public:
    int lengthOfLongestSubstringTwoDistinct(string s) {
        int res = 0, cur = 0, cntLast = 0;
        char first, second;
        for (char c : s) {
            cur = (c == first || c == second) ? cur + 1 : cntLast + 1;
            cntLast = (c == second) ? cntLast + 1 : 1;
            if (c != second) {
                first = second; second = c;
            }
            res = max(res, cur);
        }
        return res;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/159

类似题目:

Fruit Into Baskets

Longest Substring Without Repeating Characters

Sliding Window Maximum

Longest Substring with At Most K Distinct Characters

Subarrays with K Different Integers

参考资料:

https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/

https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/discuss/49759/Share-my-c%2B%2B-solution

https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/discuss/49687/Clean-11-lines-AC-answer-O(1)-space-O(n)-time.

https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/discuss/49682/Simple-O(n)-java-solution-easily-extend-to-k-characters

https://leetcode.com/problems/longest-substring-with-at-most-two-distinct-characters/discuss/49708/Sliding-Window-algorithm-template-to-solve-all-the-Leetcode-substring-search-problem.

到此这篇关于C++实现LeetCode(159.最多有两个不同字符的最长子串)的文章就介绍到这了,更多相关C++实现最多有两个不同字符的最长子串内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++实现LeetCode165.版本比较)

    [LeetCode] 165.Compare Version Numbers 版本比较 Compare two version numbers version1 and version2. If version1 > version2 return 1; if version1 <version2 return -1;otherwise return 0. You may assume that the version strings are non-empty and contain onl

  • C++实现LeetCode(228.总结区间)

    [LeetCode] 228.Summary Ranges 总结区间 Given a sorted integer array without duplicates, return the summary of its ranges. Example 1: Input:  [0,1,2,4,5,7] Output: ["0->2","4->5","7"] Explanation: 0,1,2 form a continuous ran

  • C++实现LeetCode(164.求最大间距)

    [LeetCode] 164. Maximum Gap 求最大间距 Given an unsorted array, find the maximum difference between the successive elements in its sorted form. Return 0 if the array contains less than 2 elements. Example 1: Input: [3,6,9,1] Output: 3 Explanation: The sor

  • C++实现LeetCode(163.缺失区间)

    [LeetCode] 163. Missing Ranges 缺失区间 Given a sorted integer array nums, where the range of elements are in the inclusive range [lower, upper], return its missing ranges. Example: Input: nums = [0, 1, 3, 50, 75], lower = 0 and upper = 99, Output: ["2&q

  • C++实现LeetCode(160.求两个链表的交点)

    [LeetCode] 160.Intersection of Two Linked Lists 求两个链表的交点 Write a program to find the node at which the intersection of two singly linked lists begins. For example, the following two linked lists: A:          a1 → a2 c1 → c2 → c3             B:     b1

  • C++实现LeetCode(162.求数组的局部峰值)

    [LeetCode] 162.Find Peak Element 求数组的局部峰值 A peak element is an element that is greater than its neighbors. Given an input array nums, where nums[i] ≠ nums[i+1], find a peak element and return its index. The array may contain multiple peaks, in that c

  • C++实现LeetCode(904.水果装入果篮)

    [LeetCode] 904. Fruit Into Baskets 水果装入果篮 In a row of trees, the `i`-th tree produces fruit with type `tree[i]`. You start at any tree of your choice, then repeatedly perform the following steps: Add one piece of fruit from this tree to your baskets.

  • C++实现LeetCode(161.一个编辑距离)

    [LeetCode] 161. One Edit Distance 一个编辑距离 Given two strings s and t, determine if they are both one edit distance apart. Note:  There are 3 possiblities to satisify one edit distance apart: Insert a character into s to get t Delete a character from s 

  • C++实现LeetCode(159.最多有两个不同字符的最长子串)

    [LeetCode] 159. Longest Substring with At Most Two Distinct Characters 最多有两个不同字符的最长子串 Given a string s , find the length of the longest substring t  that contains at most 2 distinct characters. Example 1: Input: "eceba" Output: 3 Explanation: ti

  • 利用正则表达式校验金额最多保留两位小数实例代码

    目录 正则表达式校验金额最多保留两位小数,那么必须满足如下条件: 部分正则表达式符号说明: 第一步,小数点之前表达式 第二步,小数点及小数位置 总结 先给出表达式结果:^(([1-9]{1}\d*)|(0{1}))(\.\d{1,2})?$ 有同学留言0识别错误,可用这个:(([1-9]{1}\d*)(.\d{1,2})?)|(0{1}.\d{1,2})思路:1.小数点前非0,则小数位置可有可无: 2.小数点前为0,那么小数位置必有修改于 2022-08-03 不熟悉正则表达式的同学,咋一看,一

  • LeetCode 刷题 Swift 两个数组的交集

    目录 题目 方法一:两个集合 思路及解法 代码 复杂度分析 方法二:排序 + 双指针 思路及解法 代码 复杂度分析 题目 给定两个数组 nums1 和 nums2,返回 它们的交集 .输出结果中的每个元素一定是 唯一 的.我们可以 不考虑输出结果的顺序 . 示例 1: 输入: nums1 = [1,2,2,1], nums2 = [2,2] 输出: [2] 示例 2: 输入: nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出: [9,4] 解释: [4,9] 也是可

  • JS如何去掉小数末尾多余的0,并且最多保留两位小数

    目录 js去掉小数末尾多余的0,并且最多保留两位小数 思路 js去掉小数点后面的0 (uniapp 和 vue比较适用) 总结 js去掉小数末尾多余的0,并且最多保留两位小数 比如: '' -> 00.00 -> 01 -> 11.10 -> 11.213000 -> 1.211.01 -> 1.01 代码如下: 思路 用JavaScript的parseFloat函数,parseFloat(’ ') 是NaN,返回0,然后用parseFloat转换字符串或者数字,判断是

  • js正则表达式 匹配两个特定字符间的内容示例

    1.js截取两个字符串之间的内容: var str = "aaabbbcccdddeeefff"; str = str.match(/aaa(\S*)fff/)[1]; alert(str);//结果bbbcccdddeee 2.js截取某个字符串前面的内容: var str = "aaabbbcccdddeeefff"; tr = str.match(/(\S*)fff/)[1]; alert(str);//结果aaabbbcccddd 3.js截取某个字符串后面

  • 使用Python 正则匹配两个特定字符之间的字符方法

    如下所示: # -*- coding: cp936 -*- import re   string = "xxxxxxxxxxxxxxxxxxxxxxxx entry '某某内容' for aaaaaaaaaaaaaaaaaa" result = re.findall(".*entry(.*)for.*",string) for x in result:     print x # '某某内容' 以上这篇使用Python 正则匹配两个特定字符之间的字符方法就是小编分享

  • c#获取两个特定字符之间的内容并输出的方法

    今天一直在绞尽脑汁的寻找解决两个字符之间的内容如何输出的问题,刚开始就使用了万能的正则表达式:但是不知哪里的原因 自己的数据一直出不来,觉得应该是我输入的字符的问题吧,因为我获取的是一个inp文件里的内容(类似与文本文件): 虽然这次正则表达的强大没有被我展示出来,但是依旧捍卫不了他在我心里的位子:还是有必要把他的使用方法贴出来: string result=regex.matchs(your str, "(?<=beginstr).*?(?=endstr)").value 经过

  • 分享几道和「滑动窗口」有关的算法面试题

    前言科普:什么是滑动窗口算法 滑动问题包含一个滑动窗口,它是一个运行在一个大数组上的子列表,该数组是一个底层元素集合. 假设有数组 [a b c d e f g h ],一个大小为 3 的 滑动窗口 在其上滑动,则有: [a b c] [b c d] [c d e] [d e f] [e f g] [f g h] 一般情况下就是使用这个窗口在数组的 合法区间 内进行滑动,同时 动态地 记录一些有用的数据,很多情况下,能够极大地提高算法地效率. 1. 滑动窗口最大值 题目来源于 LeetCode

  • Python3 无重复字符的最长子串的实现

    题目: 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例: 示例 1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3. 示例 2: 输入: "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1. 示例 3: 输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 &quo

随机推荐