C#算法之无重复字符的最长子串

C#算法之无重复字符的最长子串

问题描述

给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。

示例 1:

输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。

示例 2:

输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

解决思路

暴力法

对于每一个字符从它开始依次枚举所有可能的子串,检查每个子串是否含有重复字符。

复杂度分析:
- 时间复杂度:O(n^3),枚举所有子串需要 O(n^2),检查每个子串是否含有重复字符需 O(n)
- 空间复杂度:O(min(n,m)),n 是字符串长度,m 是字符集大小。

滑动窗口法

使用哈希表来判重,定义两个指针 ij 分别代表窗口的左右边界。从左边界开始,逐一向右尝试扩大窗口大小,每次判断右侧添加的字符是否已经在窗口内出现过,如果已经出现过则缩小窗口,即左边界右移,同时左侧字符从哈希表中移除。

复杂度分析:
- 时间复杂度:O(n),窗口大小从1向右依次遍历,每个字符最多被访问两次,一次是右边界扫描,一次是左边界扫描。
- 空间复杂度:O(min(n,m)),右边界不断向右扩张,因此只需要在哈希表中存储字符的最后出现位置即可,而由于最多有m个不同字符,因此空间复杂度为O(min(n,m))。

代码实现

暴力法代码

public int LengthOfLongestSubstring(string s) {
    int n = s.Length;
    int ans = 0;
    for (int i = 0; i < n; i++) {
        for (int j = i + 1; j <= n; j++) {
            if (AllUnique(s, i, j)) ans = Math.Max(ans, j - i);
        }
    }
    return ans;
}

private bool AllUnique(string s, int start, int end) {
    HashSet<char> set = new HashSet<char>();
    for (int i = start; i < end; i++) {
        char c = s[i];
        if (set.Contains(c)) return false;
        set.Add(c);
    }
    return true;
}

滑动窗口法代码

public int LengthOfLongestSubstring(string s) {
    int n = s.Length, ans = 0;
    Dictionary<char, int> dict = new Dictionary<char, int>();
    for (int i = 0, j = 0; j < n; j++) {
        if (dict.ContainsKey(s[j])) i = Math.Max(dict[s[j]], i);
        ans = Math.Max(ans, j - i + 1);
        dict[s[j]] = j + 1;
    }
    return ans;
}

示例说明

示例一

输入: "abcabcbb"
输出: 3

暴力法的思路:逐一枚举所有子串,检查每个子串是否含有重复字符。

  • 子串"a"没有重复字符。
  • 子串"ab"没有重复字符。
  • 子串"abc"没有重复字符。
  • 子串"abca"有重复字符"a",因此子串"abca"被排除。
  • 子串"b"没有重复字符。
  • 子串"bc"没有重复字符。
  • 子串"bca"有重复字符"c",因此子串"bca"被排除。
  • 子串"bcab"有重复字符"b",因此子串"bcab"被排除。
  • 子串"c"没有重复字符。
  • 子串"cb"有重复字符"b",因此子串"cb"被排除。
  • 子串"cbb"有重复字符"b",因此子串"cbb"被排除。
  • 子串"cbba"有重复字符"b"和"a",因此子串"cbba"被排除。

因此,无重复字符的最长子串是"abc",长度为3。

滑动窗口法的思路:定义两个指针ij分别代表窗口的左右边界,使用哈希表来判重。从左边界开始,逐一向右尝试扩大窗口大小,每次判断右侧添加的字符是否已经在窗口内出现过,如果已经出现过则缩小窗口,即左边界右移,同时左侧字符从哈希表中移除。

  • 首先,i=0,j=0已经覆盖了第一个字符"a"。
  • 向右移动右指针,j=1,发现字符"b"未曾出现,此时窗口大小为2。
  • 向右移动右指针,j=2,发现字符"c"未曾出现,此时窗口大小为3。
  • 向右移动右指针,j=3,发现字符"a"曾经在(i,j)范围内出现过,于是将左指针右移,此时i=1,窗口大小为2。
  • 向右移动右指针,j=4,发现字符"b"曾经在(i,j)范围内出现过,于是将左指针右移,此时i=2,窗口大小为2。
  • 向右移动右指针,j=5,发现字符"c"曾经在(i,j)范围内出现过,于是将左指针右移,此时i=3,窗口大小为2。
  • 向右移动右指针,j=6,发现字符"b"曾经在(i,j)范围内出现过,于是将左指针右移,此时i=4,窗口大小为2。

因此,无重复字符的最长子串是"abc",长度为3。

示例二

输入: "bbbbb"
输出: 1

暴力法的思路:逐一枚举所有子串,检查每个子串是否含有重复字符。

  • 子串"b"没有重复字符。
  • 子串"bb"有重复字符"b",因此子串"bb"被排除。
  • 子串"bbb"有重复字符"b",因此子串"bbb"被排除。
  • 子串"bbbb"有重复字符"b",因此子串"bbbb"被排除。

因此,无重复字符的最长子串是"b",长度为1。

滑动窗口法的思路:定义两个指针ij分别代表窗口的左右边界,使用哈希表来判重。从左边界开始,逐一向右尝试扩大窗口大小,每次判断右侧添加的字符是否已经在窗口内出现过,如果已经出现过则缩小窗口,即左边界右移,同时左侧字符从哈希表中移除。

  • 首先,i=0,j=0已经覆盖了第一个字符"b"。
  • 向右移动右指针,j=1,发现字符"b"曾经在(i,j)范围内出现过,于是将左指针右移,此时i=1,窗口大小为1。
  • 向右移动右指针,j=2,发现字符"b"曾经在(i,j)范围内出现过,于是将左指针右移,此时i=2,窗口大小为1。
  • 向右移动右指针,j=3,发现字符"b"曾经在(i,j)范围内出现过,于是将左指针右移,此时i=3,窗口大小为1。
  • 向右移动右指针,j=4,发现字符"b"曾经在(i,j)范围内出现过,于是将左指针右移,此时i=4,窗口大小为1。

因此,无重复字符的最长子串是"b",长度为1。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C#算法之无重复字符的最长子串 - Python技术站

(0)
上一篇 2023年5月31日
下一篇 2023年5月31日

相关文章

  • java后端把数据转换为树,map递归生成json树,返回给前端(后台转换)

    首先,需要明确一下这个过程的流程和目的:将后端获得的数据转换为树形结构,再通过递归生成 JSON 树,并返回给前端。下面我们将详细讲解这个过程。 1. 将数据转换为树形结构 首先,需要将后端的数据进行转换,变成树形结构。可以使用递归来完成这个过程。 具体实现方式如下:首先,定义一个树节点的类 Node,包含节点名称、节点编号、父节点编号、节点类型等属性。然后…

    Java 2023年5月26日
    00
  • 如何利用反射批量修改java类某一属性的代码详解

    针对如何利用反射批量修改Java类某一属性的问题,下面是一个完整的攻略: 1. 反射基础 Java反射是指在运行时动态地获取对象的元信息,包括类、方法、字段等,并对其进行操作。使用反射可以实现很多动态性较高的功能,例如动态创建对象、动态获取类的信息、动态调用方法等。 具体实现Java反射需要使用到以下几个核心类: Class:代表一个类类型,可以获取类的名称…

    Java 2023年6月15日
    00
  • Java图书管理系统课程设计

    Java图书管理系统课程设计攻略 一、需求分析 在进行Java图书管理系统课程设计之前,需要对系统需求进行分析和明确。在这个阶段,需要考虑的问题包括: 系统的主要功能模块,如图书信息录入、查询、借阅、归还等等。 系统的用户管理模块,包括管理员和普通用户的不同权限和功能。 系统的数据存储模块,需要设计数据库表结构和关键数据处理逻辑等。 二、设计数据库 根据需求…

    Java 2023年5月24日
    00
  • 详解Android客户端与服务器交互方式

    非常感谢您对Android客户端与服务器交互方式的关注。在此给您详细讲解Android客户端与服务器交互方式的攻略。 什么是Android客户端与服务器交互? Android客户端与服务器交互是指在Android手机上使用网络协议与服务器进行数据交互的过程。这种交互方式被广泛应用在Android应用程序的开发中,比如基于网络服务的即时通讯、电商 App 中的…

    Java 2023年5月19日
    00
  • SpringBoot整合kafka遇到的版本不对应问题及解决

    下面是关于“SpringBoot整合kafka遇到的版本不对应问题及解决”的完整攻略。 问题描述 在SpringBoot项目中,我们通过kafka实现消息的发送和接收,在整合kafka时,经常会遇到这样的问题,就是当我们在pom.xml文件中配置kafka依赖时,如果选择的版本不正确,就会引发一系列异常。 问题解决 在解决这个问题之前,首先需要了解kafka…

    Java 2023年5月20日
    00
  • Spring MVC 拦截器 interceptor 用法详解

    Spring MVC 拦截器(Interceptor)用法详解 什么是拦截器 拦截器是Spring MVC框架中的一种增强处理器,拦截器也可以称为过滤器(Filter)或者AOP实现,它可以在请求处理的过程中预处理请求、处理请求和处理完请求后进行后续处理。拦截器可以将特定的处理逻辑应用到整个应用程序或者某个特定的Controller中。 和Servlet的过…

    Java 2023年5月20日
    00
  • Java 类型信息详解和反射机制介绍

    Java 类型信息详解和反射机制介绍 Java是一种强类型语言,因此在编写Java程序时,对于变量、方法、类及接口等定义都需要指定明确的类型信息。Java提供了反射机制,可以在程序运行时获取类的信息及其成员对象,以及对这些对象进行操作。 Java 类型信息 Java的类型系统可以分为两类:原始类型与引用类型。Java的原始类型有八种,分别是boolean、b…

    Java 2023年5月26日
    00
  • Java中关于char类型变量能够输出中文的问题

    Java中的char类型变量能够输出中文,是因为Java使用的是Unicode字符编码标准,其中全球所有的字符都有唯一的码位,包括中文字符。在Java中,char类型变量以16位无符号整数形式存储字符。由于Unicode字符集在编码范围内包含了中文字符,所以Java的char类型变量和String类型能将中文字符完美输出。 在Java中,对于char类型变量…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部