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日

相关文章

  • JavaScrip数组去重操作实例小结

    本文将详细讲解“JavaScript 数组去重操作实例小结”,包括去重的常用方法以及实例说明。 一、常用去重方法 1. Set(ES6新增) ES6 中引入了 Set 数据结构,它类似于数组,但是数组中的元素是不能重复的,可以很方便地实现数组去重。 const arr = [1, 2, 2, 3, 3, 4]; const uniqueArr = […n…

    Java 2023年5月26日
    00
  • 被kafka-client和springkafka版本坑到自闭及解决

    接下来我将详细讲解“被kafka-client和springkafka版本坑到自闭及解决”的完整攻略。 问题描述 在使用Kafka客户端和Spring Kafka时,我们经常遇到版本不兼容的问题。当我们使用不兼容的版本时,代码将无法编译或代码将在运行时崩溃。这使得我们感到困惑和沮丧,因此本攻略将为您讲解如何解决这些问题。 解决方案 了解Spring Kafk…

    Java 2023年5月19日
    00
  • JSP中表达式的使用详解

    《JSP中表达式的使用详解》攻略 一、JSP表达式的介绍 JSP表达式一般用于将变量、常量、函数等的值输出到页面上。 语法格式: <%= 表达式 %> 其中,等号和百分号之间不要有空格。 二、表达式中可使用的内容 变量和常量 在表达式中可以使用变量或常量的值,如: <%= name %> <%= 1234 %> 表达式运算…

    Java 2023年6月15日
    00
  • Java实现的两种常见简单查找算法示例【快速查找与二分查找】

    下面我就来详细讲解一下Java实现的快速查找和二分查找算法。 一、快速查找 快速查找,也称为顺序查找,是一种最简单的查找算法。这种算法就是在待查找的一组数据中,顺序地遍历每一个数据,直到找到待查找的目标数据为止,或者遍历完数组都没有找到目标数据。 Java实现快速查找的代码如下: public class QuickFind { // 查找函数 public…

    Java 2023年5月19日
    00
  • java计算两个日期中间的时间

    如果想要计算两个日期中间的时间,可以使用Java的Date和Calendar类来处理,具体步骤如下: 使用SimpleDateFormat类将输入的两个日期字符串转换为Date对象。 String startDate = "2021-01-01"; String endDate = "2021-06-30"; Simp…

    Java 2023年5月20日
    00
  • Java获取*路径实现探讨

    针对Java获取文件路径的实现方式,我将提供以下几种攻略: 方案一:获取文件相对路径 在Java中,可以使用File类获取文件路径信息,具体步骤如下: 创建File对象,并指定文件名或文件路径。 java File file = new File(“test.txt”); 调用File对象的getAbsolutePath()方法,获取文件的绝对路径。 jav…

    Java 2023年5月20日
    00
  • springboot下使用mybatis的方法

    下面是详细的“springboot下使用mybatis的方法”的攻略: 1. 引入依赖 在pom.xml文件中引入mybatis-spring-boot-starter依赖,如下: <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId&…

    Java 2023年5月20日
    00
  • 红旗Linux4.1下安装配置Apahce+Tomcat+PHP+mySQL+vsFTPd

    下面是在红旗Linux 4.1系统下安装、配置Apache、Tomcat、PHP、MySQL和vsftpd的攻略步骤: 准备工作 安装并正确配置好红旗Linux 4.1系统,获取root权限 确保网络连接正常,可以访问外部网络 确认系统中已经安装了C/C++编译器,以及一些常用的开发工具和库文件 安装Apache 下载最新版本的Apache,使用wget命令…

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