目录
刷题日期:下午8:27 2021年5月13日星期四
个人刷题记录,代码收集,来源皆为leetcode
经过多方讨论和请教,现在打算往Java方向发力
主要答题语言为Java
题目:
剑指 Offer 50. 第一个只出现一次的字符
难度简单96
在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
示例:
s = "abaccdeff"
返回 "b"
s = ""
返回 " "
限制:
0 <= s 的长度 <= 50000
题目分析
和前面那题找出最大不重复的字符有点像。
空格的处理还是第一次遇到,之前都是有内容或者直接为null的情况。
还是需要查找集合,尝试用哈希集合来解答。
初始解答:
算是伪代码吧,全都是错,思想讲道理是没问题的。
class Solution {
public char firstUniqChar(String s) {
if(s.charAt(0) == ' ') return ' ';
Set<Character> set = new set<>();
for(int i = 0; i < s.length; i++) {
char c = s.charAt(i);
while(set.contain(c)) {
set.remove(c);
}
set.add(c);
}
if(set.empty()) {
return ' ';
} else return set.head();
}
}
学习K神,还是用到了哈希表构造的字典
class Solution {
public char firstUniqChar(String s) {
HashMap<Character,Boolean> dit = new HashMap<>();
char[] sc = s.toCharArray(); //字符串转字符组
for(char c : sc) { //遍历一遍,只出现一遍的都是真
dit.put(c, !dit.containsKey(c));
}
for(char c : sc) {
if(dit.get(c)) return c; //遍历,第一个为真的直接输出
}
return ' '; //没有则空格
}
}
执行结果:通过
显示详情 添加备注
执行用时:37 ms, 在所有 Java 提交中击败了20.69%的用户
内存消耗:38.5 MB, 在所有 Java 提交中击败了91.97%的用户
第二种提高效率:
class Solution {
public char firstUniqChar(String s) {
Map<Character,Boolean> dit = new LinkedHashMap<>(); //有序哈希表
char[] sc = s.toCharArray(); //字符串转字符组
for(char c : sc) { //遍历一遍,只出现一遍的都是真
dit.put(c, !dit.containsKey(c));
}
for(Map.Entry<Character, Boolean> d : dit.entrySet()) {
if(d.getValue()) return d.getKey(); //操作没见过
}
return ' '; //没有则空格
}
}
是快了些,执行结果:通过
显示详情 添加备注
执行用时:27 ms, 在所有 Java 提交中击败了52.90%的用户
内存消耗:38.7 MB, 在所有 Java 提交中击败了75.31%的用户
还有人用数组解的:
class Solution {
public char firstUniqChar(String s) {
if (s.equals("")) return ' '; //正确的比较方法,注意引号的区别
int[] dit = new int[26]; //小写字母,26个就够了
//巧妙在于小写字母还能这样相减
for(int i = 0; i < s.length(); i++) { //遍历一遍,只出现一遍的都计数
dit[s.charAt(i) - 'a']++;
}
for(int i = 0; i < s.length(); i++) {
if(dit[s.charAt(i) - 'a'] == 1) return s.charAt(i); //只出现一次的字符
}
return ' '; //没有则空格
}
}
显然这种方法直观又更简单,妙啊,执行结果:通过
显示详情 添加备注
执行用时:7 ms, 在所有 Java 提交中击败了87.35%的用户
内存消耗:38.4 MB, 在所有 Java 提交中击败了95.97%的用户
学习他人:
方法一:
恩L1 2020-02-21 JAVA 字典查找
执行用时 : 7 ms , 在所有 Java 提交中击败了 94.58% 的用户
内存消耗 : 41.5 MB , 在所有 Java 提交中击败了 100.00% 的用户
public char firstUniqChar(String s) {
if (s.equals("")) return ' ';
//创建‘a'-'z'的字典
int[] target = new int[26];
//第一次遍历,将字符统计到字典数组
for (int i = 0; i < s.length(); i++) {
target[s.charAt(i) - 'a']++;
}
//第二次遍历,从字典数组获取次数
for (int i = 0; i < s.length(); i++) {
if (target[s.charAt(i) - 'a'] == 1) return s.charAt(i);
}
return ' ';
}
方法二:
yxhL1 2020-04-21 java
class Solution {
public char firstUniqChar(String s) {
for (int i = 0; i < s.length(); i++) {
char ch=s.charAt(i);
//首次出现的位置是当前位置,且后面没有再出现这个字符
if(s.indexOf(ch)==i&&s.indexOf(ch,i+1)==-1)
return s.charAt(i);
}
return ' ';
}
}
方法三:
pinyuan (编辑过)2020-07-11 打卡, 方法1:使用LinkedHashMap.
class Solution {
public char firstUniqChar(String s) {
char cs = ' ';
if(s == null || s.length() == 0) return cs;
HashMap<Character, Integer> map = new LinkedHashMap<>(); // 采用LinkedHashMap保证顺序性
for(int i = 0;i < s.length();i++){
char c = s.charAt(i);
if(map.containsKey(c)){
map.put(c, map.get(c) + 1);
}
else
map.put(c, 1);
}
for(char key : map.keySet()){
if(map.get(key) == 1)
return key;
}
return cs;
}
}
方法2:使用HashMap
class Solution {
public char firstUniqChar(String s) {
if(s == null || s.length() == 0) return ' ';
HashMap<Character, Integer> map = new HashMap<>();
for(int i = 0;i < s.length();i++){
char c = s.charAt(i);
if(map.containsKey(c)){
map.put(c, map.get(c) + 1);
}
else
map.put(c, 1);
}
for(int i = 0;i < s.length();i++){
if(map.get(s.charAt(i)) == 1){
return s.charAt(i);
}
}
return ' ';
}
}
方法3:使用count计数
class Solution {
public char firstUniqChar(String s) {
if(s == null || s.length() == 0) return ' ';
int[] count = new int['z' - 'a' + 1]; //因为s只包含了小写字母
for(int i = 0;i < s.length();i++){
count[s.charAt(i) - 'a'] ++;
}
for(int i = 0;i < s.length();i++){
if(count[s.charAt(i) - 'a'] == 1)
return s.charAt(i);
}
return ' ';
}
}
方法四:
越来越好🐽 🐖 🐗L1 2021-02-06 使用引用计数,效率高
class Solution {
public char firstUniqChar(String s) {
if (s == null || s.length() == 0) return ' ';
char[] chars = s.toCharArray();
int[] arr = new int[123];
for (int i = 0; i < chars.length; i++) {
arr[chars[i]]++;
}
for (char aChar : chars) {
if (arr[aChar] == 1) return aChar;
}
return ' ';
}
}
方法五
K神: 本题考察 哈希表 的使用,本文介绍 哈希表 和 有序哈希表 两种解法。其中,在字符串长度较大、重复字符很多时,“有序哈希表” 解法理论上效率更高。
作者:jyd
链接:https://leetcode-cn.com/problems/di-yi-ge-zhi-chu-xian-yi-ci-de-zi-fu-lcof/solution/mian-shi-ti-50-di-yi-ge-zhi-chu-xian-yi-ci-de-zi-3/
来源:力扣(LeetCode)
方法一:哈希表
遍历字符串 s ,使用哈希表统计 “各字符数量是否 > 1>1 ”。
再遍历字符串 s ,在哈希表中找到首个 “数量为 11 的字符”,并返回。
class Solution {
public char firstUniqChar(String s) {
HashMap<Character, Boolean> dic = new HashMap<>();
char[] sc = s.toCharArray();
for(char c : sc)
dic.put(c, !dic.containsKey(c));
for(char c : sc)
if(dic.get(c)) return c;
return ' ';
}
}
方法二:有序哈希表
在哈希表的基础上,有序哈希表中的键值对是 按照插入顺序排序 的。基于此,可通过遍历有序哈希表,实现搜索首个 “数量为 1 的字符”。
哈希表是 去重 的,即哈希表中键值对数量≤ 字符串 s 的长度。因此,相比于方法一,方法二减少了第二轮遍历的循环次数。当字符串很长(重复字符很多)时,方法二则效率更高。
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 ' ';
}
}
总结
以上就是本题的内容和学习过程了,最近的题目都离不开哈希表,当时在看数据结构时把这一部分都跳过去了,看了也是机试考察的重点,有时间了还是回去多翻翻看看。
不过数组的解法也很巧妙,才知道字符也可以用这种方式得到差值。
欢迎讨论,共同进步。