[String] The first non-repeated character in the character stream

Title description

Please implement a function to find the first character that appears only once in the character stream. For example, when the first two characters "go" are read only from the character stream, the first character that appears only once is "g". When reading the first six characters "google" from the character stream, the first character that appears only once is "l".
Return value description: If there is no character that appears once in the current character stream, the # character is returned.


Hashing

The first method I thought of is hashing, which uses a hash table to store the information of each character. The character is used as the key, and the value format is min_index num, that is, the subscript of the character's earliest appearance and the number of times it appears. Each time a character is inserted, it is judged whether the character is included in the hash table, and if it is included, the number of occurrences of it is increased by one, otherwise the character is added to the hash table. Use resultvariables to store the first character that appears. If the currently inserted character is the resultsame or result='#'you need to traverse the hash table to find the first unique character

import java.util.HashMap;
public class Solution {
    
    
    String str = "";
    int index = 0; // 字符数量
    // value: char_index char_num
    HashMap<String, String> hashMap = new HashMap<>();
    String result = "";

    //Insert one char from stringstream
    public void Insert(char ch) {
    
    
        str += ch;
        String s = String.valueOf(ch);
        if (hashMap.containsKey(s)) {
    
    
            String value = hashMap.get(s);
            int num = Integer.parseInt(value.split(" ")[1]) + 1;
            hashMap.put(s, value.split(" ")[0] + " " + num);
        } else {
    
    
            hashMap.put(s, index + " " + 1);
        }
        index++;
        if (s.compareTo(result) == 0 || result.length() == 0 || result == "#") {
    
    
            // 上一次的结果需要修改
            result = "#";
            int min_index = Integer.MAX_VALUE;
            for (String key : hashMap.keySet()) {
    
    
                String value = hashMap.get(key);
                int ind = Integer.parseInt(value.split(" ")[0]);
                int num = Integer.parseInt(value.split(" ")[1]);
                if (num == 1 && ind < min_index) {
    
    
                    min_index = ind;
                    result = key;
                }
            }
        }
    }
    //return the first appearence once char in current stringstream
    public char FirstAppearingOnce() {
    
    
        return result.charAt(0);
    }
}

This method beats 88% of the code in time

Optimization plan 1

On the basis of the above method, some optimizations can be made. The value of the hash table of the above method stores the earliest position of the character and the number of times it appears. We can directly store the number of times the character appears, and then traverse the string to determine the character Whether the number of occurrences of is 1, if it is 1, return directly to get the earliest non-repeated character, and there is no need to store the position of the character.

When inserting a character, there are two situations. The first is that the character is not included in the hash table. This is a new character. If result='#'there is no non-repeating character at this time, the new character will be directly used as the first non-repeating character. If the first non-repeated character already exists, no processing will be done, and the result will not change; the second case is that the character is already included in the hash table, which is a repeated character. If the repeated character is before If yes result, it can no longer be used result, we will resultset #it to let the program re-traverse the string to find the first non-repeated character.

import java.util.HashMap;

public class Solution {
    
    
    String str = "";
    // value: char_index char_num
    HashMap<Character, Integer> hashMap = new HashMap<>();
    char result = '#';

    //Insert one char from stringstream
    public void Insert(char ch) {
    
    
        str += ch;
        if (!hashMap.containsKey(ch)) {
    
    
        	// 这是一个新字符
            hashMap.put(ch, 1);
            if (result == '#')
                result = ch; // 此时没有不重复的字符,就将新字符作为result
        } else {
    
    
        	// 这是一个重复字符
            hashMap.put(ch, hashMap.get(ch) + 1);
            if (ch == result)
                result = '#'; // 如果它之前是第一个不重复的字符,那么现在它已经重复了
            if (result == '#') {
    
    
                for (int i = 0; i < str.length(); i++) {
    
    
                    if (hashMap.get(str.charAt(i)) == 1) {
    
    
                        result = str.charAt(i);
                        return;
                    }
                }
            }
        }
    }

    //return the first appearence once char in current stringstream
    public char FirstAppearingOnce() {
    
    
        return result;
    }
}

This method beats 98% of the code in time

Optimization plan 2

We need to find the first non-repeating character, but there may be many non-repeating characters in the string, so in addition to finding the non-repeating characters, we also need to store the priority (order of appearance) of the characters. Here we can use the queue to store For non-repeated characters, the head of the queue is the first non-repeated character. In addition, the number of occurrences of characters needs to be stored. Considering that there are only 128 characters (), in addition to using a hash table, an array can also be used to store the number of occurrences of each character, and the ASCII code of the character is used as the array subscript.

Insert function: When inserting a character, add 1 to the number of occurrences of the character. If the character is a new character, add it to the queue.

FirstAppearingOnce: When looking for the first unique character, traverse the queue to determine whether the number of occurrences of the head element is 1, if it is 1, it will return directly, otherwise it will be removed from the queue, because this character has been repeated, and Will not be added to the queue in the future.

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;

public class Solution {
    
    
    Queue<Character> queue = new LinkedList<>();
    char count[] = new char[128]; // 存储字符出现的次数

    //Insert one char from stringstream
    public void Insert(char ch) {
    
    
        count[ch]++; // 字符出现次数加一
        if (count[ch] == 1)
            queue.add(ch); // 若这个字符只出现了一次,则把它添加到队列中
    }

    //return the first appearence once char in current stringstream
    public char FirstAppearingOnce() {
    
    
        char result = '#';
        while (!queue.isEmpty()) {
    
    
            if (count[queue.peek()] == 1)
                return queue.peek();
            queue.remove(); // 这是一个重复的字符,删除
        }
        return result;
    }
}

This method beats 94% of the code in time, and the performance is similar to that of method 2, and the idea is more concise and clever

Guess you like

Origin blog.csdn.net/weixin_43486780/article/details/113867817