❤️导图整理大厂面试高频数组6:四数组的四数之和,详解Counter类实现哈希表计数,力扣454❤️

孤柒「一起学计算机」
算法领域优质创作者
2021-11-09 15:54:35
加精

原文链接 https://mp.csdn.net/mp_blog/creation/editor/117036308

此专栏文章是对力扣上算法题目各种方法总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解.

目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), 毕竟算法不是做了一遍就能完全记住的. 所以本文适合已经知道解题思路和方法, 想进一步加强理解和记忆的朋友, 并不适合第一次接触此题的朋友(可以根据题号先去力扣看看官方题解, 然后再看本文内容).

关于 本专栏所有题目的目录链接 https://leetcode-cn.com/problems/two-sum/solution/suo-you-ti-jie-de-mu-lu-lian-jie-si-wei-ecnoo/ , 刷算法题目的顺序/注意点/技巧, 以及思维导图源文件问题请点击 此链接 https://mp.weixin.qq.com/s/ICc5JhLiL1pC3mbEz6nCIA .

想进大厂, 刷算法是必不可少的, 欢迎和博主一起打卡刷力扣算法! 博主同步更新了算法视频讲解, 更易于理解, 不想看文章的 _ 欢迎来看 https://space.bilibili.com/37854237 _!

关注博主获得题解更新的最新消息!!!

@[TOC]

[TOC]

题目链接: https://leetcode-cn.com/problems/4sum-ii/solution/si-wei-dao-tu-zheng-li-xiang-jie-counter-nw0f/

0.导图整理

1.维数太高, 分治处理

此题乍一看似乎和 四数之和 https://mp.weixin.qq.com/s/LqwK83EVZ7Xim44lHATXuA 差不多, 但是本质上却有着很大的区别, 首先无论是 三数之和 https://mp.weixin.qq.com/s/LqwK83EVZ7Xim44lHATXuA 还是 四数之和, 它们都是在一个数组上的操作, 本质上都是一维的, 同时它们都要求找到 不重复 的元组, 这就限制了我们不能简单的使用哈希表进行去重操作, 最终只能将数组排序后使用双指针的方法.

但是本题是 四个独立的数组, 相当于是 四个维度, 想在四个维度上使用双指针的方法显然是不现实的. 同时此题只要求我们找到所有4个元素的和为0的元组个数即可, 并没有要求是不重复的元组, 这样就简单了很多, 也是可以使用哈希表的方法的.

此题在使用哈希表的时候, 会遇到如下的三种情况:

1.HashMap存一个数组,如A。然后计算三个数组之和,如BCD。时间复杂度为:O(n)+O(n^3),得到O(n^3).

2.HashMap存三个数组之和,如ABC。然后计算一个数组,如D。时间复杂度为:O(n^3)+O(n),得到O(n^3).

3.HashMap存两个数组之和,如AB。然后计算两个数组之和,如CD。时间复杂度为:O(n^2)+O(n^2),得到O(n^2).

根据时间复杂度来看, 我们肯定选择第三种情况.

确定了使用的方法(哈希表)以及分类的方法(两两分组), 接下来就是代码的书写了. 此题和 两数之和 https://mp.weixin.qq.com/s/Igo3Ilvj758ilaZiNXT28w 中使用的哈希表有着很大的区别, 在两数之和中, 我们需要的是满足条件的下标值, 所以在哈希表中的值存取的就是元组的下标值, 这点是很容易实现的. 但是在此题中我们需要的是所有满足元素的个数, 所以哈希表中的值应存取出现的次数. 这相对于只存下标是有点难度的. 这就涉及到下文要讲的几个方法和类了.

2.Java中map的merge和getOrDefault方法

统计出现的次数, 在java中可以使用map类中的两个方法进行实现.

一种是countAB.put(u + v, countAB.getOrDefault(u + v, 0) + 1), 这里比较重要的是getOrDefault(u + v, 0)方法, 它的含义是获得键u + v对应的值, 也就是出现的次数, 如果当然哈希表中未出现, 则返回默认值0. 通过后面的+1操作, 实现在现有次数上+1或者初始化次数为1, 然后将这个键值对放入到哈希表中.

另一种方法是countAB.merge(u+v, 1, (old,new_)->old+1), 这里使用了merge方法, 从名字就可以看出是 合并 的意思, 也就是将新出现的键值对和原来已有的键值对进行合并, 形成新的键值对. 中间的1表示如果原来没有此键值对, 那么这个新键值对的值就是1(出现次数为1次). 最后的参数表示了新的值的相对于旧的值的变化情况, 这里就是+1的操作. 有一点要主要的是new_有个下划线, 因为在java中new是创建对象的关键词, 这里是为了区别开来. 这个函数的语法就是上文所示那样, 具体的操作情况都可以根据实际来更改.

3.Python中的Counter类

在Python中哈希表是利用dict()字典来实现的, 但毕竟不是专为哈希表设计的类, 也没有那么丰富的方法来使用. 但是Python中直接设计了能够对哈希对象进行计数的类, 并且在功能上更加优秀, 下面我们重点介绍一下这个类.

3.1 简介

1.一个 Counter 是一个 dict 的子类, 用于计数可哈希对象。它是一个集合, 元素像字典键(key)一样存储, 它们的计数存储为值。计数可以是任何整数值, 包括0和负数.

2.通常字典方法都可用于 Counter 对象,除了有两个方法工作方式与字典并不相同
fromkeys(iterable)这个类方法没有在 Counter 中实现
update([iterable-or-mapping]是在原有的键值对上加上,而不是替换

sum(c.values())                 # total of all counts
c.clear()                       # reset all counts
list(c)                         # list unique elements
set(c)                          # convert to a set
dict(c)                         # convert to a regular dictionary
c.items()                       # convert to a list of (elem, cnt) pairs
Counter(dict(list_of_pairs))    # convert from a list of (elem, cnt) pairs
c.most_common()[:-n-1:-1]       # n least common elements
+c                              # remove zero and negative counts

3.2 初始化

元素从一个 iterable 被计数或从其他的 mapping (or counter)初始化

c = Counter()                           # a new, empty counter
c = Counter('gallahad')                 # a new counter from an iterable
c = Counter({'red': 4, 'blue': 2})      # a new counter from a mapping
c = Counter(cats=4, dogs=8)             # a new counter from keyword args

3.3 空的处理

Counter对象有一个字典接口,如果引用的键没有任何记录,就返回一个0,而不是弹出一个KeyError

c = Counter(['eggs', 'ham'])
c['bacon']                              # count of a missing element is zero
0

3.4 删除元素

设置一个计数为0不会从计数器中移去一个元素。使用 del 来删除它

c['sausage'] = 0                        # counter entry with a zero count
del c['sausage']                        # del actually removes the entry

3.5 elements()方法

返回一个迭代器, 其中每个元素将重复出现计数值所指定次。元素会按首次出现的顺序返回。如果一个元素的计数值小于1, elements()将会忽略它

c = Counter(a=4, b=2, c=0, d=-2)
sorted(c.elements())
['a', 'a', 'a', 'a', 'b', 'b']

3.6 most_common([n])方法

返回一个列表, 其中包含 n 个最常见的元素及出现次数, 按常见程度由高到低排序。 如果 n 被省略或为 None, most_common()将返回计数器中的所有元素。计数值相等的元素按首次出现的顺序排序

Counter('abracadabra').most_common(3)
[('a', 5), ('b', 2), ('r', 2)]

3.7 subtract([iterable-or-mapping])方法

从 迭代对象 或 映射对象 减去元素。像dict.update()但是是减去, 而不是替换。输入和输出都可以是0或者负数

c = Counter(a=4, b=2, c=0, d=-2)
d = Counter(a=1, b=2, c=3, d=4)
c.subtract(d)
c
Counter({'a': 3, 'b': 0, 'c': -3, 'd': -6})

3.8 数学操作

提供了几个数学操作, 可以结合 Counter 对象, 以生产multisets (计数器中大于0的元素)。
加和减, 结合计数器, 通过加上或者减去元素的相应计数。
交集和并集返回相应计数的最小或最大值。
每种操作都可以接受带符号的计数, 但是输出会忽略掉结果为零或者小于零的计数

sum(c.values())                 # total of all counts
c.clear()                       # reset all counts
list(c)                         # list unique elements
set(c)                          # convert to a set
dict(c)                         # convert to a regular dictionary
c.items()                       # convert to a list of (elem, cnt) pairs
Counter(dict(list_of_pairs))    # convert from a list of (elem, cnt) pairs
c.most_common()[:-n-1:-1]       # n least common elements
+c                              # remove zero and negative counts

3.9 注意点

1.计数器主要是为了表达运行的正的计数而设计;但是, 小心不要预先排除负数或者其他类型

2.Counter 类是一个字典的子类,不限制键和值。值用于表示计数, 但你实际上可以存储任何其他值

3.most_common()方法在值需要排序的时候用

4.原地操作比如 c[key] += 1, 值类型只需要支持加和减。所以分数,小数,和十进制都可以用, 负值也可以支持。这两个方法update()和subtract()的输入和输出也一样支持负数和0

5.Multiset多集合方法只为正值的使用情况设计。输入可以是负数或者0, 但只输出计数为正的值。没有类型限制, 但值类型需要支持加, 减和比较操作

6.elements()方法要求正整数计数。忽略0和负数计数

4.总结

1.看到形如:A+B....+N=0的式子,要转换为(A+...T)=-((T+1)...+N)再计算,这个T的分割点一般是一半,特殊情况下需要自行判断。定T是解题的关键

2.dp一般不会超过二维, 这里都四维了, 维度太高, 需要分治

3.算法中间使用了map的新方法merge和getOrDefault, 相比较于传统的判断写法, 大大提高了效率

源码

Python:

class Solution:
    def fourSumCount(self, A: List[int], B: List[int], C: List[int], D: List[int]) -> int:
        # Counter类是dict()子类, 用于计数可哈希对象
        # 它是一个集合,元素像字典键(key)一样存储,它们的计数存储为值
        countAB = collections.Counter(u + v for u in A for v in B)
        ans = 0
        for u in C:
            for v in D:
                if -u - v in countAB:
                    ans += countAB[-u - v]
        return ans

java:

class Solution {
    public int fourSumCount(int[] A, int[] B, int[] C, int[] D) {
        Map<Integer, Integer> countAB = new HashMap<Integer, Integer>();
        for (int u : A) {
            for (int v : B) {
                // 存储u+v的结果,不存在赋值为1,存在在原来基础上+1
                // 另一种表达countAB.merge(u+v, 1, (old,new_)->old+1);
                countAB.put(u + v, countAB.getOrDefault(u + v, 0) + 1);
            }
        }
        int ans = 0;
        for (int u : C) {
            for (int v : D) {
                if (countAB.containsKey(-u - v)) {
                    ans += countAB.get(-u - v);
                }
            }
        }
        return ans;
    }
}

我的更多精彩文章链接, 欢迎查看

各种电脑/软件/生活/音乐/动漫/电影技巧汇总(你肯定能够找到你需要的使用技巧) https://blog.csdn.net/weixin_43959833/category_11020494.html

力扣算法刷题 根据思维导图整理笔记快速记忆算法重点内容(欢迎和博主一起打卡刷题哦) https://blog.csdn.net/weixin_43959833/category_11061515.html

计算机专业知识 思维导图整理

最值得收藏的 Python 全部知识点思维导图整理, 附带常用代码/方法/库/数据结构/常见错误/经典思想(持续更新中) https://blog.csdn.net/weixin_43959833/article/details/115267142

最值得收藏的 C++ 全部知识点思维导图整理(清华大学郑莉版), 东南大学软件工程初试906科目 https://blog.csdn.net/weixin_43959833/article/details/115269049

最值得收藏的 计算机网络 全部知识点思维导图整理(王道考研), 附带经典5层结构中英对照和框架简介 https://blog.csdn.net/weixin_43959833/article/details/115271050

最值得收藏的 算法分析与设计 全部知识点思维导图整理(北大慕课课程) https://blog.csdn.net/weixin_43959833/article/details/115266247

最值得收藏的 数据结构 全部知识点思维导图整理(王道考研), 附带经典题型整理 https://blog.csdn.net/weixin_43959833/article/details/115265378

最值得收藏的 人工智能导论 全部知识点思维导图整理(王万良慕课课程) https://blog.csdn.net/weixin_43959833/article/details/115250473

最值得收藏的 数值分析 全部知识点思维导图整理(东北大学慕课课程) https://blog.csdn.net/weixin_43959833/article/details/116722795

最值得收藏的 数字图像处理 全部知识点思维导图整理(武汉大学慕课课程) https://blog.csdn.net/weixin_43959833/article/details/116723478

红黑树 一张导图解决红黑树全部插入和删除问题 包含详细操作原理 情况对比 https://blog.csdn.net/weixin_43959833/article/details/115383564

各种常见排序算法的时间/空间复杂度 是否稳定 算法选取的情况 改进 思维导图整理 https://blog.csdn.net/weixin_43959833/article/details/115416607

人工智能课件 https://blog.csdn.net/weixin_43959833/category_10993842.html 算法分析课件 https://blog.csdn.net/weixin_43959833/category_10988063.html Python课件 https://blog.csdn.net/weixin_43959833/category_10993846.html 数值分析课件 https://blog.csdn.net/weixin_43959833/category_11001704.html 机器学习课件 https://blog.csdn.net/weixin_43959833/category_11001700.html 图像处理课件 https://blog.csdn.net/weixin_43959833/category_11001695.html

考研相关科目 知识点 思维导图整理

考研经验--东南大学软件学院软件工程(这些基础课和专业课的各种坑和复习技巧你应该知道) https://blog.csdn.net/weixin_43959833/article/details/115269528

东南大学 软件工程 906 数据结构 C++ 历年真题 思维导图整理 https://blog.csdn.net/weixin_43959833/article/details/115272922

东南大学 软件工程 复试3门科目历年真题 思维导图整理 https://blog.csdn.net/weixin_43959833/article/details/115280689

最值得收藏的 考研高等数学 全部知识点思维导图整理(张宇, 汤家凤), 附做题技巧/易错点/知识点整理 https://blog.csdn.net/weixin_43959833/article/details/115272648

最值得收藏的 考研线性代数 全部知识点思维导图整理(张宇, 汤家凤), 附带惯用思维/做题技巧/易错点整理 https://blog.csdn.net/weixin_43959833/article/details/115271431

高等数学 中值定理 一张思维导图解决中值定理所有题型 https://blog.csdn.net/weixin_43959833/article/details/115271752

考研思修 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理 https://blog.csdn.net/weixin_43959833/article/details/115827974

考研近代史 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理 https://blog.csdn.net/weixin_43959833/article/details/115796186

考研马原 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理 https://blog.csdn.net/weixin_43959833/article/details/115796066

考研数学课程笔记 https://blog.csdn.net/weixin_43959833/category_10947893.html 考研英语课程笔记 https://blog.csdn.net/weixin_43959833/category_10951922.html 考研英语单词词根词缀记忆 https://blog.csdn.net/weixin_43959833/category_10947903.html 考研政治课程笔记 https://blog.csdn.net/weixin_43959833/category_10947908.html

Python相关技术 知识点 思维导图整理

Numpy常见用法全部OneNote笔记 https://blog.csdn.net/weixin_43959833/category_10962459.html 全部笔记思维导图整理 https://blog.csdn.net/weixin_43959833/article/details/115598749

Pandas常见用法全部OneNote笔记 https://blog.csdn.net/weixin_43959833/category_10962462.html 全部笔记思维导图整理 https://blog.csdn.net/weixin_43959833/article/details/115904383

Matplotlib常见用法全部OneNote笔记 https://blog.csdn.net/weixin_43959833/category_10962463.html 全部笔记思维导图整理 https://blog.csdn.net/weixin_43959833/article/details/115919544

PyTorch常见用法全部OneNote笔记 https://blog.csdn.net/weixin_43959833/category_10962456.html 全部笔记思维导图整理 https://blog.csdn.net/weixin_43959833/article/details/115549323

Scikit-Learn常见用法全部OneNote笔记 https://blog.csdn.net/weixin_43959833/category_10962471.html 全部笔记思维导图整理 https://blog.csdn.net/weixin_43959833/article/details/115598749

Java相关技术/ssm框架全部笔记

Spring https://blog.csdn.net/weixin_43959833/category_10968021.html springmvc https://blog.csdn.net/weixin_43959833/category_10968022.html Mybatis https://blog.csdn.net/weixin_43959833/category_10968025.html jsp https://blog.csdn.net/weixin_43959833/category_10968029.html

科技相关 小米手机

小米 红米 历代手机型号大全 发布时间 发布价格 https://blog.csdn.net/weixin_43959833/article/details/115284970

常见手机品牌的各种系列划分及其特点 https://blog.csdn.net/weixin_43959833/article/details/115285119

历代CPU和GPU的性能情况和常见后缀的含义 思维导图整理 https://blog.csdn.net/weixin_43959833/article/details/115407936

...全文
31 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

509,071

社区成员

发帖
与我相关
我的任务
社区描述
我命由我不由天,来吧,和哪吒一起奋发图强,搬砖工逆袭Java架构师!
社区管理员
  • 哪 吒
  • Baker-Chen
  • 是Lay
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

【Java技能树】和哪吒一起,打卡100天,每天分享一个知识点,一起学习,一起进步,告别CRUD,搬砖工逆袭Java架构师,加油!

【积分榜】积分榜前十每周都有精彩礼包赠送!

【添加微信】备注1024,加入哪吒微信交流群,一起学习交流进大厂

试试用AI创作助手写篇文章吧