文章目录

    • 面试题50-I 第一个只出现一次的字符
    • 面试题50-II 字符流中第一个不重复的字符

面试题50-I 第一个只出现一次的字符

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

示例:

s = "abaccdeff"
返回 "b"

s = "" 
返回 " "

题解:

模式识别:涉及次数要考虑用哈希表,一般字符为key,下标为值(或依据题意为其它)。

具体步骤:
在这里插入图片描述
代码:

class Solution {
public:
    char firstUniqChar(string s) {
        map<char,int> hashmap;
        for(char val:s){
            if(hashmap.find(val)==hashmap.end()) hashmap[val]=1;
            else hashmap[val]++;
        }
        for(char val:s){
            if(hashmap[val]==1) return val;
        }
        return ' ';

    }
};
class Solution {
    public char firstUniqChar(String s) {
        HashMap<Character , Integer> map = new HashMap<>();
        char[] c = s.toCharArray();
        for(char val : c){
            if(!map.containsKey(val)) map.put(val , 1);
            else map.put(val , map.get(val) + 1);
        }

        for(char val : c){
            if(map.get(val) == 1) return val;
        }
        return ' ';
    }
}

在这里插入图片描述
时间复杂度 O(N)
空间复杂度 O(1)

面试题50-II 字符流中第一个不重复的字符

题目:
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。

返回值描述:
如果当前字符流没有存在出现一次的字符,返回#字符。

题解(哈希+队列):
题解:
具体参考这:参考

针对题目的描述,我们先提出两个问题?

Q1. 给定一个字符串(只不过这里的字符串是可变的),如果快速判断一个字符是否存在于字符串中,如果存在,也就是重复?
Q2. 这里先不考虑重复,如果快速返回第一个字符?有没有感觉有点像先来先服务?

对于一道题,如果没有思路,就要针对题目给自己问问题。然后针对问题,来考虑需要什么样的算法或者数据结构。

A1:对于“重复问题”,惯性思维应该想到哈希或者set。对于“字符串问题”,大多会用到哈希。因此一结合,应该可以想到,判断一个字符是否重复,可以选择用哈希,在c++中,可以选择用unordered_map<char, int>

A2:对于字符流,源源不断的往池子中添加字符,然后还要返回第一个满足什么条件的字符,显然设计到了“顺序”,也就是先来的先服务,这种先进先出的数据结构不就是队列嘛。因此,这里可以用队列。

假如你已经知道了要用hash 和 queue 这两个数据结构,你可以试着自己想一想,接下来的算法过程是怎么样的?
这里我提供一个算法过程,如下:

1、初始化一个unordered_map<char, int> mp, queue q

2、对于Insert(char ch)操作, 如果ch是第一次出现,则添加到q中,然后在mp中记录一下次数,如果不是第一次出现,也就是重复了,那么我们就没必要添加到q中,但是还是需要在mp中更新一下次数,因为之后要根据次数来判断是否重复。

3、对于FirstAppearingOnce()操作,我们直接判断q的头部,然后在mp中检查一下,是否重复,如果没有重复,那就是我们想要的数据。否则,如果重复了,那就应该弹出头部,然后判断下一个头部是否满足要求。
因为队列中存储的 “不重复字符” 在一系列的流读取操作后,随时有可能改变状态(变重复),所以,队列中的字符不能直接输出,要先进行一次重复判断,如果发现队头字符已经重复了,就将它移出队列并判断新的队头,否则,输出队头的值;
代码:

class Solution
{
public:
    map<char, int> hashmap;
    queue<int> q;
  //Insert one char from stringstream
    void Insert(char ch)//字符流肯定是要一个一个的输入的,所以要有Insert()操作;
    {
        if(hashmap.find(ch)==hashmap.end()) q.push(ch);
        hashmap[ch]++;
    }
  //return the first appearence once char in current stringstream
    char FirstAppearingOnce()
    {
        while(!q.empty()){
            char ch=q.front();
            if(hashmap[ch]==1) return ch;
            else q.pop();
        }
        return '#';
    }

};

java

import java.util.*;
public class Solution {
    //Insert one char from stringstream
    HashMap<Character , Integer> map = new HashMap<>();
    //Queue<Integer> q = new Queue<>(); 
    Queue<Character> q = new LinkedList<Character>();
    public void Insert(char ch)
    {
        if(!map.containsKey(ch)){
            q.add(ch);
            map.put(ch , 1);
        }
        else map.put(ch , map.get(ch) + 1);
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        while(!q.isEmpty()){
            char c = q.peek();
            if(map.get(c) == 1) return c;
            else q.remove();
        }
        return '#';
    }
}

时间复杂度O(N):对于Insert(char ch)操作,为O(1), 对于FirstAppearingOnce()操作,为O(N),因为最坏情况下,队列中存入一半的重复数据, 比如“abcdabcd”,队列会存入“abcd”,并且弹出的时候都是重复的。

空间复杂度:O(N),创建了哈希表和队列

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐