算法通过村第十二关-字符串|白银笔记|经典面试题

文章目录

  • 前言
  • 1. 反转问题
    • 1.1 反转字符串
    • 1.2 k个一组反转
    • 1.3 仅仅反转字母
      • 1.3.1 采用栈实现操作
      • 1.3.2 采用双指针实现操作
    • 1.4 反转字符串里面的单词
      • 1.4.1 使用语言提供的方法来解决(内置API)
      • 1.4.2 如何优雅自己实现上述功能
  • 2. 验证回文串
  • 3. 字符串中的第一个唯一字符
  • 4. 判断是否互为字符重排
      • 4.1 排序重组
      • 4.2 采用Hash实现操作
  • 总结


前言


提示:越是在意的人,越是绝口不提。我选择你,做内心深处的秘密。来日有人剖开这颗心来,里面除了你,什么都没有。 --陶立夏《生活的比喻》

本章挑战的难度不大,是大量字符串题目的基础。务必学扎实。

1. 反转问题

我们知道反转是链表的一个重要考点,反转同样也是字符串的一个重要问题。常见的也就是如下这些:

推荐题目⭐⭐⭐⭐⭐:

344. 反转字符串 - 力扣(LeetCode)

541. 反转字符串 II - 力扣(LeetCode)

917. 仅仅反转字母 - 力扣(LeetCode)

151. 反转字符串中的单词 - 力扣(LeetCode)

557. 反转字符串中的单词 III - 力扣(LeetCode)

这些题目你是否看出一些规律在其中,要么反转字符串,要么反转里面的单词。针对字符的反转可以变换造出很多题目来。这里我们据从基本出发,逐个击破。

1.1 反转字符串

参考题目介绍:344. 反转字符串 - 力扣(LeetCode)

在这里插入图片描述
在这里插入图片描述
这是最基本的反转题,也是最简单的问题。这里使用双指针最直接。具体的做法是:

对于一个长度为N的待反转的字符串数组,我们观察反转前后的下标的变化,就可以知道结果

s[0]   s[N - 1]
s[1]   s[N - 2]
s[2]   s[N - 3]
s[3]   s[N - 4]
s[4]   s[N - 5]
...    ...s[n - 1]   s[0]

比较完之后我们可以发现规律:即s[i] 与 s[N - 1 -i] 发生了交换。所以双指针我们就可以这样写:

  • 将left指向字符串数组的首元素,right指向字符串数组的尾元素
  • 当left < right:
    • 交换s[left] 和 s[right]
    • left 指针右移一位,即left = left + 1
    • right指针左移一位,即right = tight -1
  • 当left >= right ,反转结束,返回字符数组即可
    /*** 反转字符串(双指针)* @param s the string */public static void reverseString(char[] s) {int n = s.length;for(int left = 0,right = n - 1; left < right; left++,right--){char c = s[left];s[left] = s[right];s[right] = c;}}

1.2 k个一组反转

参考题目介绍:541. 反转字符串 II - 力扣(LeetCode)

在这里插入图片描述
在这里插入图片描述
怎么感觉这题在找事呢?确实是闲了。这里我们根据题意直接模拟结果:

反转每个下标从2k的倍数开始,长度为k的字串。如果字串长度不足k则反转整个字串。

/*** 反转k个字符串* @param s* @param k* @return*/public static String reverseStr(String s, int k) {if(s == null || s.length=0){return new String();}int n = s.length();char[] chars = s.toCharArray();for(int i = 0; i < n; i += 2*k){reverse(chars,i,Math.min(k + i,n) -1);}return new String(chars);}public static void reverse(char[] arr, int left, int right) {while(left < right){char c = arr[left];arr[left] = arr[right];arr[right] = c;left++;right--;}}

1.3 仅仅反转字母

参考题目介绍:917. 仅仅反转字母 - 力扣(LeetCode)

在这里插入图片描述

在这里插入图片描述
这里第一眼的感觉是不是很复杂,但同样从两头向中间就可以了,但是问题‘-’不是均匀的有些麻烦,处理起来不容易就增加了难度。其实换一种思路就不同了,栈这个工具,对于反转来说非常好用。

1.3.1 采用栈实现操作

具体方法:

将s中的所有字母单独存放在栈中,所以出栈来说就是反序操作了(当然也可以用数组存并反序的)

然后遍历s的所有字符,如果是字母就输出。

     /*** 仅仅反转字母* @param s the string to reverse* @return*/public static String reverseOnlyLetters(String s) {// 校验参数if (s == null || s.length() == 0) {return s;}// 创建一个栈作存储单词Stack<Character> letters = new Stack<Character>();for (Character c : s.toCharArray()){if (Character.isLetter(c)){letters.push(c);}}StringBuilder res = new StringBuilder();for (Character c : s.toCharArray()){if (Character.isLetter(c)){res.append(letters.pop());}else{res.append(c);}}return res.toString();}

1.3.2 采用双指针实现操作

一个接一个输出s的所有字符,当遇到一个字母时,我们希望找到逆序遍历字符串的下一个字母。

所以我们这么做:维护一个指针j从后向前遍历字符串,当需要字母的时候就使用它。

    /*** 进反转字母(双指针实现)* @param s the string to reverse* @return*/public static String reverseOnlyLetters2(String s) {// 校验参数if (s == null || s.length() == 0) {return s;}StringBuilder res = new StringBuilder();int j = s.length() - 1;for(int i = 0; i < s.length(); i++) {if (Character.isLetter(s.charAt(i))){// 可能不止一个while(!Character.isLetter(s.charAt(j))){j--;}res.append(s.charAt(j--));}else{res.append(s.charAt(i));}}return   res.toString();}

1.4 反转字符串里面的单词

参考题目介绍:151. 反转字符串中的单词 - 力扣(LeetCode)

在这里插入图片描述
在这里插入图片描述
这个题目经常在很多面试题中见到,这样的题目重点在如何处理单词,其实难度并不大,我们重点看下分析:

1.4.1 使用语言提供的方法来解决(内置API)

比如Java,Python,C++等很多语言提供了相关的特性,因此我们可以首先使用语言的特性来解决:

很多语言对字符串都有特殊的处理,提供了split(拆分),reverse(反转) 和 join(连续)等方法。一次采用内置的API是可行的。

  • 使用split将字符串按照空格分割成字符串数组;
  • 使用reverse将字符串数组进行反转;
  • 使用join方法将字符串重新拼接成一个字符串。

如图:

在这里插入图片描述

public String reverseWords(String s) {if(s == null || s.length() == 0){return s;}// 去除开头和结尾的空白字符,这个很重要s = s.trim();// 正则匹配连续的字符空白字符作为分隔符// 正则表达式中\s匹配任何空白字符,包括空格、制表符、换页符等等, 等价于[ \f\n\r\t\v]List<String> wordList = Arrays.asList(s.split("\\s+"));Collections.reverse(wordList);return String.join(" ",wordList);
}

上面的方法,在面试中式禁止使用的,别想了,怎么会这么优雅呢,还是乖乖自己实现吧。

1.4.2 如何优雅自己实现上述功能

对于字符串可变的语言,就不需要在额外开辟空间了,直接在字符串上原地实现,这种情况下,反转字符和去除空格可以一起完成。

    /*** 反转字符串中的单词* @param s* @return*/public static String reverseWords(String s) {// 校验参数if(s == null || s.length() == 0) {return s;}// 出去多余空白字符StringBuilder sb = trimSpaces(s);// 反转字符串reverse(sb,0,sb.length() - 1);// 反转每个单词reverseWord(sb);return sb.toString();}private static void reverseWord(StringBuilder sb) {int n = sb.length();int start = 0, end = 0;while(start < n){// 循环到单词末尾while(end < n && sb.charAt(end) != ' '){++end;}// 反转单词reverse(sb,start,end - 1);// 更新start, 去寻找下一个单词start = end + 1;++end;}}/*** 反转字符出(可变)* @param sb* @param left* @param right*/private static void reverse(StringBuilder sb, int left, int right) {while (left < right){char temp = sb.charAt(left);sb.setCharAt(left++,sb.charAt(right));sb.setCharAt(right--,temp);}}private static StringBuilder trimSpaces(String s) {int left = 0,right = s.length() - 1;// 去除掉开头和结尾的空白字符while (left <= right && s.charAt(left) == ' ') {left++;}while (left <= right && s.charAt(right) == ' ') {right--;}// 将字符串间多余的空白符去掉StringBuilder sb = new StringBuilder();while(left <= right){char c = s.charAt(left);if (c != ' '){sb.append(c);}else  if (sb.charAt(sb.length() - 1) != ' '){sb.append(c);}left++;}return sb;}

2. 验证回文串

参考题目地址:125. 验证回文串 - 力扣(LeetCode)

在这里插入图片描述
在这里插入图片描述
回文问题再链表中也是常见的,再字符串中同样也是重点。(这里记录一下骨头哥☠️的经历技术面式:

第一就式写一个判断字符串回文的问题,题目本身很简单,双指针的典型问题。下面就会被加餐,找最长的回文串(这里就需要动态规划的思想了,这里我们后面再说))

说是话,刷了这么多题目,这个问题真的式手到擒来。有很多思路。最简单的方法就是对字符串进行一次遍历,并保留其中的字母和数字,放入另一个字符串sgood中。这样我们只需要判断sgood是不是一个普通的回文串了。

如果不是用语言的特性,这里我们可以使用双指针的思想来处理。

  • 初始,左右指针分别指向sgood的两侧
  • 不断向中间移动,判断是否相同,如果相遇就说明是回文串
     /*** 判断是否为回文字符串* @param s* @return*/public static boolean isPalindrome(String s) {if (s == null || s.length() == 0) {return true;}StringBuilder sgood = new StringBuilder();int len = s.length();for(int i = 0; i < len; i++) {char c = s.charAt(i);if (Character.isLetterOrDigit(c)) {sgood.append(Character.isLowerCase(c));}}int n = sgood.length();int left = 0,right = n - 1;while(left < right) {if (Character.toLowerCase(sgood.charAt(left)) != Character.toLowerCase(sgood.charAt(right))) {return false;}++left;--right;}return true;}

3. 字符串中的第一个唯一字符

参考题目地址:387. 字符串中的第一个唯一字符 - 力扣(LeetCode)

在这里插入图片描述

对于这个问题,最直观的方法就是遍历两次就可以知道结果,采用hash统计字符串中每个字符出现的次数。在第二次遍历时,就可以遍历到只出现1次的字符,直接返回他的索引即可,没有的话返回-1。

    /*** 找只出现一次的字符* @param s* @return*/public static int firstUniqChar(String s) {// 参数校验if(s == null || s.length() == 0){return 0;}Map<Character,Integer> frequency = new HashMap<Character,Integer>();for(int i = 0; i < s.length(); i++){char c = s.charAt(i);frequency.put(c,frequency.getOrDefault(c,0) + 1);}for(int i = 0; i < s.length(); i++){if (frequency.get(s.charAt(i)) == 1){return i;}}return -1;}

4. 判断是否互为字符重排

参考题目介绍:242. 有效的字母异位词 - 力扣(LeetCode)

在这里插入图片描述

这是一道简单题,就不要想的特别复杂啦。(当然这也是一道非常经典的题目)

这个题目来说,如果你觉得时排列组合的问题,还解决了,说明你排列组合学的很好。但是这里有更好的解法。

4.1 排序重组

将两个字符串全部从小到大或者从大到小排序,然后再逐个比较,不管原始字符串是什么,都可以判断出来,代码也不复杂。

      /*** 判断字符串是否重排* @param s1* @param s2* @return*/public static boolean checkPermutation1(String s1, String s2) {// 将字符串转成数组char[] chars1 = s1.toCharArray();char[] chars2 = s2.toCharArray();// 排序Arrays.sort(chars1);Arrays.sort(chars2);// 比较return new String(chars1).equals(new String(chars2));}

这里需要注意我们使用了内置api,面试是不允许的。

4.2 采用Hash实现操作

注意:这里我们不能简单的判断是否已经存在,因为字符串可能在某个串里面重复存在例如“abac”。所以我们可以记录出现的次数,如果一个字符串经过重新排列后,能变成另外一个字符串,那么他们每个不同字符出现的次数是相同的。例如:出现此处不同的,那么便是两个字符串不能够经过重新排列得到。

所以写起来页不复杂,但是长了些。

  /*** 判断字符串是否重排* @param s1* @param s2* @return*/public static boolean checkPermutation(String s1, String s2) {if(s1.length() != s2.length()){return false;}char[] chars = s1.toCharArray();Map<Character, Integer> s1Map = getMap(s1);Map<Character, Integer> s2Map = getMap(s2);for(Character c : chars){if(!s1Map.containsKey(c) || !s2Map.containsKey(c) || s1Map.get(c).intValue() != s2Map.get(c).intValue() ){return false;}}return  true;}/*** 统计指定字符串str中各字符的出现次数,并以Map的形式返回* @param str* @return*/public static Map<Character, Integer> getMap(String str) {Map<Character, Integer> map = new HashMap<>();char[] chars = str.toCharArray();for (char aChar : chars) {map.put(aChar, map.getOrDefault(aChar, 0) + 1);}return map;} 

总结

提示:字符串常见问题;双指针问题的回顾;反转问题;回文字符串;重排序问题。


如果有帮助到你,请给题解点个赞和收藏,让更多的人看到 ~ ("▔□▔)/

如有不理解的地方,欢迎你在评论区给我留言,我都会逐一回复 ~

也欢迎你 关注我 ,喜欢交朋友,喜欢一起探讨问题。
在这里插入图片描述

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

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

相关文章

GitHub爬虫项目详解

前言 闲来无事浏览GitHub的时候&#xff0c;看到一个仓库&#xff0c;里边列举了Java的优秀开源项目列表&#xff0c;包括说明、仓库地址等&#xff0c;还是很具有学习意义的。但是大家也知道&#xff0c;国内访问GitHub的时候&#xff0c;经常存在访问超时的问题&#xff0c;…

鸡群优化(CSO)算法(含MATLAB代码)

先做一个声明&#xff1a;文章是由我的个人公众号中的推送直接复制粘贴而来&#xff0c;因此对智能优化算法感兴趣的朋友&#xff0c;可关注我的个人公众号&#xff1a;启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法&#xff0c;经典的&#xff0c;或者是近几年…

《Secure Analytics-Federated Learning and Secure Aggregation》论文阅读

背景 机器学习模型对数据的分析具有很大的优势&#xff0c;很多敏感数据分布在用户各自的终端。若大规模收集用户的敏感数据具有泄露的风险。 对于安全分析的一般背景就是认为有n方有敏感数据&#xff0c;并且不愿意分享他们的数据&#xff0c;但可以分享聚合计算后的结果。 联…

【算法练习Day13】二叉树的层序遍历翻转二叉树对称二叉树

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 二叉树的层序遍历翻转二叉树…

【二】spring boot-设计思想

spring boot-设计思想 简介&#xff1a;现在越来越多的人开始分析spring boot源码&#xff0c;拿到项目之后就有点无从下手了&#xff0c;这里介绍一下springboot源码的项目结构 一、项目结构 从上图可以看到&#xff0c;源码分为两个模块&#xff1a; spring-boot-project&a…

ipa文件怎么把应用上架到苹果ios系统下载的App Store商城

注册为苹果开发者&#xff1a;首先&#xff0c;您需要注册为苹果开发者。前往苹果开发者网站&#xff08;https://developer.apple.com/&#xff09;&#xff0c;点击"Enroll"按钮&#xff0c;并按照相关步骤注册和付费&#xff08;开发者账号需要年度费用&#xff0…

SpringCloud Alibaba - Seata 四种分布式事务解决方案(TCC、Saga)+ 实践部署(下)

目录 一、Seata 分布式解决方案 1.1、TCC 模式 1.1.1、TCC 模式理论 对比 TCC 和 AT 模式的一致性和隔离性 TC 的工作模型 1.2.2、TCC 模式优缺点 1.2.3、TCC 模式注意事项&#xff1a;空回滚 1.2.4、TCC 模式注意事项&#xff1a;业务悬挂 1.2.5、实现 TCC 模式 案例…

(六)正点原子STM32MP135移植——内核移植

目录 一、概述 二、编译官方代码 三、移植 四、编译 一、概述 前面已经移植好了TF-A、optee、u-boot&#xff0c;在u-boot能正常跑起来的情况下&#xff0c;现在来移植内核。 二、编译官方代码 进入kernel目录 2.1 解压源码、打补丁 /* 解压源码 */ tar xf linux-6.1.28.…

【Go语言实战】(25) 分布式算法 MapReduce

MapReduce 写在前面 身为大数据专业的学生&#xff0c;其实大学我也多多少少接触过mapreduce&#xff0c;但是当时觉得这玩意太老了&#xff0c;觉得这和php一样会被时代淘汰。只能说当时确实太年轻了&#xff0c;没有好好珍惜那时候的学习资源… 现在回过头来看mapreduce&a…

想做好接口测试,先把这些概念搞清楚了

接口一般来说有两种&#xff0c;一种是程序内部的接口&#xff0c;一种是系统对外的接口。 系统对外的接口 比如你要从别的网站或服务器上获取资源或信息&#xff0c;别人肯定不会把数据库共享给你&#xff0c;他只能给你提供一个他们写好的方法来获取数据&#xff0c;你引用…

【BBC新闻文章分类】使用 TF 2.0和 LSTM 的文本分类

一、说明 NLP上的许多创新是如何将上下文添加到词向量中。常见的方法之一是使用递归神经网络

数据结构之带头双向循环链表

目录 链表的分类 带头双向循环链表的实现 带头双向循环链表的结构 带头双向循环链表的结构示意图 空链表结构示意图 单结点链表结构示意图 多结点链表结构示意图 链表创建结点 双向链表初始化 销毁双向链表 打印双向链表 双向链表尾插 尾插函数测试 双向链表头插 …

如何选择合适的自动化测试工具?

自动化测试是高质量软件交付领域中最重要的实践之一。在今天的敏捷开发方法中&#xff0c;几乎任一软件开发过程都需要在开发阶段的某个时候进行自动化测试&#xff0c;以加速回归测试的工作。自动化测试工具可以帮助测试人员以及整个团队专注于自动化工具无法处理的各自任务&a…

【数据结构---排序】很详细的哦

本篇文章介绍数据结构中的几种排序哦~ 文章目录 前言一、排序是什么&#xff1f;二、排序的分类 1.直接插入排序2.希尔排序3.选择排序4.冒泡排序5.快速排序6.归并排序总结 前言 排序在我们的生活当中无处不在&#xff0c;当然&#xff0c;它在计算机程序当中也是一种很重要的操…

关掉在vscode使用copilot时的提示音

1. 按照图示的操作File --> Preferences --> Settings 2. 搜索框输入关键字Sound&#xff0c;因为是要关掉声音&#xff0c;所以找有关声音的设置 3. 找到如下图所示的选项 Audio Cues:Line Has Inline Suggetion,将其设置为Off 这样&#xff0c;就可以关掉suggest code时…

Elasticsearch:什么时候应该考虑在 Elasticsearch 中添加协调节点?

仅协调节点&#xff08;coordinating only nodes&#xff09;充当智能负载均衡器。 仅协调节点的这种特殊角色通过减轻数据和主节点的协调责任&#xff0c;为广泛的集群提供了优势。 加入集群后&#xff0c;这些节点与任何其他节点类似&#xff0c;都会获取完整的集群状态&…

毕业设计选题之Android基于移动端的线上订餐app外卖点餐安卓系统源码 调试 开题 lw

&#x1f495;&#x1f495;作者&#xff1a;计算机源码社 &#x1f495;&#x1f495;个人简介&#xff1a;本人七年开发经验&#xff0c;擅长Java、Python、PHP、.NET、微信小程序、爬虫、大数据等&#xff0c;大家有这一块的问题可以一起交流&#xff01; &#x1f495;&…

C# - Opencv应用(1) 之VS下环境配置详解

C# - Opencv应用&#xff08;1&#xff09; 之VS下环境配置详解 有时候&#xff0c;单纯c#做前端时会联合C实现的dll来落地某些功能由于有时候会用C - Opencv实现算法后封装成dll&#xff0c;但是有时候会感觉麻烦&#xff0c;不如直接通过C#直接调用Opencv在此慢慢总结下C# -…

SpringBoot vue云办公系统

SpringBoot vue云办公系统 系统功能 云办公系统 登录 员工资料管理: 搜索员工 添加编辑删除员工 导入导出excel 薪资管理: 工资账套管理 添加编辑删除工资账套 员工账套设置 系统管理: 基础信息设置 部门管理 职位管理 职称管理 权限组管理 操作员管理 开发环境和技术 开发语…

选择适合户外篷房企业的企业云盘解决方案

“户外篷房企业用什么企业云盘好&#xff1f;Zoho WorkDrive企业网盘可以帮助户外篷房企业实现文档统一管理、提高工作效率、加强团队协作&#xff0c;并且支持各种文件类型的预览和编辑。” S公司是一家注重管理规范的大型户外篷房企业&#xff0c;已经有10余年的经验。作为设…