最字头之四:最长不重复字串

最长不重复子串 最长不重复子串就是从一个字符串中找到一个连续子串,该子串中任何两个字符都不能相同,且该子串的长度是最大的。 每个测试用例的输入由一行小写英文字母a,b,c...,z组成,字符串的长度不超过10000. example:input: abcdaba output:4 abcd C++ 实现: #include <iostream> ... 阅读详情
文章作者:Yx.Ac   文章来源:勇幸|Thinking (http://www.ahathinking.com)   转载请注明,谢谢合作。

---

注:代码为本人参考作者实现的。并非作者的代码,如果有错误请见谅!

题:从一个字符串中找到一个连续子串,该子串中任何两个字符不能相同,求子串的最大长度并输出一条最长不重复子串。

本节从最直接的方法逐步优化,渐进探索了四种实现方式,并最终找到时间复杂度为O(N),辅助空间为常数的方案,内容如下:

==基本算法 使用Hash==

==DP方案==

==DP + Hash 方案==

==DP + Hash 优化方案==

==================================

基本算法 使用Hash

要求子串中的字符不能重复,判重问题首先想到的就是hash,寻找满足要求的子串,最直接的方法就是遍历每个字符起始的子串,辅助hash,寻求最长的不重复子串,由于要遍历每个子串故复杂度为O(n^2),n为字符串的长度,辅助的空间为常数hash[256]。代码如下:

#include <iostream>
#include <string>
#include <memory.h>
using namespace std;

int main(){
   string str;
   int maxlen = 0;
   int index = 0;
   int visit[27];
   cin >> str;
   int size = str.size();
   for(int i = 0; i < size; i++){
	  memset(visit,0,sizeof(visit));
      for(int j = i;j < size; j++){
	     if(visit[str[j]-96] == 0){
		    visit[str[j]-96] = 1;
		 }else{
		    if(j - i > maxlen){
			   maxlen = j - i;
			   index = i;
			}
			break;//the point!
		 }
	  }
   }
   for(int i = index; i < index + maxlen; i++)
	   cout << str[i];
   cout << endl;
   return 0;
}

DP方案

前面刚刚讨论过最长递增子序列的问题,咋一想就觉得二者有点类似,何不向DP方面想一下,为什么说二者类似,在LIS问题中,对于当前的元素,要么是与前面的LIS构成新的最长递增子序列,要么就是与前面稍短的子序列构成新的子序列或单独构成新子序列;

同理,对于最长不重复子串,某个当前的字符,如果它与前面的最长不重复子串中的字符没有重复,那么就可以以它为结尾构成新的最长子串;如果有重复,且重复位置在上一个最长子串起始位置之后,那么就与该起始位置之后的稍短的子串构成新的子串或者单独成一个新子串。

举个例子:例如字符串“abcdeab”,第二个字符a之前的最长不重复子串是“abcde”,a与最长子串中的字符有重复,但是它与稍短的“bcde”串没有重复,于是它可以与其构成一个新的子串,之前的最长重复子串“abcde”结束;

再看一个例子:字符串“abcb”,跟前面类似,最长串“abc”结束,第二个字符b与稍短的串“c”构成新的串;

这两个例子,可以看出些眉目:当一个最长子串结束时(即遇到重复的字符),新的子串的长度是与第一个重复的字符的下标有关的,如果该下标在上一个最长子串起始位置之前,则dp[i] = dp[i-1] + 1,即上一个最长子串的起始位置也是当前最长子串的起始位置;如果该下标在上一个最长子串起始位置之后,则新的子串是从该下标之后开始的。

于是类似LIS,对于每个当前的元素,我们“回头”去查询是否有与之重复的,如没有,则最长不重复子串长度+1,如有,则考察上一个子串起始位置与重复字符下标的关系,当然,如果DP使用O(n^2)的方案,则我们只需在内层循环遍历到上一个最长子串的起始位置即可,如下。

O(N^2)的DP方案,我们可以与LIS的DP方案进行对比,是一个道理的。代码如下:

作者的代码:

/* LNRS dp */
int dp[30];
 
void LNRS_dp(char * arr, int size)
{
    int i, j;
    int last_start = 0;     // 上一次最长子串的起始位置
    maxlen = maxindex = 0;
 
    dp[0] = 1;
    for(i = 1; i < size; ++i)
    {
        for(j = i-1; j >= last_start; --j) // 遍历到上一次最长子串起始位置
        {
            if(arr[j] == arr[i])
            {
                dp[i] = i - j;
                last_start = j+1; // 更新last_start
                break;//Point!!!
            }else if(j == last_start) // 无重复
            {
                dp[i] = dp[i-1] + 1;
            }
        }
        if(dp[i] > maxlen)
        {
            maxlen = dp[i];
            maxindex = i + 1 - maxlen;
        }
    }
    output(arr);
}
我的实现代码:

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
//bool contains(char x,string str){
   // bool con = false;
  // for(int i = 0; i < str.size(); i++)
	//   if(str[i] == x)
	//	   return true;
  // return false;
//}
int contains(char x,string str,int index){
   for(int i = 0; i < str.size(); i++)
	   if(str[i] == x)
		   return i + index;
   return -1;
}
int main(){
  string str;
  int maxlen = 0;
  int index = 0;
  int forindex = 0;
  int dp[40] = {0};
  cin >> str;
  dp[0] = 1;
  for(int i = 1; i < str.size(); i++){
     if(contains(str[i],str.substr(forindex,i-forindex),forindex) == -1){
	    dp[i] = dp[i-1] + 1;
		if(dp[i] > maxlen){
		  maxlen = dp[i];
		  index = i;
		}
	 }
	 else{
	    forindex = contains(str[i],str.substr(forindex,i-forindex),forindex)+1;
		dp[i] = i - forindex + 1;
		if(dp[i] > maxlen){
		  maxlen = dp[i];
		  index = i;
		}
	 }
  }
  //sort(dp,dp+str.size());
  for(int i = index - maxlen + 1; i <= index; i++)
	  cout << str[i];
  cout << endl;
  return 0;
}




【算子】不重复字符串子串最长长度 在一个字符串中找到没有重复字符子串中最长的长度。。“owke” 是一个子字符序列但不是一个子字符串。 阅读详情

相关推荐

Benchmark系列——基本概念和分类

本文主要介绍了Benchmark的基本概念和分类情况。

Bluetangos的博客 8438

【无重复字符的最长子串--三种方法】

大家好,今天我们来讨论一下LeetCode上关于数组方面的一个题目:无重复字符的最长子串。题目不难,方法很多。熊猫希望通过这一道简单的题目来使大家了解到不同的解题方法。LeetCode03以上就是今天讲解的无重复字符串的全部内容,题目不难,也不难讲。不过这些解题方法却很重要。的支持。

m0_熊猫馆主的博客 1万+

Claude Code 实战指南:从入门到高效编程

本文是一份Claude Code实战指南,旨在帮助开发者从入门到精通这款AI编程助手。文章详细讲解了如何通过清晰的指令公式与Claude Code高效沟通,并展示了如何将其深度集成到日常开发工作流中,例如理解陌生代码、调试和生成测试文档。指南还提供了避坑建议与最佳实践,并通过构建一个天气查询CLI工具的完整案例,演示了如何利用Claude Code加速开发进程,实现从设计到代码的高效人机协作。

weixin_28339967的博客 484

Leetcode 无重复字符的最长子串

哈希表只存储每个字符最近一次出现的位置,是为了在滑动窗口中快速查找字符的最近出现情况,从而在 O(1) 的时间内决定是否需要更新窗口的起点。这样可以确保算法的时间复杂度为 O(n),在处理大规模输入时仍能高效运行。// 存储字符和其索引// 无重复字符子串的最大长度// 滑动窗口的起始位置++end) {// 如果当前字符已经在滑动窗口中,更新起始位置到其下一个位置// 更新当前字符的索引// 更新最大长度string s;cout << "请输入一个字符串: ";

985小菜鸡 1948

Infiniband互连网络概述

一、Infiniband是什么? InfiniBand(简称IB)是一种工业标准规范,它定义了一种输入/输出架构,用于计算节点、通信基础设施设备、存储和嵌入式系统的互连。操作系统可以是Linux、Windows或ESXI。 IB网络一共是五层,从第一天起,IB就被设计为提供一个端到端的解决方案,改善和加速从物理层到上层的所有协议层。 IB协议于2000年由IBTA(InfiniBand Trade Association)提出,其规定了一...

weixin_41687819的博客 5229

C语言—for循环打印矩形,正三角形,倒三角形,九九乘法,等腰三角形,倒着的等腰三角形(简易版代码)(重点考察for循环嵌套)

本章节教大家如何利用for循环打印正三角形,倒三角形,九九乘法表及等腰三角形(简易版代码)说明:1、循环语句的循环体内又包含另一个完整的循环结构,称为循环结构的嵌套。内嵌的循环语句中还可以再嵌套循环结构,这样就形成多重循环结构的嵌套。2、for 语句、while 语句和 do-while 语句都允许嵌套。三种循环语句可以相互嵌套。3、内层的循环语句必须完全被包含在外层的循环体中,不能发生交叉。

m0_63501145的博客 1695

【算法】字符串中的最长无重复子串(三种解法)

问题: 求一个字符串中的最长无重复子串,或者说求一个数组中最长的无重复子数组(都是一种意思) 输入:abcdedafg 输出:5 解释:abcde这是一个最长的无重复子串,同理edafg也是。所以最长的无重复子串是5 方法一:借助unordered_set和left,right指针 算法思想:left指针开始的时候指向set中的第一个元素。right向后遍历,遍历到的数字如果set中没有则加...

进阶之路 1万+

《AFSim 2.9中文参考手册》

本栏目将对《AFSim 2.9中文参考手册》进行持续更新,欢迎关注交流!对本文或者AFSIM相关内容感兴趣的朋友,可私心联系作者。《AFSim 2.9中文参考手册》内容概览。

henggesim的博客 1万+

最长无重复子串

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

stable_zl的博客 1214

Arduino安装图文教程:小白也能轻松上手

手把手带你完成Arduino安装全过程,无论你是编程新手还是硬件小白,都能快速搭建开发环境。结合arduino安装教程与实操步骤,避开常见错误,让创作即刻启程。

weixin_35509395的博客 1107

【06】新国都——新国都 嵌入式笔试,校招,题目记录及解析

本文总结了新国都嵌入式校招笔试题目及解析,内容涵盖C语言基础、Linux系统、数据结构与算法等多个方面。主要包括:1)不定项选择题10道,涉及字符串常量、蓝牙与GPRS区别、编译错误识别等;2)判断题10道,考察Linux权限、循环控制、内存管理等;3)填空题5道,包括编码计算、逻辑运算、宏定义等;4)简答题2道,解析全局变量引用和进程线程区别。题目难度适中,重点考察嵌入式开发基础知识和编程能力,并提供详细解析和扩展知识链接,对准备嵌入式相关笔试具有参考价值。

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 1432

无重复字符的最长子串

无重复字符的最长子串

weixin_42029738的博客 1万+

lammps 案例:高熵合金FeNiCrCoCu建模及拉伸模拟

高熵合金力学性能模拟包括拉伸、剪切、摩擦等模拟,本文以高熵合金FeNiCrCoCu为例介绍高熵合金建模及拉伸过程模拟。 FeNiCrCoCu原子数量比为1:1:1:1:1 高熵合金的拉伸与单晶拉伸过程类似,主要包含以下步骤: 1.建模 高熵合金含有原子类型较多,建模时,一般以含量最多的原子为主建立初始模型。 使用set type/ratio或者set type/fraction的方式按一定比例替换为其它合金原子。 如随机选择20%的原子1,将其转换为原子2: set type 1 type/ratio 2

lammps_jiayou的博客 6067

最字头之二:最长公共字串

除代码外,其他文字部分均为直接转载。代码为参考。 文章作者:Yx.Ac   文章来源:勇幸|Thinking (http://www.ahathinking.com)   转载请注明,谢谢合作。 --- 这个LCS跟前面说的最长公共子序列的LCS不一样,不过也算是LCS的一个变体,在LCS中,子序列是不必要求连续的,而子串则是“连续”的。即: 题:给定两个字符串X,Y,求二

1ouis的专栏 1003

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

leetcode:无重复字符的最长字串(详解)

内容包括:题目,代码实现及注释,思路详解

weixin_73142957的博客 1610

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

力扣(三)

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 示例 2: 输入: s = "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 示例 3: 输入: s = "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pw

Touale的博客 723

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

无重复字符的最长字串

然后往后找,右指针指向b, 不重复,继续,右指针指向c, 不重复,继续。此时子串是abca, 此时应该把左指针移到第一个a的后面,也就是b的位置,此时子串就不重复了,继续,右指针指向b,此时子串是bcab,又重复了,左指针应该指向c。向右遍历字符,如果遍历到的新字符不存在于当前子串中,就把右指针向右滑动,如果有重复了,就从子串中找和他重复的那个字符,把左指针放到找到的这个字符的后面。请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。示例 3:输入: s = "pwwkew"

dlz_yhn的博客 1332

【子串】3. 无重复的最长子串

力扣刷题;子串问题;

Smileyan's blog 1万+

滑动窗口算法

滑动窗口算法 滑动窗口算法可以用以解决数组/字符串的子元素问题,它可以将嵌套的循环问题,转换为单循环问题,降低时间复杂度。 给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。 输入: s = “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 通过不断滑动窗口的大小,判断窗口中元素是否相同,从而解决问题。 滑动窗口法的思路 我们在字符串 S 中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引闭区间 [left, rig.

qq_45131570的博客 539

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

无重复字符的子串是指在一个字符串中,没有任何字符重复出现的连续子序列。例如,在字符串 “abcabcbb” 中,最长的无重复字符子串是 “abc”,长度为3。

一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身"农奴"把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟! 2164

LeetCode 算法:无重复字符的最长子串c++

LeetCode 算法:无重复字符的最长子串c++

世界那么大,我想去看看~【随心更新,看世界去了😄】 1638

最长无重复字串

对应letecode链接: https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/ 题目描述: 给定一个字符串 s ,请你找出其中不含有重复字符的最长子串的长度。 示例1: 输入: s = "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 示例 2: 输入: s = "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串...

qq_56999918的博客 1477

LeetCode(3)——最长不重复子串

题目内容 描述 给定一个字符串,找出不含有重复字符的最长子串的长度。 示例: 给定 “abcabcbb” ,没有重复字符的最长子串是 “abc” ,那么长度就是3。 给定 “bbbbb” ,最长的子串就是 “b” ,长度是1。 给定 “pwwkew” ,最长子串是 “wke” ,长度是3。请注意答案必须是一个子串,”pwke” 是 子序列 而不是子串。 思路 1——...

Andy的博客 2万+
上一篇: 最字头之三:最长重复子串
下一篇: Java中equal和"=="的区别
louis9212
博客等级 码龄14年 8粉丝 49原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值