小白水平理解面试经典题目LeetCode 159. Longest Substring with At Most Two Distinct Characters【Prime】

159. 最多包含两个不同字符的最长子串

一、原题描述与小白翻译

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

给定一个字符串 s ,找到最多包含 2 个不同字符的最长子字符串 t 的长度。

二、例子

在这里插入图片描述
在这里插入图片描述

三、 小白做题

坐在自习室正在准备刷题的小白看到这道题,想想自己那可是没少和白月光做题呢,也不知道小美刷题刷到哪里了,这题怎么还没来问我,难道是因为没买会员看不到这道题?

这时候黑长直女神突然进到教室过来问:小白,你看到二叉树题目了吗,这道159的题目,感觉描述的比较直接,类型算是String类的题目,你有什么好思路吗?

小白内心镇定:这机会不就来了吗,小美,你喜欢李庚希吗,我请你去看《我们一起摇太阳》啊?

在这里插入图片描述
哦,不是,题目描述意思说的简单一些。
这题其实意思上比较好理解,对于示例一来说,一共五个字符,其中要找出一个字符段中只包含两个不同的字符,并且是最长的子字符串是3。
这就是问题所要求的,当涉及子字符串子数组时候,我们又能利用到滑动窗口技术。因此,我们滑动窗口向右移动,直到值是有效的,当窗口向左收缩,来找到我们的窗口,然后右侧运行直到树的长度。

这里我们可以创建一个Map<character, Interger>来创建一个记录每个字符频率的map。

小美:小伙子,可以啊,这不仅进行了解题,阅读理解也有俩下子!不过电影票要你买单哦。

小白:没问题,谁叫为了“真爱”呢。

在这里插入图片描述

四、真正面试环节

面试官:你可以解答这道”从二叉树构造字符串“的题目吗,来看看你对树结构的理解。

小白:嘿嘿,这不巧了么这不是。
在这里插入图片描述

Java 版本

	public static int lengthOfLongestSubstringTwoDistinct(String s) {
        // 空字符串或者null直接返回0
        if (s == null || s.length() == 0) {
            return 0;
        }

        int n = s.length();

        // 哈希表记录每个字符出现的次数
        HashMap<Character, Integer> map = new HashMap<>();

        // 不同字符类型的数量
        int distinctCount = 0, result = 0;

        // 遍历字符串中每一个字符, i代表右边界,循环一次带表右移
        for (int i = 0, j = 0; i < n; i++) {
            char ci = s.charAt(i);

            // 用getOrDefault更新字符出现的次数,如果是新加入的,那么给定默认值0,开始计数
            map.put(ci, map.getOrDefault(ci, 0) + 1);

            // 如果当前字符出现次数为1,则不同字符类型数量加1
            if (map.get(ci) == 1) {
                distinctCount++;
            }

            // 如果记录新生成字符的数字已经超过要求的2,需要缩小滑动窗口
            while (distinctCount > 2) {
                char leftChar = s.charAt(j);
                // 更新左边界字符出现的次数
                map.put(leftChar, map.get(leftChar) - 1);

                // 当这个cj字符值是0的情况下,那么不同字符的总数减去1.
                if (map.get(leftChar) == 0) {
                    distinctCount--;
                }

                // 左边界右移
                j++;
            }

            // 更新这个新结果的字符串长度
            result = Math.max(result, i - j + 1);
        }
        return result;
    }

小明:OK,完事儿,等着面试官来表扬自己吧。他肯定会说:小子,你是个好手!工位都给你准备好了,工资你说了算。

面试官:矮油,不错啊,不过你这能不能写python和c++版本的啊。

小明OS:今年这个找工市场,人言洛阳花似锦,偏我来时不逢春。。。不是,怎么还让我写这么多语法啊!

面试官:这不是咱们面对人群广泛吗,不会写可有很多俊男靓女会写哦。

Python 版本

def length_of_longest_substring_two_distinct(s):
    """
    求解字符串中最多包含两个不同字符的最长子串

    Args:
        s: 字符串

    Returns:
        最长子串长度
    """
    # 空字符串或者None直接返回0
    if not s:
        return 0

    n = len(s)
    
    # 哈希表记录每个字符出现的次数
    char_count = {}
    
    # 不同字符类型的数量
    distinct_count = 0

    # 最长子串长度
    result = 0

    # 左右指针
    i, j = 0, 0

    # 遍历字符串
    for i in range(n):
        c = s[i]

        # 更新字符出现的次数
        char_count[c] = char_count.get(c, 0) + 1

        # 如果当前字符出现次数为1,则不同字符类型数量加1
        if char_count[c] == 1:
            distinct_count += 1

        # 当不同字符类型数量超过2时,需要缩小滑动窗口
        while distinct_count > 2:
            left_char = s[j]

            # 更新左边界字符出现的次数
            char_count[left_char] -= 1

            # 如果左边界字符出现次数为0,则不同字符类型数量减1
            if char_count[left_char] == 0:
                distinct_count -= 1

            # 左边界右移
            j += 1

        # 更新最长子串长度
        result = max(result, i - j + 1)

    return result

C++ 版本

#include <iostream>
#include <unordered_map>

using namespace std;

int lengthOfLongestSubstringTwoDistinct(string s) {
    // 空字符串或者""直接返回0
    if (s.empty()) {
        return 0;
    }

    int n = s.length();

    // 哈希表记录每个字符出现的次数
    unordered_map<char, int> char_count;

    // 不同字符类型的数量
    int distinct_count = 0;

    // 最长子串长度
    int result = 0;

    // 左右指针
    int i = 0, j = 0;

    // 遍历字符串
    for (i = 0; i < n; i++) {
        char c = s[i];

        // 更新字符出现的次数
        char_count[c]++;

        // 如果当前字符出现次数为1,则不同字符类型数量加1
        if (char_count[c] == 1) {
            distinct_count++;
        }

        // 当不同字符类型数量超过2时,需要缩小滑动窗口
        while (distinct_count > 2) {
            char left_char = s[j];

            // 更新左边界字符出现的次数
            char_count[left_char]--;

            // 如果左边界字符出现次数为0,则不同字符类型数量减1
            if (char_count[left_char] == 0) {
                distinct_count--;
            }

            // 左边界右移
            j++;
        }

        // 更新最长子串长度
        result = max(result, i - j + 1);
    }

    return result;
}

小白:您好,面试官,这回可以了吧,我终于有钱请小美看电影了!

在这里插入图片描述

复杂度分析

  • 时间复杂度O(n) :我们遍历包含 n 元素的字符串一次。由于哈希表将查找时间减少到 O(1),因此总体时间复杂度为 O(n) 。
  • 空间复杂度O(n):所需的额外空间取决于哈希表中存储的项目数量,该哈希表恰好存储 n 元素。

🍀🍀🍀 更多精彩免费分析题目可在这里观看 面试数据结构与算法总结分类+leetcode目录【基础版】🍀🍀🍀

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值