【LeetCode】剑指 Offer Ⅱ 第3章:字符串(7道题) -- Java Version

题库链接:https://leetcode.cn/problem-list/e8X3pBZi/

在这里插入图片描述

题目解决方案
剑指 Offer II 014. 字符串中的变位词双指针 + 数组模拟哈希表 ⭐
剑指 Offer II 015. 找到字符串中所有字母异位词双指针 + 数组模拟哈希表 ⭐
剑指 Offer II 016. 不含重复字符的最长子字符串双指针 + 数组模拟哈希表 ⭐
剑指 Offer II 017. 最小覆盖子串双指针 + 哈希表 ⭐
剑指 Offer II 018. 有效的回文双指针(前后)⭐
剑指 Offer II 019. 最多删除一个字符得到回文双指针(前后)⭐
剑指 Offer II 020. 回文子字符串的个数双指针(从回文中心出发)⭐

本章的题目主要分为两种类型:变位词 和 回文;
……
如果将 字符串 看成一个由字符组成的数组,那么也可以用两个指针来定位一个子字符串,其中一个指针指向字符串的第1个字符,另一个指针指向字符串的最后一个字符,两个指针之间所包含的就是一个子字符串。
……
一般来说,就双指针的字符串问题而言,这种类型的面试题基本上都与 统计字母出现的次数 有关,我们常用 哈希表 来存储每个元素出现的次数。

1. 剑指 Offer II 014. 字符串中的变位词 – P31

给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的某个变位词。

1.1 滑动窗口 – O(m+n)

时间复杂度 O ( m + n ) O(m+n) O(m+n),空间复杂度 O ( n ) O(n) O(n)

窗口定长为 n,每次向前移动一格.

class Solution {// 1. 滑动窗口public boolean checkInclusion(String s1, String s2) {int n = s1.length(), m = s2.length();if (n > m) return false;  // 如果 n > m,则 s2 中必不存在 s1 的变位词int[] cnt1 = new int[26];  // 26个英文字母int[] cnt2 = new int[26];for (int i = 0; i < n; i++) {++cnt1[s1.charAt(i) - 'a'];++cnt2[s2.charAt(i) - 'a'];}if (Arrays.equals(cnt1, cnt2)) return true; for (int i = n; i < m; i++) {++cnt2[s2.charAt(i) - 'a'];--cnt2[s2.charAt(i-n) - 'a'];if (Arrays.equals(cnt1, cnt2)) return true;}return false;}
}

在这里插入图片描述

1.2 双指针 + 数组模拟哈希表 – O(m+n)(⭐)

时间复杂度 O ( m + n ) O(m+n) O(m+n),空间复杂度 O ( n ) O(n) O(n)

class Solution {// 2. 双指针 + 数组模拟哈希表public boolean checkInclusion(String s1, String s2) {int n = s1.length(), m = s2.length();if (n > m) {return false;}int[] cnt = new int[26];for (int i = 0; i < n; i++) --cnt[s1.charAt(i) - 'a'];  // 让 s1 全为负数for (int l = 0, r = 0; r < m; r++) {  // 双指针遍历 s2,从 s2 中找出 s1 的变式int t = s2.charAt(r) - 'a';cnt[t]++;while (cnt[t] > 0) --cnt[s2.charAt(l++) - 'a'];if (r - l + 1 == n) return true;  // 说明此时 cnt 数组之和全为 0}return false;}
}

在这里插入图片描述

2. 剑指 Offer II 015. 找到字符串中所有字母异位词 – P35

给定两个字符串 s 和 p,找到 s 中所有 p 的 变位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
……
此题也可使用1题中 滑动窗口 的解法,但是滑动窗口 + 两个 cnt[] 的方法要比双指针的慢一些,为避免冗余,此处省略.

2.1 双指针 + 数组模拟哈希表 – O(m+n)(⭐)

时间复杂度 O ( m + n ) O(m+n) O(m+n),空间复杂度 O ( n ) O(n) O(n)

class Solution {// 双指针public List<Integer> findAnagrams(String s, String p) {int n = s.length(), m = p.length();List<Integer> list = new LinkedList<>();int[] cnt = new int[26];  // 26个小写英文字母for (int i = 0; i < m; i++) --cnt[p.charAt(i) - 'a'];  // 初始化 p 串, 使cnt--for (int l = 0, r = 0; r < n; r++) {  // 双指针移动 s 串int t = s.charAt(r) - 'a';cnt[t]++;while (cnt[t] > 0) --cnt[s.charAt(l++) - 'a'];if (r - l +  1 == m) list.add(l);  // 在 s 中找到 p 的变位词,记录起始索引} return list;}
}

在这里插入图片描述

3. 剑指 Offer II 016. 不含重复字符的最长子字符串 – P36

给定一个字符串 s ,请你找出其中不含有重复字符的 最长连续子字符串 的长度。

3.1 双指针 + 数组模拟哈希表 – O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

class Solution {// 1. 双指针 + 数组模拟哈希表public int lengthOfLongestSubstring(String s) {int n = s.length();if (n == 0) return 0;int res = 0;int[] ascii = new int[256];  // 与前两题不同的是,这次不局限于小写英文字母了for (int l = 0, r = 0; r < n; r++) {int t = s.charAt(r);ascii[t]++;while (ascii[t] > 1) --ascii[s.charAt(l++)];  // ascii[i] > 0, 说明出现了重复字符,开始移动 l res = Math.max(res, r - l + 1);  // 记录不重复子字符串的长度}return res;}
}

在这里插入图片描述

3.2 HashSet – O(n)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

class Solution {public int lengthOfLongestSubstring(String s) {// 哈希集合,记录每个字符是否出现过Set<Character> set = new HashSet<Character>();int n = s.length();// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动int r = -1, ans = 0;for (int l = 0; l < n; l++) {if (l != 0) {// 左指针向右移动一格,移除一个字符set.remove(s.charAt(l - 1));}while (r + 1 < n && !set.contains(s.charAt(r + 1))) {// 不断地移动右指针set.add(s.charAt(r + 1));++r;}// 第 l 到 r 个字符是一个极长的无重复字符子串ans = Math.max(ans, r - l + 1);}return ans;}
}

在这里插入图片描述

PS:补充知识1 - 【HashSet】

在这里插入图片描述

💡 HashSet集合(元素无序且唯一),其底层是哈希表,特点:

  • 无序;
  • 不可重复;
  • 不能排序;

……
元素的唯一性是靠元素重写 hashCode() 和 equals() 方法来保证的,如果不重写则无法保证唯一性.(Integer以及String类等都已经重写了这两个方法,一定要注意自己定义的类需要重写才能确保唯一性!)
……
更多内容可参考:
[1] 单列集合Set的实现类HashSet - 陪雨岁岁年年的博客
[2] Java-单列集合(Collection,List,Set集合的详细介绍)- 壹万捌先生的博客

4. 剑指 Offer II 017. 最小覆盖子串 – P39

给定两个字符串 s 和 t 。返回 s 中包含 t 的所有字符的最短子字符串。如果 s 中不存在符合条件的子字符串,则返回空字符串 “” 。

4.1 双指针 + 哈希表 – O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

class Solution {public String minWindow(String s, String t) {int n = s.length(), m = t.length();Map<Character,Integer> tmap = new HashMap<>();for (int i = 0; i < m; i++) tmap.put(t.charAt(i), tmap.getOrDefault(t.charAt(i),0)+1);int count = 0;Map<Character,Integer> smap = new HashMap<>();String res = "";for (int l = 0, r = 0; r < n; r++) {char rch = s.charAt(r);smap.put(rch, smap.getOrDefault(rch,0)+1);if (smap.get(rch) <= tmap.getOrDefault(rch,0)) {  // 排除重复冗余字符count++;}while (smap.getOrDefault(s.charAt(l),0) > tmap.getOrDefault(s.charAt(l),0) && l < r) {  // 当子字符串超过所需匹配字符时,移动lsmap.put(s.charAt(l), smap.getOrDefault(s.charAt(l),0)-1);l++;}if (count == m) {if (res.isEmpty() || (r - l + 1) < res.length()){  // 比较找出最小字符串res = s.substring(l, r + 1);}}}return res;}
}

在这里插入图片描述

4.2 双指针 + 数组模拟哈希表 – O(n)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

相比于4.1要更快,但是相对也要更难记忆.

class Solution {public String minWindow(String s, String t) {int[] map = new int[256];for(char c: t.toCharArray()){  // 初始化 t 字符串map[c]++;}int minLen = Integer.MAX_VALUE, minStart = 0;  // 设定最短字符串的长度和起始位置int m = t.length(), n = s.length();char[] sc = s.toCharArray();for (int l = 0, r = 0; r < n; r++){int rch = sc[r];map[rch]--;if(map[rch] >= 0){  // 减小与 t 的字符差距m--; }if(m == 0){  // 成功在 s 中匹配到包含 t 的子字符串int lch = sc[l];while(map[lch] < 0){  // 开始尝试缩小窗口范围map[lch]++;l++;lch = sc[l];  }int len = r - l + 1;if(len < minLen){  // 找出最小子字符串minLen = len;minStart = l;}map[lch]++;l++;m++;}}return minLen == Integer.MAX_VALUE ? "" : s.substring(minStart, minStart + minLen);}
}

在这里插入图片描述

5. 剑指 Offer II 018. 有效的回文 – P42

给定一个字符串 s ,验证 s 是否是 回文串 ,只考虑字母和数字字符,可以忽略字母的大小写。

5.1 双指针(前后)-- O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

class Solution {// 双指针:需要注意的是,有效字符包括:英文字母、数字和空格public boolean isPalindrome(String s) {int n = s.length();char[] sch = s.toLowerCase().toCharArray();for (int l = 0, r = n-1; l < r;) {if (!Character.isLetterOrDigit(sch[l])) l++;  // 判断是否为英文字母或数字else if (!Character.isLetterOrDigit(sch[r])) r--;else {if (sch[l] != sch[r]) return false;  // 前后指针不相同,说明非回文l++;r--;}}return true;}
}

在这里插入图片描述

PS:补充知识1 - 【Character包装类 – 8种方法】

判断一个字符是否是数字、英文、其他字符.

// 1. 判断该字符是否是字母,是返回true,否返回false
Character.isLetter(char ch)
// 2. 判断一个字符是否是数字字符,是返回true,否返回false
Character.isDigit(char ch)	
// 3. 判断该字符是字母还是数字,如果字符是字母或数字返回true; 否则false。
Character.isLetterOrDigit(char ch)
// 4. 判断指定字符是否为空白字符,空白符包含:空格、tab 键、换行符
Character.isWhitespace(char ch) 
// 5. 判断该字符是否是小写字母,是返回true,否返回false
Character.isLowerCase(char ch)
// 6. 判断该字符是否是大写字母,是返回true,否返回false
Character.isUpperCase(char ch)
// 7. 将小写字符转换为大写
Character.toUpperCase('A')
// 8. 将大写字符转换为小写
Character.toUpperCase('a')
// 9. 用于返回一个表示指定 char 值的 String 对象。结果是长度为 1 的字符串,仅由指定的 char 组成。
Character.toString('a')

6. 剑指 Offer II 019. 最多删除一个字符得到回文 – P43

给定一个非空字符串 s,请判断如果 最多 从字符串中删除一个字符能否得到一个回文字符串。

6.1 双指针(前后)-- O(n)(⭐)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( n ) O(n) O(n)

class Solution {public boolean validPalindrome(String s) {int n = s.length();char[] sch = s.toCharArray();int l = 0, r = n-1;for (; l < r; l++, r--) {if (sch[l] != sch[r]) break;  // 找到第一次不同之处}return isPalindrome(l+1,r,sch) || isPalindrome(l,r-1,sch);  // 删左或删右}public boolean isPalindrome(int l, int r, char[] sch) {  // 再次利用双指针进行回文判断while (l < r) {if (sch[l] != sch[r]) return false;l++;r--;}return true;}
}

在这里插入图片描述

6.2 双指针(前后)+StringBuilder – O(n)

时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

速度并不会提升,且书写代码量似乎也不会渐少,总之不太推荐这种写法。

class Solution {public boolean validPalindrome(String s) {int n = s.length();int l = 0, r = n - 1;while (l < r) {if (s.charAt(l) != s.charAt(r)) break;l++;r--;}if (r <= l) return true;String ls = s.substring(l+1, r+1);  // substring(), 左闭右开StringBuilder stringBuilder = new StringBuilder(ls);String rs = s.substring(l, r);StringBuilder stringBuilder2 = new StringBuilder(rs);return ls.equals(stringBuilder.reverse().toString()) || rs.equals(stringBuilder2.reverse().toString());}
}

在这里插入图片描述

PS:补充知识1 - 【substring() 方法】

在这里插入图片描述

substring() 方法返回字符串的子字符串,左闭右开区间 [beginIndex, endIndex)。

public class RunoobTest {public static void main(String args[]) {String Str = new String("This is text");System.out.print("返回值 :" );System.out.println(Str.substring(4) );  // 返回值 : is textSystem.out.print("返回值 :" );System.out.println(Str.substring(4, 10) );  // 返回值 : is te}
}

7. 剑指 Offer II 020. 回文子字符串的个数 – P44

给定一个字符串 s ,请计算这个字符串中有多少个回文子字符串。

7.1 双指针(从回文中心出发)-- O(n2)(⭐)

时间复杂度 O ( n 2 ) O(n^2) O(n2),空间复杂度 O ( 1 ) O(1) O(1)

class Solution {// 双指针:从回文中心出发public int countSubstrings(String s) {int n = s.length();if (n <= 1) return n;int count = 0;char[] sch = s.toCharArray();for (int i = 0; i < n; i++) {count += countPalindrome(sch, i, i);  // 奇数长度:一个对称中心count += countPalindrome(sch, i, i+1);  // 偶数长度:两个对称中心}return count;}public int countPalindrome(char[] sch, int l, int r) {int count = 0;while (l >= 0 && r < sch.length && sch[l] == sch[r]) {count++;l--;r++;}return count;}
}

在这里插入图片描述

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

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

相关文章

现代C++中的从头开始深度学习:【5/8】卷积

一、说明 在上一个故事中&#xff0c;我们介绍了机器学习的一些最相关的编码方面&#xff0c;例如 functional 规划、矢量化和线性代数规划。 现在&#xff0c;让我们通过使用 2D 卷积实现实际编码深度学习模型来开始我们的道路。让我们开始吧。 二、关于本系列 我们将学习如何…

小研究 - Mysql快速全同步复制技术的设计和应用(一)

Mysql半同步复制技术在高性能的数据管理中被广泛采用&#xff0c;但它在可靠性方面却存在不足.本文对半同步复制技术进行优化&#xff0c;提出了一种快速全同步复制技术&#xff0c;通过对半同步数据复制过程中的事务流程设置、线程资源合理应用、批量日志应用等技术手段&#…

服务器数据恢复-EXT3分区误删除邮件的数据恢复案例

服务器数据恢复环境&#xff1a; 一台服务器有一组由8块盘组建的RAID5阵列&#xff0c;EXT3文件系统。 服务器故障&#xff1a; 由于工作人员的误操作导致文件系统中的邮件丢失。用户需要恢复丢失的邮件数据。 服务器数据恢复过程&#xff1a; 1、将故障服务器中所有磁盘以只…

用户体验旅程图:改进用户体验的好工具

用户体验旅程图&#xff1a;改进用户体验的好工具 怎么改进体验&#xff0c;是有方法的 用户情绪曲线来衡量用户感觉 趣讲大白话&#xff1a;没有流程刨析&#xff0c;就没法改进 【趣讲信息科技245期】 **************************** 企业管理需要基本的流程的 企业流程简称BP…

Vue2(生命周期,列表排序,计算属性和监听器)

目录 前言一&#xff0c;生命周期1.1&#xff0c;生命周期函数简介1.2&#xff0c;Vue的初始化流程1.3,Vue的更新流程1.4&#xff0c; Vue的销毁流程1.5&#xff0c; 回顾生命周期1.,6&#xff0c;代码演示1.6-1&#xff0c;beforeCreate1.6-2&#xff0c;created1.6-3&#xf…

Python爬虫异常处理心得:应对网络故障和资源消耗

作为一名专业的爬虫代理&#xff0c;我知道在爬取数据的过程中&#xff0c;遇到网络故障和资源消耗问题是再正常不过了。今天&#xff0c;我将与大家分享一些关于如何处理这些异常情况的心得和技巧。不论你是在处理网络不稳定还是资源消耗过大的问题&#xff0c;这些技巧能够帮…

CMake良心教程(1)手把手教你入门!

目录 一.CMake是什么&#xff1f;有什么用&#xff1f; 二.环境配置 2.1CMake安装 2.2MinWG安装 三.构建最小项目 3.1项目的构建 3.2外部构建与内部构建 四.CMakeLists.txt语法介绍 4.1 project关键字 4.2 set 与 PROJECT_NAME 4.3 MESSAGE关键字 4.4 ADD_EXECUTABL…

安全防护,保障企业图文档安全的有效方法

随着企业现在数据量的不断增加和数据泄露事件的频发&#xff0c;图文档的安全性成为了企业必须高度关注的问题。传统的纸质文件存储方式已不适应现代企业的需求&#xff0c;而在线图文档管理成为了更加安全可靠的数字化解决方案。那么在在线图文档管理中&#xff0c;如何采取有…

【流量、日志分析】常见的web流量分析、windows日志分析

1.web流量分析 1.1 特点 通常会提供一个包含流量数据的 PCAP 文件&#xff0c;有时候也会需要先进行修复或重构传输文件后&#xff0c;再进行分析。 复杂的地方在于数据包里充满着大量无关的流量信息&#xff0c;因此如何分类和过滤数据是我们需要做的。 1.2 流量包修复 例…

计算机视觉与图形学-神经渲染专题-pi-GAN and CIPS-3D

《pi-GAN: Periodic Implicit Generative Adversarial Networks for 3D-Aware Image Synthesis》 摘要 我们见证了3D感知图像合成的快速进展&#xff0c;利用了生成视觉模型和神经渲染的最新进展。然而&#xff0c;现有的方法在两方面存在不足&#xff1a;首先&#xff0c;它们…

18. SpringBoot 如何在 POM 中引入本地 JAR 包

❤️ 个人主页&#xff1a;水滴技术 &#x1f338; 订阅专栏&#xff1a;成功解决 BUG 合集 &#x1f680; 支持水滴&#xff1a;点赞&#x1f44d; 收藏⭐ 留言&#x1f4ac; Spring Boot 是一种基于 Spring 框架的轻量级应用程序开发框架&#xff0c;它提供了快速开发应用程…

06 为什么需要多线程;多线程的优缺点;程序 进程 线程之间的关系;进程和线程之间的区别

为什么需要多线程 CPU、内存、IO之间的性能差异巨大多核心CPU的发展线程的本质是增加一个可以执行代码工人 多线程的优点 多个执行流&#xff0c;并行执行。&#xff08;多个工人&#xff0c;干不一样的活&#xff09; 多线程的缺点 上下文切换慢&#xff0c;切换上下文典型值…

Android LinearLayout dynamic add child ImageView,Glide load,kotlin

Android LinearLayout dynamic add child ImageView&#xff0c;Glide load&#xff0c;kotlin images.xml <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"andro…

宋浩概率论笔记(二)随机变量

本章节内容较多&#xff0c;是概率论与数理统计中最为重要的章节&#xff0c;对于概率密度和分布函数的理解与计算要牢牢掌握&#xff0c;才能在后期的学习中更得心应手。

前端js--剪刀石头布

效果图 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevice-width, initial-scale1.0" /><linkrel"stylesheet"href"ht…

libcurl网络库的函数接口使用

文章目录 1、libcurl简介2、libcurl的使用3、函数简介4、 curl_easy_setopt函数部分选项介绍5、curl_easy_perform 函数说明&#xff08;error 状态码&#xff09;6、简单实例,包含库文件&#xff0c;头文件即可 1、libcurl简介 libcurl是一个跨平台的网络协议库&#xff0c;支…

Running Homebrew as root is extremely dangerous and no longer supported

Running Homebrew as root is extremely dangerous and no longer supported 查看磁盘所有信息 在使用homebrew安装smartmontools&#xff0c;查看Mac磁盘信息&#xff0c;包括mac磁盘写入量、mac磁盘健康、磁盘启动次数等&#xff0c;遇到的问题及解决方案 使用brew install s…

【IDEA + Spark 3.4.1 + sbt 1.9.3 + Spark MLlib 构建鸢尾花决策树分类预测模型】

决策树进行鸢尾花分类的案例 背景说明&#xff1a; 通过IDEA Spark 3.4.1 sbt 1.9.3 Spark MLlib 构建鸢尾花决策树分类预测模型&#xff0c;这是一个分类模型案例&#xff0c;通过该案例&#xff0c;可以快速了解Spark MLlib分类预测模型的使用方法。 依赖 ThisBuild /…

Django的FBV和CBV

Django的FBV和CBV 基于django开发项目时&#xff0c;对于视图可以使用 FBV 和 CBV 两种模式编写。 FBV&#xff0c;function base views&#xff0c;其实就是编写函数来处理业务请求。 from django.contrib import admin from django.urls import path from app01 import view…

xcode打包导出ipa

转载&#xff1a;xcode打包导出ipa 目录 转载&#xff1a;xcode打包导出ipa 第一步&#xff1a;注册苹果开发者账号 第二步&#xff1a;下载APP Uploader 第三步&#xff1a;使用xcode打包导出ipa文件&#xff0c;供其他人内测 众所周知&#xff0c;在开发苹果应用时需要使…