剑指offer(C++)-JZ48:最长不含重复字符的子字符串(算法-动态规划)

简介: 剑指offer(C++)-JZ48:最长不含重复字符的子字符串(算法-动态规划)

题目描述:

请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。

数据范围:

s.length≤40000 s.length≤40000

示例:

输入:

"abcabcbb"


返回值:

3


说明:

因为无重复字符的最长子串是"abc",所以其长度为 3。

解题思路:

本题是动态规划的经典题目。有两个解题思路。

思路一:滑动窗口

  1. 设计一个滑动窗口,窗口的右边界先行,用哈希表统计字符出现次数。
  2. 当出现重复字符时,左边界出发缩小窗口直到重复字符消失。
  3. 持续刷新最值就可以了。


思路二:动态规划


  1. 用哈希表存放字符上次出现的位置下标;用长度比字符串大1的vector,存放截止到第i个字符时,能继续维持的子串长度,比如v[0]=0,v[1]=1,v[2]可能为1可能为2。
  2. 执行遍历。用哈希表判断当前字符是否为重复字符,如果不是重复字符,那就在前面子串长度基础上加1;若出现了重复字符,则该字符与其重复字符的距离为i-m[s[i]],但如果两者之间有别的重复字符,则需要考虑此类情况,可以认为在其重复字符之后的子串中,该字符未出现过,则有v[i]+1;所以,比较v[i]+1和i-m[s[i]]谁小取谁,因为小的子串没断开,后续可以继续连接,而断开的子串虽然长度大,但不可以继续增加了。
  3. 持续更新字符最新下标以及子串长度最大值。

测试代码:

思路一:滑动窗口

class Solution {
public:
    // 最长子串
    int lengthOfLongestSubstring(string s) {
        // 定义哈希表
        unordered_map<char, int> m;
        // 滑动窗口遍历
        int result = 0;
        for(int left = 0, right = 0; right < s.length(); ++right){
            // 窗口右边界先行,统计字符出现次数
            m[s[right]]++;
            // 当出现重复字符,窗口左边界右移缩小窗口直到重复字符消失
            while(m[s[right]] > 1){
                m[s[left]]--;
                left++;
            }
            // 持续刷新子串最大长度
            result = max(result, right - left + 1);
        }
        return result;
    }
};

思路二:动态规划

class Solution {
public:
    // 最长子串
    int lengthOfLongestSubstring(string s) {
        // 定义哈希表,存放的是字符出现的位置下标
        unordered_map<char, int> m;
        int result = 0;
        // v[i]表示截止到i个字符时,能继续维持的子串长度
        // 所以v[0]=0,v[1]=1
        vector<int> v = vector<int>(s.length() + 1, 0);
        // i是字符串中字符下标
        for(int i = 0; i < s.length(); ++i){
            // 当哈希表中没发现重复字符,那就在前面最长子串长度基础上+1
            if(m.find(s[i]) == m.end())
                v[i + 1] = v[i] + 1;
            // 若出现了重复字符,该字符与其重复字符的距离为i-m[s[i]]
            // 但如果两者之间有别的重复字符,那要考虑这类情况
            // 可以认为在其重复字符之后的子串中,该字符未出现过,则有v[i]+1
            // 所以v[i]+1和i-m[s[i]]谁小,取谁,因为小的这个子串没断开
            else
                v[i + 1] = min(v[i] + 1, i - m[s[i]]);
            // 刷新该字符最新下标
            m[s[i]] = i;
            // 刷新最值
            result = max(result, v[i + 1]);
        }
        return result;
    }
};


相关文章
|
2月前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
80 15
|
2月前
|
存储 算法 数据处理
公司局域网管理中的哈希表查找优化 C++ 算法探究
在数字化办公环境中,公司局域网管理至关重要。哈希表作为一种高效的数据结构,通过哈希函数将关键值(如IP地址、账号)映射到数组索引,实现快速的插入、删除与查找操作。例如,在员工登录验证和设备信息管理中,哈希表能显著提升效率,避免传统线性查找的低效问题。本文以C++为例,展示了哈希表在局域网管理中的具体应用,包括设备MAC地址与IP分配的存储与查询,并探讨了优化哈希函数和扩容策略,确保网络管理高效准确。
|
23天前
|
存储 监控 算法
基于 C++ 哈希表算法的局域网如何监控电脑技术解析
当代数字化办公与生活环境中,局域网的广泛应用极大地提升了信息交互的效率与便捷性。然而,出于网络安全管理、资源合理分配以及合规性要求等多方面的考量,对局域网内计算机进行有效监控成为一项至关重要的任务。实现局域网内计算机监控,涉及多种数据结构与算法的运用。本文聚焦于 C++ 编程语言中的哈希表算法,深入探讨其在局域网计算机监控场景中的应用,并通过详尽的代码示例进行阐释。
43 4
|
3月前
|
存储 算法 Java
算法系列之动态规划
动态规划(Dynamic Programming,简称DP)是一种用于解决复杂问题的算法设计技术。它通过将问题分解为更小的子问题,并存储这些子问题的解来避免重复计算,从而提高算法的效率。
119 4
算法系列之动态规划
|
3月前
|
存储 监控 算法
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
45 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
|
3月前
|
消息中间件 Linux C++
c++ linux通过实现独立进程之间的通信和传递字符串 demo
的进程间通信机制,适用于父子进程之间的数据传输。希望本文能帮助您更好地理解和应用Linux管道,提升开发效率。 在实际开发中,除了管道,还可以根据具体需求选择消息队列、共享内存、套接字等其他进程间通信方
85 16
|
3月前
|
算法 安全 调度
【动态规划篇】穿越算法迷雾:约瑟夫环问题的奇幻密码
【动态规划篇】穿越算法迷雾:约瑟夫环问题的奇幻密码
|
3月前
|
机器学习/深度学习 算法 测试技术
【动态规划篇】01 背包的逆袭:如何用算法装满你的 “财富背包”
【动态规划篇】01 背包的逆袭:如何用算法装满你的 “财富背包”
|
4月前
|
算法 Java C++
【潜意识Java】蓝桥杯算法有关的动态规划求解背包问题
本文介绍了经典的0/1背包问题及其动态规划解法。
110 5
|
4月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
134 2

热门文章

最新文章