【公司】最长子串问题-双指针解法

该博客介绍了在面对复杂产品业务时,如何处理用户程序与底层模块交互的问题。具体是一个底层模块接收到多个命令,需要找出最长的没有重复的命令序列。博主提出了双指针的方法来解决这个问题,并给出了两种不同的解决方案:一种是自己的解法,另一种是更高效的大佬解法。代码示例展示了如何找到最长不重复子串,对于信息技术领域的算法设计和实现具有参考价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

@TOC

题目描述

产品业务较复杂时,用户程序在实现某一个特定功能时,往往需要与底层模块进行多次交互,然后组合获取的底层结果,最终完成用户功能。

实际上,一个底层模块,由于自身框架设计等原因,导致对外协议接口使用上会存在很多限制,用户程序需要严格根据底层模块的协议来进行交互。

假设存在底层模块,对外提供n种不同交互命令X,编号依次为X1,…,Xn,互不相等,

模块具有如下限制:模块先对接收到的命令进行过滤,提取序列中最长的没有重复的命令序列,如n=7,应用下发命令序列如下:

X1 X2 X3 X1 X5 X4 X2 X5 X7 X6 X1 X3 X2 X3

因此该序列中,最长的没有重复有效命令序列为 X4 X2 X5 X7 X6 X1 X3 ,即最多命令数为 7

简化上述过程,求解出 应用有效命令序列中最多命令数?

解析

题目大概就是求最长不重复子串(子串:原序列中必须连续的一段;子序列:原序列中可以不连续的一段),我这里采用的方法是双指针

https://ask.qcloudimg.com/http-save/yehe-8271427/f89b5fef965534bbe79b87bdc7cced71.png?imageView2/2/w/1620
https://ask.qcloudimg.com/http-save/yehe-8271427/c22f22b74c3de9aa916e53e5edbee783.png?imageView2/2/w/1620
https://ask.qcloudimg.com/http-save/yehe-8271427/327b2aa05c7ba564af493ded610a537b.png?imageView2/2/w/1620
https://ask.qcloudimg.com/http-save/yehe-8271427/0b810aeb48d8ab236cfa61be56b277a7.png?imageView2/2/w/1620
https://ask.qcloudimg.com/http-save/yehe-8271427/281e3e856ce039032172e904ebe462a0.png?imageView2/2/w/1620
https://ask.qcloudimg.com/http-save/yehe-8271427/2e39d2018f01d93a6bf4521356dd86b5.png?imageView2/2/w/1620

// 本蒟蒻的解法
#include <iostream>
#include <stdio.h>
#include <algorithm>

using namespace std;

int N;
// 公司题目里面没说n的取值范围
int arr[10010];
int main(){
    scanf("%d",&N);
    for(int i=0;i<N;i++) {
        scanf("%d",&arr[i]);
    }
    // s表示头指针,e表示尾指针,l记录结果
    int s=0,l=1;
    for(int e=0; e<N; e++) {
        for(int j=s; j<e; j++) {
            if(arr[j] == arr[e]){
                s = j+1;
            }
        }
        l = max(l, e-s+1);
    }
    printf("%d\n", l);
}
// 大佬的解法Orz
# include <iostream>
#include <stdio.h>

using namespace std;

int arr[100010], s[100010];
int N;

int main(){
    int l=1;
    scanf("%d", &N);
    for (int i=0,j=0; i<N; i++){
        scanf("%d",&arr[i]);
        ++ s[arr[i]];
        while (s[arr[i]] > 1) -- s[arr[j++]];
        l = max(l, i-j+1);
    }
    printf("%d\n",l);
    return 0;
}
### 滑动窗口算法解决无重复字符的最长子串问题 滑动窗口是一种常用的优化技术,用于处理数组或字符中的连续子集问题。在本题中,目标是找到一个字符中没有重复字符的最长子串的长度。相比于暴力解法的时间复杂度 $O(n^2)$,滑动窗口可以将时间复杂度降低到 $O(n)$,从而显著提升效率。 #### 核心思想 滑动窗口通过两个指针(通常称为 `left` 和 `right`)来维护一个窗口,该窗口内不包含重复字符。当 `right` 指针向右移动时,检查当前字符是否已经存在于窗口中。如果存在,则调整 `left` 指针的位置,以确保窗口内的字符始终唯一[^3]。 #### 算法步骤 1. 初始化两个指针 `left` 和 `right`,分别表示窗口的左右边界。 2. 使用哈希表或者数组记录每个字符是否出现在当前窗口中。例如,使用长度为 128 的整型数组 `num` 来存储 ASCII 字符的出现状态,其中 `num[char] == 1` 表示该字符已经在窗口中出现过,`num[char] == 0` 表示未出现[^4]。 3. 当 `right` 指针指向的字符不在窗口中时,将其标记为已出现,并更新窗口的大长度。 4. 如果 `right` 指针指向的字符已经存在,则移动 `left` 指针,直到窗口中不再包含重复字符。 5. 在每一步操作后,更新子串长度。 #### 时间与空间复杂度 - **时间复杂度**:由于每个字符多被访问两次(一次由 `right` 指针进入窗口,一次由 `left` 指针移出窗口),因此总的时间复杂度为 $O(n)$,其中 $n$ 是字符的长度。 - **空间复杂度**:取决于字符集的大小。若使用固定大小的数组(如长度为 128 的数组),则空间复杂度为 $O(1)$。 #### 示例代码(C语言) 以下是一个基于滑动窗口思想的 C 语言实现: ```c #include <stdio.h> #include <string.h> int lengthOfLongestSubstring(char* s) { int n = strlen(s); int charMap[128] = {0}; // 用于记录字符是否出现 int left = 0, maxLen = 0; for (int right = 0; right < n; right++) { while (charMap[s[right]] > 0) { charMap[s[left]]--; left++; } charMap[s[right]]++; if (right - left + 1 > maxLen) { maxLen = right - left + 1; } } return maxLen; } int main() { char s[] = "abcabcbb"; int result = lengthOfLongestSubstring(s); printf("The length of the longest substring without repeating characters is %d\n", result); // 输出: 3 return 0; } ``` #### 示例说明 - 对于输入 `"abcabcbb"`,最长无重复字符的子串是 `"abc"`,其长度为 3。 - 对于输入 `"pwwkew"`,最长无重复字符的子串是 `"wke"`,其长度为 3。 - 对于输入 `"bbbbb"`,最长无重复字符的子串是 `"b"`,其长度为 1。 #### 优势与适用场景 滑动窗口算法适用于需要查找满足特定条件的连续子数组或子串问题。除了本题外,它还可以用于其他类似问题,如“小覆盖子串”、“最长重复字符替换后的子串”等。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值