Problem 2 First Non-Repeating Characters

  • use case: O(1) time + first

  • 关键词,first: 必须keep时序

  • O(1) time: Map(Key: Character, Value: ListNode) + DLL as Queue

  • 这和LRU的区别点是什么?

    • 识别那些character是non repeating,

    • 一个字母已经出现了2次vs这个字母一次都没有出现---》你怎么知道踢了vs还是放进去

Option 1: double linkedlist + map + set

API 1: new coming character:

  • double linkedlist==> 最快做删除 ==> 找到自己就能找到前一个和后一个==> 添加和删除都是O(1)的时间

  • Look up operation ==> Map<Character, ListNode> ==> 很快找到ListNode ==> Set<Character>==> help determine repeat

  • 分析

    • case 1先确认这个字母在不在set里,如果存在,直接ignore

    • case 2如果不在set里面

      • case2.1再看map,如果这个字母不在map里面

        • 这是我们第一次遇到这个字母,update Map + DLL

      • case2.2如果这个字母在map里面

        • 说明这个字母发生了重复,remove it from Map +DLL, add it to repeating set

API 2: who is the first?

  • 看看你define的DLL里哪一段是代表时间序列

// Some code

public class Solution{
    static class Node {
        Node prev;
        Node next;
        Character ch;
        Node(Character ch) {
            this.ch;
        }
    }
    private Node head;
    private Node tail;
    private Set<Character> repeated;
    private Map<Character, Node> singled;
    public Solution() {
        head =  new Node(null);
        head.prev = head.next = head;
        tail = head;
        repeated = new HashSet<>();
        singled = new HashMap<>();
    }
    public void read(char ch){
        // if the character already exists more than once ==> ignore
        if (repeated.contains(ch)) {
            return;
        }
        
        Node node = singled.get(ch);
        // if the character appears for the first time ==> add to the list and the nonrepeated 
        if (node == null) {
            node = new Node(ch);
            append(Node);
        }
        // if the character is already in the nonrepeated ==> remove it from the map and list
        // put it into the repeat set
        else {
            remove(Node);
        }
    }
    private void append(Node node){
        // append to map
        // append to the DLL
        singled.put(node.ch, node);
        tail.next = node;
        node.prev = tail
        node.next = head;
        tail = tail.next;
    }
    
    
    private void remove(Node node) {
        // remove from the map
        // add to repeat set
        // remove from DLL
        node.prev.next = node.next;
        node.next.prev = node.prev;
        if (node == tail) {
            tail = node.prev;
        }
        node.prev = node.next = null;
        singled.remove(node.ch);
        repreated.add(node.ch);
        
    }
    
    private Character firstNonRepeating() {
        if (head == tail) {
            return null;
        }
        return head.next.ch;
    }
}

Option 2: double linkedlist + map

API 1: new coming character:

  • double linkedlist==> 最快做删除 ==> 找到自己就能找到前一个和后一个==> 添加和删除都是O(1)的时间

  • Look up operation ==> Map<Character, ListNode> ==> 很快找到ListNode ==> Set<Character>==> help determine repeat

  • 分析

    • case 1先确认这个字母在不在map里

      • 如果存在对用的是reference node 是null,直接ignore

    • case 2如果不在set里面

      • case2.1再看map,如果这个字母不在map里面

        • 这是我们第一次遇到这个字母,如果这个字母不在map里面

      • case2.2如果这个字母在map里面

        • 如果是多次出现的字母,map里存的是这个字母的marker(mark this character already repeat)

          • use Null as special value

API 2: who is the first?

  • 看看你define的DLL里哪一段是代表时间序列

// Some code
public class Solution{
    static class Node {
        Node prev;
        Node next;
        Character ch;
    }
    Node(Character ch) {
        this.ch = ch;
    }
    private Node head;
    private Node tail;
    private Map<Character, Node> map;
    
    public Solution{
        head = new Node(null);
        head.prev = head.next = head;
        tail = head;
        map = new HashMap<>();
    }
    public void read(char ch) {
        // case 1
        if (!map.containsKey(ch)) {
            Node node = new Node(ch);
            append(Node);
        }
        // case 2.2
        else if (map.get(ch) != null) {
            remove(map.get(ch));
        }
        // case 2.1, 2nd timt to see ==> do nothing
    }
    private void append(Node node) {
        map.put(node.ch, node);
        tail.next = node;
        node.prev = tail;
        node.next = head;
        tail = tail.next;
    }
    private void remove(Node node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
        if (node == tail) {
            tail = node.prev;
        }
        node.prev = node.next = null;
        map.put(node.ch, null);
    }
    public Character firstNonRepeating() {
        if (head == tail) {
            return null;
        }
        return head.next.ch;
    }
}

Last updated