【LeetCode】剑指 Offer 50. 第一个只出现一次的字符 p243 -- Java Version

news/2024/11/29 12:31:59/

题目链接:https://leetcode.cn/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof/

1. 题目介绍(50. 第一个只出现一次的字符)

在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。

在这里插入图片描述

【测试用例】:
示例1

输入:s = “abaccdeff”
输出:‘b’

示例2

输入:s = “”
输出:’ ’

【条件约束】:

限制

  • 0 <= s 的长度 <= 50000

【相关题目】

注意:本题与主站 387. 字符串中的第一个唯一字符 题目相同.

其它题目:

【题目1】: 从一个字符串中删除在另一个字符串中出现过的所有字符 (OR63 删除公共字符)。定义一个函数,输入两个字符串,从第一个字符串中删除在第二个字符串中出现过的所有字符。例如,输入 ”They are
students.” 和 ”aeiou” ,则删除之后的第一个字符串变成 ”Thy r stdnts.”
……
【Solution】:为了解决这个问题,我们可以创建一个用数组实现的简单 哈希表 来存储第二个字符串。这样我们从头到尾扫描第一个字符串的每个字符时,用 O(1) 时间就能判断出该字符是不是在第二个字符串中。如果第一个字符串的长度是 n, 那么总的时间复杂度是 O(n).

【题目2】:删除字符串中所有重复出现的字符(316. 去除重复字母)。定义一个函数,删除字符串中所有重复出现的字符。例如:输入“google”,删除重复字符之后的结果是“gole”。
……
【Solution】:我们可以创建一个 boolean数组 来实现简单的哈希表。数组中的元素的意义是其下标看作 ASCII 码后对应的字母在字符串中是否已经出现。 我们先把数组中所有的元素都设为 false。以 “google” 为例,当扫描到第一个 g 时,g 的 ASCII 码是 103,那么我们把数组中下标位103 的元素设为 true。当扫描到第二个 g 时,我们发现数组中下标位 103 的元素的值是 true,就知道 g 在前面已经出现过。
……
【Supplementary】:316. 去除重复字母 题目中除了要求去除重复字母,还要求返回值是 最小字典序。因此,在这一题中,我们还加入了 单调栈 来判断并存储 最小字典序的去重字符串。

【题目3】:变位词(剑指 Offer II 032. 有效的变位词)。该题有很多变形题,后面可以统一的练一练。在英语中,如果两个单词中出现的字母相同,且每个字母出现的次数也相同,那么这两个单词互为变位词(Anagram)。例如,silentlistenevillive 等互为变位词。请完成一个函数,判断输入的两个字符串是不是互为变位词。
……
【Solution】:我们可以创建一个用数组实现的简单 哈希表,用来统计字符串中每个字符出现的次数。

  • 当扫描到第一个字符串中的每个字符时,为哈希表对应的项的值增加1;
  • 接下来去扫描第二个字符串,当扫描到每个字符时,为哈希表对应的项的值减去1;
  • 如果扫描完第二个字符串后,哈希表中所有的值都是0,那么这两个字符串就互为变位词。

【举一反三】

如果需要判断 多个字符是不是在某个字符串里出现过 或者 统计多个字符在某个字符串中出现的次数,那么我们可以考虑 基于数组创建一个简单的哈希表,这样可以用很小的空间消耗换来时间效率的提升。

2. 题解

2.1 枚举 – O(n2)

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

解题思路】:
该题最直观的想法就是 从头开始扫描这个字符串中的每个字符。当访问到某字符时,拿这个字符和后面的每个字符相比较,如果字符串有 n 个字符,则每个字符可能与后面的 O(n) 个字符相比较,因此这种思路的时间复杂度是 O(n2)。
……
实现策略】:

  1. 双层循环遍历字符串,将每个字符都与字符串比较一遍;
  2. 通过变量 count 来记录当前字符在字符串中出现的次数,找出第一个无重复的字符后返回。
class Solution {// Solution1:枚举public char firstUniqChar(String s) {// 遍历每一个字符,寻找无重复的字符for (int i = 0; i < s.length(); i++){// 记录当前字符出现的次数int count = 0;char curr = s.charAt(i);for (int j = 0; j < s.length(); j++) {if (curr == s.charAt(j)) count++;}// 遍历完一遍字符串,如果count值为1,则返回if(count == 1) return curr;}// 没有无重复字符,返回单空格return ' ';}
}

在这里插入图片描述

2.2 哈希表 – O(n)

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

解题思路】:
题目与字符出现的次数有关,那么我们就可以通过哈希表来统计每个字符在该字符串中出现的次数。哈希表的键为字符,值为该字符出现的次数。
……
实现策略】:

  1. 定义哈希表 map
  2. 第一次遍历字符串,存入哈希表,用来统计该字符串中字符分别出现的个数;
  3. 第二次遍历字符串,从哈希表中找出 值为1的字符 返回。
class Solution {// Solution2:哈希public char firstUniqChar(String s) {// 定义哈希表HashMap<Character,Integer> map = new HashMap<>(); // 遍历一遍字符串,存入哈希表for (int i = 0; i < s.length(); i++){if (map.containsKey(s.charAt(i))) map.put(s.charAt(i),map.get(s.charAt(i)) + 1);else map.put(s.charAt(i),1);}// 第二次遍历字符串,找出第一个value值为1的返回for (int i = 0; i < s.length(); i++){if (map.get(s.charAt(i)) == 1) return s.charAt(i);}// 没有无重复字符,返回单空格return ' ';}
}

在这里插入图片描述

有序哈希表

解题思路】:
在哈希表的基础上,有序哈希表中的键值对是 按照插入顺序排序 的。基于此,可通过遍历有序哈希表,实现搜索首个 “数量为 1 的字符”。

Java 使用 LinkedHashMap 实现有序哈希表。 LinkedHashMap 底层借助哈希桶+双向链表,就是在hashmap的基础上通过双向链表维护元素节点间的顺序。如果想要查找效率快且维护插入顺序的话,用它就对啦,默认的就是按插入顺序排列。

class Solution {public char firstUniqChar(String s) {Map<Character, Boolean> dic = new LinkedHashMap<>();char[] sc = s.toCharArray();for(char c : sc)dic.put(c, !dic.containsKey(c));for(Map.Entry<Character, Boolean> d : dic.entrySet()){if(d.getValue()) return d.getKey();}return ' ';}
}

在这里插入图片描述

3. 参考资料

[1] 面试题50. 第一个只出现一次的字符(哈希表 / 有序哈希表,清晰图解)


http://www.ppmy.cn/news/39178.html

相关文章

ChatGPT背后有哪些关键技术?CSIG企业行带你一探究竟

目录1 ChatGPT的时代2 CSIG企业行3 议题&嘉宾介绍3.1 对生成式人工智能的思考3.2 对话式大型语言模型研究3.3 文档图像处理中的底层视觉技术4 观看入口1 ChatGPT的时代 2015年&#xff0c;马斯克、美国创业孵化器Y Combinator总裁阿尔特曼、全球在线支付平台PayPal联合创始…

对象的比较(数据结构系列12)

目录 前言&#xff1a; 1.PriorityQueue 1.1PriorityQueue的特性 1.2PriorityQueue的构造器 1.3大根堆的创建 1.4PriorityQueue中函数的说明 2.java中对象的比较 2.1基本类型的比较 2.2对象的比较 2.2.1覆写基类的equals 2.2.2基于Comparable接口类的比较 2.2.3基于…

vue3的setup的使用和原理解析

1.前言 最近在做vue3相关的项目&#xff0c;用到了组合式api&#xff0c;对于vue3的语法的改进也是大为赞赏&#xff0c;用起来十分方便。对于已经熟悉vue2写法的同学也说&#xff0c;上手还是需要一定的学习成本&#xff0c;有可能目前停留在会写会用的阶段&#xff0c;但是s…

信号与系统之《一文看懂傅里叶变换》

“傅里叶变换是一种非常有用的数学工具&#xff0c;它可以将一个复杂的信号分解成许多简单的频率成分。傅里叶变换在信号处理、图像处理、音乐、视频和通信等许多领域都有广泛的应用。相信大部分同学在毕业之后的一段时间之内都还没有理解到傅里叶变换的精髓&#xff0c;今天我…

INFINONE XC164单片机逆向记录(5)C166地址系统

本人所写的博客都为开发之中遇到问题记录的随笔,主要是给自己积累些问题。免日后无印象,如有不当之处敬请指正(欢迎进扣群 24849632 探讨问题); 写在专栏前面https://blog.csdn.net/Junping1982/article/details/129955766 INFINONE XC164单片机逆向记录(1)资料准备

SDL问题预测

0x00 前言 这里针对可能针对SDL的问题记录&#xff0c;当然很多内容不会直接公布&#xff0c;需要大家自己去探索&#xff0c;当然如果有一些问题也可以同步进行留言 0x01 问题 1.SDL是什么英文组成的 Software Develment Life Cycle 有些称为SDLC&#xff0c;有的说是SDL实…

【数据结构】特殊矩阵的压缩存储|保姆级详解+图解

作者&#xff1a;努力学习的大一在校计算机专业学生&#xff0c;热爱学习和创作。目前在学习和分享&#xff1a;算法、数据结构、Java等相关知识。博主主页&#xff1a; 是瑶瑶子啦所属专栏: 【数据结构】&#xff1a;该专栏专注于数据结构知识&#xff0c;持续更新&#xff0c…

Java 核心技术 - 异常处理机制

一、异常分类 Java 异常可以分为三类&#xff1a;受检查异常&#xff08;checked exception&#xff09;、运行时异常&#xff08;runtime exception&#xff09;和错误&#xff08;error&#xff09;。 受检查异常是在编译时就需要处理的异常&#xff0c;如果没有处理会导致…