【字符串】【分类讨论】【KMP】1163. 按字典序排在最后的子串

news2024/11/16 19:29:30

作者推荐

视频算法专题

本文涉及知识点

字符串 字典序 分类讨论
本题无法使用KMP,因为t1不段变化。

LeetCode1163. 按字典序排在最后的子串

给你一个字符串 s ,找出它的所有子串并按字典序排列,返回排在最后的那个子串。
示例 1:
输入:s = “abab”
输出:“bab”
解释:我们可以找出 7 个子串 [“a”, “ab”, “aba”, “abab”, “b”, “ba”, “bab”]。按字典序排在最后的子串是 “bab”。
示例 2:
输入:s = “leetcode”
输出:“tcode”
提示:
1 <= s.length <= 4 * 105
s 仅含有小写英文字符。

KMP

令s[0,i)的最后子串是t1,s[0,i]的最后子串t2。则t2一定以s[i],结尾,因为t1+s[i]一定在t1后面。
{ 从 t 1 取 0 个字符, t 2 = s [ i ] s [ i ] > t [ 0 ] 从 t 1 取后 m 个字符 t [ i − m , i ) + s [ i ] 条件下面详述 \begin{cases} 从t1取0个字符,t2 = s[i] & s[i] > t[0] \\ 从t1取后m个字符 t[i-m,i)+s[i] &条件下面详述\\ \end{cases} {t10个字符,t2=s[i]t1取后m个字符t[im,i)+s[i]s[i]>t[0]条件下面详述
t1[0,m) 不会小于 t[i-m,i),否则t1就是t[n-m,m)。
如果两种是大于关系,则t1[0,m]大于 t[i-m,i)+s[i] ,不成立。
故一定是相等关系,且t1[m]小于s[i]。
可以利用KMP的公共前后缀。
如果以上情况都不符合,则t2 = t1 + s[i]。
如果使用KMP,t1不断变化,时间复杂度是O(nn),超时。

分类讨论

令n = s.length()。
性质一:令s[x,y)是最后的子串,x ∈ \in [0,n)则y=n。因为s[x,n)的字典序比s[x,y)大。
性质二:令s[i,n)在s[x,n)中的字典序最大,x ∈ \in [0,j)。确保:j > i。
令s[i,i+k)和s[j,j+k)相等,下标 j+K非法, s[i+k]!=s[j+k]。初始:i=0,j=1,k=0
{ k + + s [ i + k ] = = s [ j + k ] k = 0 , i = j , j + + s [ i + k ] < s [ j + k ] 待证明一 k = 0 , i + = k + 1 s [ i + k ] > s [ j + k ] 待证明二 \begin{cases} k++ & s[i+k]==s[j+k] \\ k=0,i=j,j++& s[i+k] < s[j+k] & 待证明一\\ k=0,i+= k+1 & s[i+k] > s[j+k] & 待证明二\\ \end{cases} k++k=0,i=j,j++k=0,i+=k+1s[i+k]==s[j+k]s[i+k]<s[j+k]s[i+k]>s[j+k]待证明一待证明二

待证明一

显然s[j,n)的字典序大于s[i,n)结合性质二,s[j,n)是 s[x,n)中的最大字典序,x ∈ \in [0,j+1)。

待证明二

令x ∈ \in [j,j+k] ,则len = x - j+1 。
s[x,n)的字典序小于s[i+len,n),结合性质二,s[i+len,n)小于s[i],s[x,n)小于s[i,n)。现在来证明无后效性:
从小到处理len,则:
s[0,j+len)符合性质二,由于s[0,i+len]符合性质二。

超时

多余n-1个a,后面跟一个b。时间复杂度O(nn)。

代码

核心代码

class Solution {
public:
	string lastSubstring(string s) {
		int i = 0;
		for (int j = 1; j < s.length(); )
		{
			int k = 0;
			for (; ((j + k) < s.length()) && (s[j + k] == s[i + k]); k++);
			int tmp = i;
			if (s[i + k] < s[j + k])
			{
				i = j++;
			}
			else
			{
				j += k + 1;
			}			
		}
		return s.substr(i);
	}
};

测试用例

template<class T,class T2>
void Assert(const T& t1, const T2& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}

}

int main()
{
	string s ;
	{
		Solution sln;
		s = "cacacb";
		auto res = sln.lastSubstring(s);
		Assert("cb", res);
	}
	{
		Solution sln;
		s = "abab";
		auto res = sln.lastSubstring(s);
		Assert("bab", res);
	}

	{
		Solution sln;
		s = "leetcode";
		auto res = sln.lastSubstring(s);
		Assert("tcode", res);
	}
	
}

优化

极端情况下,i=j++,执行了n次,k也为n。故时间复杂度为O(nn)。
分两种情况:
一,i+k <= j 不变。
二,i+k > j。下面具体分析:
令m = j-i。
将s[j,j+k)和s[i,i+k)分成若干块,最后一块长度为k%m,前面的块长度都为m,则:
s[j,j+k)的各块分别为:s[j,i) s[i,i+m) s[i+m,i+m2) ⋯ \cdots
s[i,i+k)的个块分别为:s[i,i+m) s[i+m,i+m
2) ⋯ \cdots
→ \rightarrow s[j,i) == s [i,i+m) == s[i+m,i+m*2) ⋯ \cdots
显然s[j,n)淘汰了s[i,n)
x$\in[0,m)
s[j,n)能够淘汰s[j+n,n) 因为s[i,n)删除前m个字符,s[i+x,n)删除就是两者。
同理:s[j+m,n)能淘汰s[j]和s[j+m+x,n)。
⋮ \vdots
故 i =j + k - (k%m)    ⟺    \iff i+m+k - (k%m)
因为 m > k%m ,所以 i+m+k - (k%m) > i+ k,也就i至少增加k。
无论什么情况:
i或j至少有一个至少增加k,故总时间复杂度是O(n)。

代码

class Solution {
public:
	string lastSubstring(string s) {
		int i = 0;
		for (int j = 1; j < s.length(); )
		{
			int k = 0;
			for (; ((j + k) < s.length()) && (s[j + k] == s[i + k]); k++);
			int tmp = i;
			if (s[i + k] < s[j + k])
			{
				const int m = j - i;
				if (k > m)
				{
					i = (j + k - k%m);
					j = i + 1;
				}
				else
				{
					i = j++;
				}
			}
			else
			{
				j += k + 1;
			}			
		}
		return s.substr(i);
	}
};

2023年5月版

class Solution {
public:
string lastSubstring(string s) {
int iMaxIndex = 0;
for (int i = 1; i < s.length(); i++)
{
int k = 0;
for (; (i + k < s.length()) && (s[i + k] == s[iMaxIndex + k]); k++)
{
}
if ((i + k < s.length()) && (s[i + k] > s[iMaxIndex + k]))
{
auto tmp = iMaxIndex;
iMaxIndex = i;
i = max(i,tmp+k);
}
else
{
i = i + k ;
}
}
return s.substr(iMaxIndex);
}
};

2024年2月版

class Solution {
public:
string lastSubstring(string s) {
int i = 0;
for (int j = 1; j < s.length(); )
{
int k = 0;
for (; ((j + k) < s.length()) && (s[j + k] == s[i + k]); k++);
int tmp = i;
if (s[i + k] < s[j + k])
{
const int m = j - i;
if (k > m)
{
i += k+1;
j = i + 1;
}
else
{
i = j++;
}
}
else
{
j += k + 1;
}
}
return s.substr(i);
}
};

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1502155.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于华为昇腾(Ascend)AI芯片,CANN计算架构,MindSpore深度学习框架,MindStudio开发工具

1、华为昇腾生态 深度学习之前的配置都是&#xff1a;NVIDIA GPU / CPU CUDA Tensorflow/PyTorch 后来老美禁止 NVIDIA 卖GPU芯片给我们&#xff0c;于是国内企业开始发力CPU和GPU硬件&#xff0c;成果丰硕&#xff0c;虽然与NVIDIA顶级GPU还有一些差距&#xff0c;但是也不…

网络故障基本判断方法

1&#xff09;电脑上使用winR键&#xff0c;打开运行窗口&#xff0c;输入CMD命令&#xff0c;点击回车键 2&#xff09;在弹出的CMD运行窗口中输入ipconfig命令 通过该命令可以查看本机的IP地址&#xff0c;子网掩码和网关等信息。确认电脑中所有网卡配置是否正确。 3&…

有点炫酷有点diao的免费wordpress模板主题

这是一款经典的免费wordpress主题&#xff0c;被广泛应用于多个行业的网站。 https://www.wpniu.com/themes/189.html

【linux】04 :linix实用操作

1.常用快捷键 ctrlc表示强制停止。linux某些程序的运行&#xff0c;如果想强制停止&#xff0c;可以使用&#xff1b;命令输入错误&#xff0c;也可以通过ctrlc,退出当前输入&#xff0c;重新输入。 ctrld表示退出登录&#xff0c;比如退出root以回到普通用户&#xff0c;或者…

visual studio 将编译后的dll等文件自动复制到指定目录

编译后的文件dll等总要手动复制到指定目录下&#xff0c;为了解决这一繁琐的操作&#xff0c;可以直接设置在编译完成后&#xff0c;自动复制到目标目录 - 在解决方案资源管理器&#xff0c;选中项目右键-》选中属性-》在弹出的面板选择生成事件 - 在后期生成事件命令行里填写…

IOS降级后从高版本到低版本恢复备份

IOS降级后从高版本到低版本恢复备份 此方法只适用于小版本还原&#xff0c;比如17.4->17.3&#xff0c;未验证大版本恢复可行性手机型号&#xff1a;iphone 13pro 系统版本&#xff1a;17.4 降级版本&#xff1a;17.3.1 步骤 通过itunes或者MacOS系统下对当前版本进行备份…

React-useEffect

1.概念 说明&#xff1a;用于在React组件中创建不是由事件引起而是由渲染本身引起的操作&#xff0c;比如发送 A列AX请求&#xff0c;更改DOM等。 2.案例 // useEffect用于组件不是由事件引起的而是由渲染本身引起的操作&#xff0c;如ajax,更改Dom等。 import { useEffect,…

【MapReduce】03.MapReduce框架原理

目录 1.InputFormat数据输入 1.1.切片与MapTask并行度决定机制 1.2.Job提交流程源码和切片源码 1.3.FileInputFormat切片机制 1.4.TextInputFormat 1.5.CombineTextInputFormat切片机制 1.6.CombineTextInputFormat 1.InputFormat数据输入 1.1.切片与MapTask并行度决定…

小白跟做江科大51单片机之AD/DA

1.看原理图找接口 2.看时序图编写读取数据代码 XPT2046.c代码 #include <REGX52.H> //引脚定义 sbit XPY2046_DINP3^4; sbit XPY2046_CSP3^5; sbit XPY2046_DCLKP3^6; sbit XPY2046_DOUTP3^7; unsigned int XPT2046_ReadAD(unsigned char Command) { unsigned char …

基于SSM的党务政务服务热线平台(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的党务政务服务热线平台&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spri…

Windows®、Linux® 和 UNIX® 系统都适用的远程桌面工具 OpenText ETX

Windows、Linux 和 UNIX 系统都适用的远程桌面工具 OpenText ETX 为 Windows、Linux 和 UNIX 实施精益、经济高效的虚拟化&#xff1b;提供完整的远程 Windows 可用性&#xff1b;以类似本地的性能远程工作&#xff1b;安全地保护系统和知识产权&#xff08;IP&#xff09;&am…

landsat遥感卫星地表温度LST计算教程

地表温度反演算法主要有以下三种&#xff1a;大气校正法&#xff08;也称为辐射传输方程&#xff1a;Radiative Transfer Equation——RTE&#xff09;、单通道算法和分裂窗算法。 大气校正法基本原理&#xff1a;首先估计大气对地表热辐射的影响, 然后把这部分大气影响从卫星传…

MySQL实战:SQL优化及问题排查

有更合适的索引不走&#xff0c;怎么办&#xff1f; MySQL在选取索引时&#xff0c;会参考索引的基数&#xff0c;基数是MySQL估算的&#xff0c;反映这个字段有多少种取值&#xff0c;估算的策略为选取几个页算出取值的平均值&#xff0c;再乘以页数&#xff0c;即为基数 查…

24V 36V 48V 60V 72V 转3.3V 5V动态响应好 惠海H62410A模块供电解决方案

H62410A是一种内置100V耐压MOS&#xff0c;支持输入高达90V的高压降压开关控制器&#xff0c;可以向负载提供1A的连续电流。H62410A支持输出恒定电压&#xff0c;可以通过调节VFB采样电阻来设置输出电压&#xff0c;同时支持最大电流限制&#xff0c;可以通过修改CS采样电阻来设…

线下活动线上同步直播?媒体同步直播的好处

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 线下活动线上同步直播&#xff0c;即利用互联网技术将线下活动的实时内容传输到线上平台&#xff0c;供无法到场的观众在线观看。这种直播方式的好处主要体现在以下几个方面&#xff1a;…

自动驾驶技术解析与关键步骤

目录 前言1 自动驾驶主要技术流程1.1 车辆周围环境感知1.2 车辆和行人检测分析1.3 运动轨迹规划 2 关键技术概述2.1 车辆探测与图片输入2.2 行人检测2.3 运动规划2.4 电子地图2.5 轨迹预测2.6 交通灯分析2.7 故障检测 结语 前言 自动驾驶汽车作为未来交通领域的重要发展方向&a…

13:大数据与Hadoop|分布式文件系统|分布式Hadoop集群

大数据与Hadoop&#xff5c;分布式文件系统&#xff5c;分布式Hadoop集群 Hadoop部署Hadoop HDFS分布式文件系统HDFS部署步骤一&#xff1a;环境准备HDFS配置文件 查官方手册配置Hadoop集群 日志与排错 mapreduce 分布式离线计算框架YARN集群资源管理系统步骤一&#xff1a;安装…

【吊打面试官系列】Java虚拟机JVM篇 - 关于类加载器的JVM面试题

大家好&#xff0c;我是锋哥。今天分享关于类加载器的JVM面试题&#xff0c;希望对大家有帮助&#xff1b; 什么是类加载器&#xff1f; 类加载器是一个用来加载类文件的类。Java源代码通过javac编译器编译成类文件。然后JVM来执行类文件中的字节码来执行程序。类加载器负责加…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《考虑多能互补灵活性和用户低碳意愿的区域综合能源系统鲁棒优化调度》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

git - 笔记

为什么要学习Git 为什么要学习Git软件 为什么学习 因为在主流开发中&#xff0c;基于互联网软件开发的项目都会使用Git软件来进行项目开发过程中的资源管理 比如人力资源 代码资源 比如前端资源 .html .java等代码资源 文档资源 像项目开发中涉及到的需求文档等 这种项目中管理…