leetcode刷题之哈希表的应用(1)

简介: leetcode刷题之哈希表的应用(1)

 

💕"study hard"💕

作者:Mylvzi

文章主要内容:leetcode刷题之哈希表的应用(1)

1.只出现一次的数字

 分析:

 核心就是在数组中找出现一次的数字,其实有很多思路,比如设计计数数组,比如使用Set不存储相同数据的特性来存储数据, 下面是用Set解题

public int singleNumber(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int x: nums) {
            if(set.contains(x)) {
                set.remove(x);
                continue;
            }
            set.add(x);
        }
        Object[] objects = set.toArray();
        return (int)objects[0];
    }

 其实如果你对异或运算熟悉,很容易想到这是利用异或来解决单身狗问题

public int singleNumber(int[] nums) {
                    int single = 0;
        for (int x: nums) {
            single ^= x;
        }
        return single;
        }

补充哈希表的思路:

public int singleNumber(int[] nums) {
        Map<Integer,Integer> map = new HashMap<>();
        for (int x:nums) {
            map.put(x, map.getOrDefault(x,0)+1);
        }
        for (int x:nums) {
            if(map.get(x) == 1) {
                return x;
            }
        }
        return -1;
    }

set的天然去重是指当你插入多个相同的值的时候,只会保留一个

在leetcode上一共有关于他的两个题目,都可以采用hashMap的方式解决

137. 只出现一次的数字 II - 力扣(LeetCode)

class Solution {
    public int singleNumber(int[] nums) {
        Map<Integer,Integer> map = new HashMap<>();
        for (int x:nums) {
            map.put(x, map.getOrDefault(x,0)+1);
        }
        for (int x:nums) {
            if(map.get(x) == 1) {
                return x;
            }
        }
        return -1;
    }
}

260. 只出现一次的数字 III - 力扣(LeetCode)

class Solution {
    public int[] singleNumber(int[] nums) {
        Map<Integer,Integer> map = new HashMap<>();
        for (int x:nums) {
            map.put(x, map.getOrDefault(x,0)+1);
        }
        List<Integer> list = new ArrayList<>();
        for (int x:nums) {
            if(map.get(x) == 1) {
                list.add(x);
            }
        }
        int[] ret = new int[2];
        for (int i = 0; i < ret.length; i++) {
            ret[i] = list.get(i);
        }
        return ret;
    }
}

2.随机链表的复制

138. 随机链表的复制 - 力扣(LeetCode)

 此题的难点在于不能直接拷贝原链表,直接拷贝会发生错乱的,只能拷贝val(直接拷贝会让你新的结点指向旧的结点),因为随机指针的存在,当我们拷贝节点时,「当前节点的随机指针指向的节点」可能还没创建,但是如果我们能建立旧结点和新节点的映射,就能很好的解决问题,所以本题使用hashMap

代码实现:

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;
    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
        public Node copyRandomList(Node head) {
            // return  head;
        HashMap<Node,Node> hashMap = new HashMap();
        Node cur = head;
        while (cur != null) {
            Node newNode = new Node(cur.val);
            hashMap.put(cur,newNode);
            cur = cur.next;
        }
        cur = head;
        while (cur != null) {
            hashMap.get(cur).next = hashMap.get(cur.next);
            hashMap.get(cur).random = hashMap.get(cur.random);
            cur = cur.next;
        }
        return hashMap.get(head);
    }
}

3.宝石与石头

771. 宝石与石头 - 力扣(LeetCode)

 此题最容易想到的就是暴力搜索,遍历字符串stone,遇到的每个字符都再去和jewels一一比较,但这样时间复杂度过高,有没有其他方法呢?

 使用set,先将jewels中的所有字符存储,再去遍历stones字符串,去判断set中是否包含对应的字符

代码实现

class Solution {
    public int numJewelsInStones(String jewels, String stones) {
        // 思路1:暴力搜索
        int cnt = 0;
        for (int i = 0; i < stones.length(); i++) {
            char ch = stones.charAt(i);
            for (int j = 0; j < jewels.length(); j++) {
                if (jewels.charAt(j) == ch) {
                    cnt++;
                }
            }
        }
        return cnt;
        // 思路2:使用set
        Set<Character> set = new HashSet<>();
        for (int i = 0; i < jewels.length(); i++) {
            set.add(jewels.charAt(i));
        }
        int cnt = 0;
        for (int i = 0; i < stones.length(); i++) {
            if(set.contains(stones.charAt(i))) {
                cnt++;
            }
        }
        return cnt;
    }
}

实际上这两种方式的时间复杂度相同(( ̄▽ ̄)")

当然还有大佬提供了一种"位运算的思路"

class Solution {
public:
    int numJewelsInStones(string jewels, string stones) {
        long long mask = 0;
        for (char c: jewels)
            mask |= 1LL << (c & 63);
        int ans = 0;
        for (char c: stones)
            ans += mask >> (c & 63) & 1;
        return ans;
    }
};

参考大佬链接:

分享|从集合论到位运算,常见位运算技巧分类总结! - 力扣(LeetCode)

4.前k个高频词

https://leetcode.cn/problems/top-k-frequent-words/submissions/

代码实现:

 

class Solution {
    public List<String> topKFrequent(String[] words, int k) {
        // 1.使用Map存储的单词--次数的映射关系  不涉及下标的使用foreach循环更快
        Map<String,Integer> map = new TreeMap<>();
        for (String word:words) {
            if (map.get(word) == null) {// 未被插入
                map.put(word,1);
            }else {
                int val = map.get(word);
                map.put(word,val+1);
            }
        }
        // 2.建立小根堆 top-k问题(频率从高到低)  这里使用了匿名内部类   是通过Comparator这个接口实现的  需要重写compare方法
        PriorityQueue<Map.Entry<String,Integer>> minheap = new PriorityQueue<>(new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                                // 频率相同  要根据字母顺序建立大根堆  输出的时候是要字母顺序小的在前  插入的时候虽然也是字母顺序小的进入 但是再一反转  字母顺序大的就跑前面了
                if(o2.getValue().compareTo(o1.getValue()) == 0) {
                    return o2.getKey().compareTo(o1.getKey());
                }
                return o1.getValue() - o2.getValue();
            }
        });
        // 3.遍历map  在queue中存储数据
        for (Map.Entry<String,Integer> entry: map.entrySet()) {
            // 堆排  现存前k个
            if(minheap.size() < k) {
                // 这里也有可能出现频率相同的数据  插入的时候要去判断字母顺序
                minheap.add(entry);
            }else {
                Map.Entry<String,Integer> top = minheap.peek();
                // 频率i相同  还要进一步判断字母顺序  字母顺序小的进来
                if(top.getValue().compareTo(entry.getValue()) == 0) {
                    if (top.getKey().compareTo(entry.getKey()) > 0) {
                        minheap.poll();
                        minheap.offer(entry);
                    }
                }else {// 频率不同  频率大的进来
                    if(top.getValue().compareTo(entry.getValue()) < 0) {
                        minheap.poll();
                        minheap.offer(entry);
                    }
                }
            }
        }
        List<String> ret = new ArrayList<>();
        for (int i = 0; i < k; i++) {
            ret.add(minheap.poll().getKey());
        }
        Collections.reverse(ret);
        return ret;
    }
}

另一种更简单的写法:将所有的比较逻辑使用匿名内部类和三目运算符解决

public List<String> topKFrequent(String[] words, int k) {
        Map<String, Integer> cnt = new HashMap<String, Integer>();
        for (String word : words) {
            cnt.put(word, cnt.getOrDefault(word, 0) + 1);
        }
        List<String> rec = new ArrayList<String>();
        for (Map.Entry<String, Integer> entry : cnt.entrySet()) {
            rec.add(entry.getKey());
        }
        // 排序的逻辑也很简单  谨记频率的大小是优先  频率相同再去考虑字母顺序
        // 先看频率是否相同  不同 直接返回频率的差值  i相同比较字典序
        Collections.sort(rec, new Comparator<String>() {
            public int compare(String word1, String word2) {
                return cnt.get(word1) == cnt.get(word2) ? word1.compareTo(word2) : cnt.get(word2) - cnt.get(word1);
            }
        });
        return rec.subList(0, k);
    }


目录
相关文章
|
2月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
3月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
113 2
|
18天前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
16 1
|
2月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
|
3月前
|
Python
【Leetcode刷题Python】50. Pow(x, n)
本文介绍了LeetCode第50题"Pow(x, n)"的解法,题目要求实现计算x的n次幂的函数,文章提供了递归分治法的详细解析和Python实现代码。
26 1
|
3月前
|
算法 Python
【Leetcode刷题Python】73. 矩阵置零
本文介绍了LeetCode第73题的解法,题目要求在给定矩阵中将所有值为0的元素所在的行和列全部置为0,并提供了一种原地算法的Python实现。
32 0
【Leetcode刷题Python】73. 矩阵置零
|
3月前
|
Python
【Leetcode刷题Python】1467. 两个盒子中球的颜色数相同的概率
本文介绍了LeetCode第50题"Pow(x, n)"的解法,题目要求实现计算x的n次幂的函数,文章提供了递归分治法的详细解析和Python实现代码。
40 0
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
56 6
|
3月前
|
Python
【Leetcode刷题Python】剑指 Offer 26. 树的子结构
这篇文章提供了解决LeetCode上"剑指Offer 26. 树的子结构"问题的Python代码实现和解析,判断一棵树B是否是另一棵树A的子结构。
50 4
|
3月前
|
索引 Python
【Leetcode刷题Python】从列表list中创建一颗二叉树
本文介绍了如何使用Python递归函数从列表中创建二叉树,其中每个节点的左右子节点索引分别是当前节点索引的2倍加1和2倍加2。
56 7