(新卷,100分)- 关联子串(Java JS Python C)

(新卷,100分)- 关联子串(Java & JS & Python & C)

题目描述

给定两个字符串str1和str2,如果字符串str1中的字符,经过排列组合后的字符串中,只要有一个字符串是str2的子串,则认为str1是str2的关联子串。

若str1是str2的关联子串,请返回子串在str2的起始位置;

若不是关联子串,则返回-1。

输入描述

输入两个字符串,分别为题目中描述的str1、str2。

输出描述

若str1是str2的关联子串,请返回子串在str2的起始位置;

若不是关联子串,则返回-1。

若str2中有多个str1的组合子串,请返回最小的起始位置。

备注
  • 输入的字符串只包含小写字母;
  • 两个字符串的长度范围[1, 100000]之间;
用例
输入abc efghicbaiii
输出5
说明str2包含str1的一种排列组合("cab"),此组合在str2的字符串起始位置为5(从0开始计数)
输入abc efghiccaiii
输出-1
说明“abc”字符串中三个字母的各种组合(abc、acb、bac、bca、cab、cba),str2中均不包含,因此返回-1
题目解析

本题看上去是要求解全排列,但是题目描述数量级为:两个字符串的长度范围[1, 100000]之间;

因此str1的全排列肯定会超时。

本题可以使用尺取法来求解,尺取法其实就是高级一点的滑动窗口,常用于解决最小覆盖子串问题

大家可以认真看下上面这个博客,对尺取法有个大致了解。

尺取法,通常是有一个子串str1,和一个父串str2,我们需要在父串str2中找到包含str1子串所有字符的目标串target,不在意字符顺序。

解决方案很固定:

预处理动作:

  • 统计出子串str1中各字符的数量,记录到count中,这里的count容器通常选择128长度的数组,因为字符串中的字符通常都是ASCII码表的字符,而ASCII码只有128个,因此选择128长度的数组就可以涵盖到所有字符。
  • 定义一个total变量,来记录str1字符的总数(即str1的长度)

滑窗动作:

  • 初始滑窗,即父串str2的0~str1.length-1范围的滑窗。此时滑窗只有新增字符的过程,即滑窗左边界保持在0,而滑窗右边界从0运动到str1.length-1位置。
  • 后续滑窗,即父串str2的 i ~ i + str1.length - 1,其中 i >= 1,每次滑窗整体向右移动一格,即相较于上一个滑窗,会失去 str2[i-1]字符,以及新增 str2[i + str1.length - 1] 字符。

滑窗的意义:

  • 滑窗其实就是一个str2的子串,我们可以基于滑窗来统计滑窗内子串各字符的数量,如果滑窗内各字符的数量与str1各字符数量一致,则说明滑窗内子串就是一个目标子串

滑窗处理新增字符:

  • 当滑窗新增一个字符c时,我们应该count[c] -= 1,表示滑窗子串和str1的差别缩小了,此时total是否也需要-=1吗?total是str1的字符总数,此时需要细化讨论
  1. 如果字符c不是str1内的字符,则total不需要-=1
  2. 如果字符c是str1内的字符,此时又需要细化讨论,字符c虽然是str1内的字符,但是滑窗内c字符的数量完全有可能超过str1内的字符数量,即滑窗内存在多余的字符c,那么此时滑窗新增了一个c,并不会缩小和str1的差距,即total不需要-=1。

那么此时就需要搞清楚,如何判断滑窗内字符c是否是str1的字符?以及是str1字符的情况下,是否为超标字符?

上面两个判断,可以用一句话实现:count[c] > 0

  • 如果滑窗新增的字符c不是str1字符,则必然count[c] <= 0
  • 如果滑窗新增的字符c是str1字符,但是超标了,则经过count[c]--动作,超过的c字符,必然count[c] <= 0

滑窗处理移除字符:

当滑窗移除一个字符c是,我们应该count[c]++,表示滑窗子串和str1的差别扩大了,此时total是否也需要+=1吗?total是str1的字符总数,此时需要细化讨论:

  • 如果字符c不是str1内的字符,则total不需要+=1
  • 如果字符c是str1内的字符,此时又需要细化讨论,字符c虽然是str1内的字符,但是滑窗内c字符的数量完全有可能超过str1内的字符数量,即滑窗内存在多余的字符c,那么此时滑窗移除一个c,并不会扩大和str1的差距,即不需要total+=1

那么此时就需要搞清楚,如何判断滑窗内字符c是否是str1的字符?以及是str1字符的情况下,是否为超标字符?

上面两个判断,可以用一句话实现:count[c]>=0

  • 如果滑窗移除的字符c不是str1字符,则移除之前必然count[c] < 0
  • 如果滑窗移除的字符c是str1字符,但是超标了,则移除之前必然count[c] < 0
Java算法源码
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String str1 = sc.next(); String str2 = sc.next(); System.out.println(getResult(str1, str2)); } public static int getResult(String str1, String str2) { // count用于统计str1中各字符的数量 int[] count = new int[128]; for (int i = 0; i < str1.length(); i++) { char c = str1.charAt(i); count[c]++; } // total统计str1总共字符个数 int total = str1.length(); // 初始滑窗,滑窗范围内容,就是一个子串 for (int i = 0; i < str1.length(); i++) { // 滑窗子串新增的字符 char add = str2.charAt(i); // 如果新增字符是str1的字符,即count[add] > 0时,则说明滑窗子串已找到一个目标字符,此时剩余add字符数量count[add]--,剩余目标字符总数total-- if (count[add]-- > 0) { total--; } } // 如果total == 0,则说明滑窗内所有字符都是str1内的字符,由于限定了滑窗的长度就是str1的长度,因此滑窗内字符和str1完全匹配 if (total == 0) return 0; // 下一个滑窗范围是 i ~ i + str1.length() - 1 for (int i = 1; i + str1.length() - 1 < str2.length(); i++) { // 相较于上一个滑窗失去的字符remove char remove = str2.charAt(i - 1); // 相较于上一个滑窗新增的字符add char add = str2.charAt(i + str1.length() - 1); // 本轮滑窗remove字符,在上一轮是被add的字符,我们假设此字符为c,此时可以分两种情况讨论: // 1、c是str1的字符,则初始统计时count[c]>0,上一轮滑窗加入c字符,则count[c]--,此轮count[c]是有可能>=0或者<0的, // 1.1、如果本轮count[c]>=0,则说明上轮滑窗并没有找到所有的c字符,因此本轮移除的c字符可以还原total数量 // // 1.2、如果本轮count[c]<0,这说明上轮滑窗内的c字符超标了,即c字符是目标字符,但是滑窗内包含的c字符数量超过了str1中c字符的数量,因此本轮移除c字符是超标部分,不会还原total // 2、c不是str1的字符,则初始统计时count[c]==0,上一轮滑窗加入c字符,则count[c]--,此轮必然count[c]<0,因此c字符的移除,并不会还原total if (count[remove]++ >= 0) { total++; } if (count[add]-- > 0) { total--; } if (total == 0) { return i; } } return -1; } }
JS算法源码
/* JavaScript Node ACM模式 控制台输入获取 */ const readline = require("readline"); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); rl.on("line", (line) => { let [str1, str2] = line.split(" "); console.log(getResult(str1, str2)); }); function getResult(str1, str2) { // count用于统计str1中各字符的数量 const count = {}; for (let i = 0; i < str1.length; i++) { const c = str1[i]; count[c] = (count[c] ?? 0) + 1; } // total统计str1总共字符个数 let total = str1.length; // 初始滑窗,滑窗范围内容,就是一个子串 for (let i = 0; i < str1.length; i++) { // 滑窗子串新增的字符 const add = str2[i]; // 如果新增字符是str1的字符,即count[add] > 0时,则说明滑窗子串已找到一个目标字符,此时剩余add字符数量count[add]--,剩余目标字符总数total-- if (count[add]-- > 0) { total--; } } // 如果total == 0,则说明滑窗内所有字符都是str1内的字符,由于限定了滑窗的长度就是str1的长度,因此滑窗内字符和str1完全匹配 if (total == 0) return 0; // 下一个滑窗范围是 i ~ i + str1.length() - 1 for (let i = 1; i + str1.length - 1 < str2.length; i++) { // 相较于上一个滑窗失去的字符remove const remove = str2[i - 1]; // 相较于上一个滑窗新增的字符add const add = str2[i + str1.length - 1]; // 本轮滑窗remove字符,在上一轮是被add的字符,我们假设此字符为c,此时可以分两种情况讨论: // 1、c是str1的字符,则初始统计时count[c]>0,上一轮滑窗加入c字符,则count[c]--,此轮count[c]是有可能>=0或者<0的, // 1.1、如果本轮count[c]>=0,则说明上轮滑窗并没有找到所有的c字符,因此本轮移除的c字符可以还原total数量 // 1.2、如果本轮count[c]<0,这说明上轮滑窗内的c字符超标了,即c字符是目标字符,但是滑窗内包含的c字符数量超过了str1中c字符的数量,因此本轮移除c字符是超标部分,不会还原total // 2、c不是str1的字符,则初始统计时count[c]==0,上一轮滑窗加入c字符,则count[c]--,此轮必然count[c]<0,因此c字符的移除,并不会还原total if (count[remove]++ >= 0) { total++; } if (count[add]-- > 0) { total--; } if (total == 0) return i; } return -1; }
Python算法源码
# 输入获取 str1, str2 = input().split() # 算法入口 def getResult(): # count用于统计str1中各字符的数量 count = {} for c in str1: count[c] = count.get(c, 0) + 1 # total统计str1总共字符个数 total = len(str1) # 初始滑窗,滑窗范围内容,就是一个子串 for i in range(len(str1)): # 滑窗子串新增的字符 add = str2[i] # 如果新增字符是str1的字符,即count[add] > 0时,则说明滑窗子串已找到一个目标字符,此时剩余add字符数量count[add]--,剩余目标字符总数total-- if count.get(add) is not None: if count[add] > 0: total -= 1 count[add] -= 1 # 如果total == 0,则说明滑窗内所有字符都是str1内的字符,由于限定了滑窗的长度就是str1的长度,因此滑窗内字符和str1完全匹配 if total == 0: return 0 # 下一个滑窗范围是 i ~ i + str1.length() - 1 for i in range(1, len(str2) - len(str1) + 1): # 相较于上一个滑窗失去的字符remove remove = str2[i-1] # 相较于上一个滑窗新增的字符add add = str2[i + len(str1) - 1] # 本轮滑窗remove字符,在上一轮是被add的字符,我们假设此字符为c: # 1、c是str1的字符,则初始统计时count[c]>0,上一轮滑窗加入c字符,则count[c]--,此轮count[c]是有可能>=0或者<0的, # 1.1、如果本轮count[c]>=0,则说明上轮滑窗并没有找到所有的c字符,因此本轮移除的c字符可以还原total数量 # 1.2、如果本轮count[c]<0,这说明上轮滑窗内的c字符超标了,即c字符是目标字符,但是滑窗内包含的c字符数量超过了str1中c字符的数量,因此本轮移除c字符是超标部分,不会还原total if count.get(remove) is not None: if count[remove] >= 0: total += 1 count[remove] += 1 if count.get(add) is not None: if count[add] > 0: total -= 1 count[add] -= 1 if total == 0: return i return -1 # 算法调用 print(getResult())
C算法源码
#include <stdio.h> #include <string.h> #define MAX_LEN 100000 int getResult(char *str1, char *str2); int main() { char str1[MAX_LEN], str2[MAX_LEN]; scanf("%s %s", str1, str2); printf("%d\n", getResult(str1, str2)); return 0; } int getResult(char *str1, char *str2) { // count用于统计str1中各字符的数量 int count[128] = {0}; for (int i = 0; i < strlen(str1); i++) { char c = str1[i]; count[c]++; } // total统计str1总共字符个数 int total = strlen(str1); // 初始滑窗,滑窗范围内容,就是一个子串 for (int i = 0; i < strlen(str1); i++) { // 滑窗子串新增的字符 char add = str2[i]; // 如果新增字符是str1的字符,即count[add] > 0时,则说明滑窗子串已找到一个目标字符,此时剩余add字符数量count[add]--,剩余目标字符总数total-- if (count[add]-- > 0) { total--; } } // 如果total == 0,则说明滑窗内所有字符都是str1内的字符,由于限定了滑窗的长度就是str1的长度,因此滑窗内字符和str1完全匹配 if (total == 0) return 0; // 下一个滑窗范围是 i ~ i + str1.length() - 1 for (int i = 1; i + strlen(str1) - 1 < strlen(str2); i++) { // 相较于上一个滑窗失去的字符remove char remove = str2[i - 1]; // 相较于上一个滑窗新增的字符add char add = str2[i + strlen(str1) - 1]; // 本轮滑窗remove字符,在上一轮是被add的字符,我们假设此字符为c,此时可以分两种情况讨论: // 1、c是str1的字符,则初始统计时count[c]>0,上一轮滑窗加入c字符,则count[c]--,此轮count[c]是有可能>=0或者<0的, // 1.1、如果本轮count[c]>=0,则说明上轮滑窗并没有找到所有的c字符,因此本轮移除的c字符可以还原total数量 // // 1.2、如果本轮count[c]<0,这说明上轮滑窗内的c字符超标了,即c字符是目标字符,但是滑窗内包含的c字符数量超过了str1中c字符的数量,因此本轮移除c字符是超标部分,不会还原total // 2、c不是str1的字符,则初始统计时count[c]==0,上一轮滑窗加入c字符,则count[c]--,此轮必然count[c]<0,因此c字符的移除,并不会还原total if (count[remove]++ >= 0) { total++; } if (count[add]-- > 0) { total--; } if (total == 0) { return i; } } return -1; }

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

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

相关文章

Java毕设选题推荐:基于SpringBoot+Vue的体育赛事视频管理系统的设计与实现基于Springboot的体育赛事视频管理系统【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

Python flask django公司人力资源管理系统

目录Python Flask/Django 公司人力资源管理系统摘要关于博主开发技术路线相关技术介绍核心代码参考示例结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;Python Flask/Django 公司人力资源管理系统摘要 现代企业人力资源管理&#xff…

(新卷,100分)- 喊7的次数重排(Java JS Python)

(新卷,100分)- 喊7的次数重排&#xff08;Java & JS & Python&#xff09;题目描述喊7是一个传统的聚会游戏&#xff0c;N个人围成一圈&#xff0c;按顺时针从1到N编号。编号为1的人从1开始喊数&#xff0c;下一个人喊的数字为上一个人的数字加1&#xff0c;但是当将要…

大数据领域MongoDB的集群搭建与管理指南

MongoDB集群从0到1&#xff1a;搭建、优化与管理实战指南 引言 你是否遇到过这样的痛点&#xff1f; 单机MongoDB存储快满了&#xff0c;加硬盘却发现性能瓶颈越来越明显&#xff1b;peak时段查询延迟飙升&#xff0c;用户投诉“页面加载慢”&#xff1b;某次服务器宕机&#x…

一道题看穿位运算功力:只出现一次的数字 III

一道题看穿位运算功力: ##《只出现一次的数字 III》到底在考你什么? 我是 Echo_Wish。 说实话,Single Number III 这道题,我第一次刷的时候,内心是有点不服的。 不是因为难,而是因为—— 解法太“不像常规算法”了。 你如果用: HashMap 排序 统计次数 都能做,但题目…

(新卷,100分)- 恢复数字序列(Java JS Python)

(新卷,100分)- 恢复数字序列&#xff08;Java & JS & Python&#xff09;题目描述对于一个连续正整数组成的序列&#xff0c;可以将其拼接成一个字符串&#xff0c;再将字符串里的部分字符打乱顺序。如序列8 9 10 11 12&#xff0c;拼接成的字符串为89101112&#xff0…

配电网故障重构+智能算法Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书和数学建模资料 &#x1…

Java毕设选题推荐:基于SpringBoot+Vue的旅游管理系统门票购买、酒店信息、房间预订、行程工具等功能【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

【双层模型】分布式光伏储能系统的优化配置方法Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书和数学建模资料 &#x1…

基于GA_BFGS算法的配电网故障恢复性重构研究附Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书和数学建模资料 &#x1…

从零开始掌握消息队列

前言在当今的分布式系统架构中&#xff0c;消息队列已经成为不可或缺的核心组件。Apache Kafka作为一款高吞吐量、低延迟的分布式消息系统&#xff0c;被广泛应用于大数据处理、日志收集、流式处理等场景。一、Kafka是什么&#xff1f;Apache Kafka是一个分布式流处理平台&…

计算机毕设 java 基于智能推荐的宠物之家网站设计与实现 Java 智能推荐宠物服务平台设计与开发 基于 Java 的宠物之家智能推荐系统研发

计算机毕设 java 基于智能推荐的宠物之家网站设计与实现 f48cc9&#xff08;配套有源码 程序 mysql 数据库 论文&#xff09;本套源码可以先看具体功能演示视频领取&#xff0c;文末有联 xi 可分享随着互联网科技的进步和人们生活水平的提高&#xff0c;宠物数量快速增加&#…

大数据运营中的常见陷阱与规避策略:资深专家经验分享

大数据运营中的常见陷阱与规避策略&#xff1a;资深专家经验分享关键词&#xff1a;大数据运营、数据质量、业务目标脱节、模型偏差、数据安全、陷阱规避、实战策略摘要&#xff1a;大数据运营已成为企业数字化转型的核心引擎&#xff0c;但许多团队在实际落地中常陷入“数据越…

【毕业设计】基于Springboot的体育赛事视频管理系统(源码+文档+远程调试,全bao定制等)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

绿色AI:降低环境影响的计算策略

绿色AI:降低环境影响的计算策略 关键词:绿色AI、环境影响、计算策略、节能算法、可持续发展 摘要:本文聚焦于绿色AI领域,旨在探讨降低人工智能计算对环境影响的有效策略。随着AI技术的迅猛发展,其高能耗问题日益凸显,对环境造成了一定压力。文章首先介绍了绿色AI的背景,包…

基于改进下垂控制的微电网控制研究Simulink实现

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书和数学建模资料 &#x1…

基于非对称纳什谈判的多微网电能共享运行优化策略Matlab实现

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书和数学建模资料 &#x1…

配电网多目标pareto重构+智能算法Matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;擅长数据处理、建模仿真、程序设计、完整代码获取、论文复现及科研仿真。 &#x1f34e; 往期回顾关注个人主页&#xff1a;Matlab科研工作室 &#x1f447; 关注我领取海量matlab电子书和数学建模资料 &#x1…

手把手教 - 单片机 MQTTS 协议通信测试

一、介绍 开发板:STM32F407 rt-thread版本:4.1.0 二、工程配置 2.1 以太网配置 2.2 rtc 时钟开启 2.3 软件包配置 MQTT 依赖包 - pahomqtt,版本:1.2.0 。启动 TLS 需设置 MQTT 线程栈大小 ≥ 6144 配置 mbedtls,版本:2.28.1 。必须增加帧长度。 无证书 SSL 连接(单…

特价股票与公司现金流管理效率的关系

特价股票与公司现金流管理效率的关系关键词&#xff1a;特价股票、公司现金流管理效率、财务分析、投资决策、市场估值摘要&#xff1a;本文旨在深入探讨特价股票与公司现金流管理效率之间的内在联系。通过对相关核心概念的阐述、算法原理的剖析、数学模型的构建以及实际案例的…