D15 LeetCode 432.全O(1)的数据结构(困难)

一、题目

class AllOne {

    public AllOne() {

    }
    
    public void inc(String key) {

    }
    
    public void dec(String key) {

    }
    
    public String getMaxKey() {

    }
    
    public String getMinKey() {

    }
}

/**
 * Your AllOne object will be instantiated and called as such:
 * AllOne obj = new AllOne();
 * obj.inc(key);
 * obj.dec(key);
 * String param_3 = obj.getMaxKey();
 * String param_4 = obj.getMinKey();
 */

 二、思路(自己)

  • 这个题目我感觉并不难,就是设计一个数据结构和它的函数,但是其实有点难理解的是它的题意。比如输入代表什么意思,还有就是字符串key的计数是什么意思?这里我绕了好大的弯,getMaxKey返回任意一个计数最大的字符串?(挺打脸的,它要求时间复杂度为O(1)))
  • 我代码写完执行出错才发现原来我理解错意思了,其实它的计数指的是AllOne中该字符串的个数,我理解为该字符串的比较大小了。如下为我的错误代码:
class AllOne {
    List<String> list=new ArrayList<>();


    public AllOne() {

    }

    public void inc(String key) {
        list.add(key);
    }

    public void dec(String key) {
        list.remove(key);
        if(list.size()==0) list.clear();
    }

    public String getMaxKey() {
        if(this.list.size()==0) return "";
        String s="";
        for (int i = 0; i <list.size(); i++) {
            if(compare(this.list.get(i),s)>0){
                s=list.get(i);
            }
        }
        return s;
    }

    public String getMinKey() {
        if(this.list.size()==0) return "";
        String s=list.get(0);
        for (int i = 0; i <list.size(); i++) {
            if(compare(this.list.get(i),s)<0){
                s=list.get(i);
            }
        }
        return s;
    }
     static int compare(String s1,String s2){
        if(s1.length()>s2.length()) return 1;
        if(s1.length()<s2.length()) return -1;
        else {
            return s1.compareTo(s2);
        }
     }

}


/**
 * Your AllOne object will be instantiated and called as such:
 * AllOne obj = new AllOne();
 * obj.inc(key);
 * obj.dec(key);
 * String param_3 = obj.getMaxKey();
 * String param_4 = obj.getMinKey();
 */
  • 比较有意思的是居然还通过了10个测试用例
  • 懂题目意思了其实就不难了,因为之前也做过类似的题目。但是,我犯了个小错误,弄得我一直提交之后解答出错。
    class AllOne {
     //   List<String> list=new ArrayList<>();
        Map<String,Integer> map=new HashMap<>();
    
    
        public AllOne() {
    
        }
    
        public void inc(String key) {
            if(this.map.containsKey(key))
                this.map.put(key,this.map.get(key)+1);
            else
                this.map.put(key,1);
        }
    
        public void dec(String key) {
            if(this.map.containsKey(key)){
                this.map.put(key,this.map.get(key)-1);
            if(this.map.get(key)==0) map.remove(key);
            }
        }
        Comparator<Map.Entry<String,Integer>> com=new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                return o1.getValue()-o2.getValue();
            }
        };
    
        public String getMaxKey() {
            if(this.map.size()==0) return "";
            //又是按照map的值取key,之前做过
            List<Map.Entry<String,Integer>> list=new ArrayList<>(this.map.entrySet());
            Collections.sort(list,com);
            return list.get(list.size()-1).getKey();
        }
    
        public String getMinKey() {
            if(this.map.size()==0) return "";
            List<Map.Entry<String,Integer>> list=new ArrayList<>(this.map.entrySet());
            Collections.sort(list,com);
            return list.get(0).getKey();
        }
    }

    最后还是未通过,为什么呢,时间复杂度高了

  • 我记得我之前做过类似的题,是用set去重好像,但是具体怎么用我还是忘记了。。。我去翻翻以前的笔记。。。找不见了,估计那时候还没开始写博客

三、题解(官方)

  • 题目要求O(1)的时间复杂度
  • 我看了评论区宫水三叶的答案,真厉害,是自己写一个哈希表来实现时间复杂度
  • 定义节点类,用来存储字符串出现的次数
  • 以下为代码和注释,挺好理解的
    class AllOne{
        //定义节点类用来作为哈希表的数组部分
        class Node{
            int cnt;//字符串出现的次数
            Set<String> set=new HashSet<>();//次数为cnt的字符串
            Node left,right;//链表前后元素
            Node(int _cnt){
                cnt=_cnt;
            }
        }
    
        Node hh,tt;
        //记录输入的节点,减少遍历来查找
        Map<String,Node> map=new HashMap<>();
        public AllOne(){
            //初始化双链表
            hh=new Node(-1000);tt=new Node(-1000);
            hh.right=tt; tt.left=hh;
        }
    
        void  clear(Node node){
            if(node.set.size()==0){
                //如果node中没有字符串了,那么就把它消掉
                node.left.right=node.right;
                node.right.left=node.left;
            }
        }
    
        public void inc(String key){
            //如果之前已经存储过现在输入的字符串
            if(map.containsKey(key)){
                //取出哈希表数组部分的节点
                Node node=map.get(key);
                //因为该字符串数量加一,所以不能待在哈希表这个数组部分
                node.set.remove(key);
                int cnt=node.cnt;
                Node next=null;
                if(node.right.cnt==cnt+1){
                    //如果数量加一后为后面那个数组部分的数量,则将其放到下一个节点的位置
                    next=node.right;
                }else {
                    //没有对应数量的节点,且后面的那个节点一定大于加一,将节点插入到刚才所在节点后面
                    next=new Node(cnt+1);
                    next.right=node.right;
                    next.left=node;
                    node.right.left=next;
                    node.right=next;
                }
                next.set.add(key);
                //记录加入节点和位置
                map.put(key,next);
                clear(node);
            }else {//如果之前没有存储过这个字符串,那么该字符串数量为1
                Node node=null;
                if(hh.right.cnt==1){
                    node=hh.right;//之前存在数量为1的字符串
                }else {//没有数量为1的字符串,插入
                    node=new Node(1);
                    node.right=hh.right;
                    node.left=hh;
                    hh.right.left=node;
                    hh.right=node;
                }
                node.set.add(key);//把字符串放入node中
                map.put(key,node);
            }
        }
    
        public void dec(String key){
            Node node=map.get(key);//找出key对应的节点位置
            node.set.remove(key);
            int cnt=node.cnt;
            if(cnt==1){
                map.remove(key);
            }else {
                Node prev=null;
                if(node.left.cnt==cnt-1){
                    prev=node.left;
                }else {
                    prev=new Node(cnt-1);
                    prev.right=node;
                    prev.left=node.left;
                    node.left.right=prev;
                    node.left=prev;
                }
                prev.set.add(key);
                map.put(key,prev);
            }
            clear(node);
        }
        
        public String getMaxKey(){
            Node node=tt.left;
            for(String str:node.set) return str;
            return "";
        }
        
        public String getMinKey(){
            Node node=hh.right;
            for(String str:node.set) return str;
            return "";
        }
    }
    
    /**
     * Your AllOne object will be instantiated and called as such:
     * AllOne obj = new AllOne();
     * obj.inc(key);
     * obj.dec(key);
     * String param_3 = obj.getMaxKey();
     * String param_4 = obj.getMinKey();
     */

    继续加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值