IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> ??思维导图整理大厂面试高频数组15: 介绍Entry类和海象运算符 哈希表解决最短连续子数组 力扣697?? -> 正文阅读

[数据结构与算法]??思维导图整理大厂面试高频数组15: 介绍Entry类和海象运算符 哈希表解决最短连续子数组 力扣697??

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

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

关于本专栏所有题目的目录链接, 刷算法题目的顺序/注意点/技巧, 以及思维导图源文件问题请点击此链接.

想进大厂, 刷算法是必不可少的, 欢迎和博主一起打卡刷力扣算法, 博主同步更新了算法视频讲解 和 其他文章/导图讲解, 更易于理解, 欢迎来看!

题目链接:https://leetcode-cn.com/problems/degree-of-an-array/solution/si-wei-dao-tu-zheng-li-jie-shao-entrylei-fkxe/

0.导图整理

1.题目分析

这道题在题目的理解上还是有一定的难度的, 看到有些评论反应连题目都没读懂, 那先来解读下题目.

数组的度的定义是指数组里任一元素出现频数的最大值: 也就是数组中出现最多的那个数的个数.

你的任务是在nums中找到与nums拥有相同大小的度的最短连续子数组, 返回其长度: 也就是要求我们找到一个子数组, 子数组中出现最多的那个数的个数 和 原数组是相同的, 并且要求这个子数组尽可能的短.

2.哈希表的结构设计

了解题目要求后, 这题的求解过程就分为两部分: 先找到数组的度, 再找到满足要求的最短连续子数组.

找数组的度很容易就能想到利用哈希表来解决, 只需要利用哈希表来记录每个数出现的次数, 然后遍历哈希表获得最大的次数即可. 困难之处在于如何寻找最短连续子数组.

我们先来分析下最短连续子数组的要求: 记原数组中出现次数最多的数为 x, 那么和原数组的度相同的最短连续子数组, 必然包含了原数组中的全部 x, 且两端恰为 x 第一次出现和最后一次出现的位置, 这样才能确保子数组的长度最短, 不会包含多余的元素.

通过这样的分析结果发现, 我们不仅要保存每个数出现的次数, 还需要保存每个数第一次出现和最后一次出现的位置, 因此就能设计出这样的哈希表: 每一个数映射到一个长度为 3 的数组, 数组中的三个元素分别代表这个数出现的次数、这个数在原数组中第一次出现的位置 和 这个数在原数组中最后一次出现的位置.

这里还涉及到一种特殊情况: 符合条件的 x 可能有多个, 即多个不同的数在原数组中出现次数相同. 这时我们只需要比较哪个子数组的长度更短即可.

3. java的Map类遍历

在代码实现中, 我们需要遍历哈希表中对应的所有的值, 来寻找数组的度 和 最短连续子数组长度. 这里是利用Map.entrySet()来实现的, 可能很多朋友对此方法还是比较陌生的, 我们来介绍一下.

3.1 Map.Entry

在介绍方法之前, 我们首先介绍下Map.Entry这个类. 它是Map中的一个内部类, 表示一个映射项, 映射项包含Key和Value (我们常说的键值对, 每一个键值对也就是一个Entry类), Map.Entry里面包含getKey()和getValue()方法. 用来获取相应的 键和值.

3.2 Map.entrySet()

它是Map类的一个方法, 它的返回值就是所有键值对组成的集合, Set里面的类型是Map.Entry, 所以返回值的类型就是Map.Entry类, 这样我们通过调用Map.entrySet()这个方法获得所有的键值对, 再通过Map.Entry类中的getValue()方法就可以获得所有的值了. 之后就可以对这些值进行各种操作获得结果了.

3.3 四种方法遍历Map

这里总结的了四种方法遍历Map, 每种方式都有不同的用途, 感兴趣的可以看一下.

public static void main(String[] args) {
 
    Map<String, String> map = new HashMap<String, String>();
    map.put("1", "value1");
    map.put("2", "value2");
    map.put("3", "value3");
  
    //第一种:普遍使用,二次取值
    System.out.println("通过Map.keySet遍历key和value:");
    for (String key : map.keySet()) {
        System.out.println("key= "+ key + " and value= " + map.get(key));
    }
  
    //第二种
    System.out.println("通过Map.entrySet使用iterator遍历key和value:");
    Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
    while (it.hasNext()) {
        Map.Entry<String, String> entry = it.next();
        System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
    }
  
    //第三种:推荐,尤其是容量大时
    System.out.println("通过Map.entrySet遍历key和value");
    for (Map.Entry<String, String> entry : map.entrySet()) {
        System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
    }
 
    //第四种
    System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
    for (String v : map.values()) {
        System.out.println("value= " + v);
    }
 }

4.Python的 := 海象运算符

随着Python 3.8的发布, 赋值表达式运算符(也称为海象运算符)也发布了, 它最大的特点就是能够在表达式中进行赋值, 不需要再单独的进行赋值了, 用起来还是很方便的.

我大概总结了它的几种用法和优点如下:

  1. 运算符使值的赋值可以传递到表达式中, 省去了一个赋值中间变量的步骤, 这也是它设计的初衷.
my_list = [1,2,3]
count = len(my_list)
if count > 3:
   print(f"Error, {count} is too many items")

# 当转换为海象运算符时...
if (count := len(my_list)) > 3:
   print(f"Error, {count} is too many items")
  1. 可以在while语句中合并表达式和修饰符, 赋值在循环表达式之前
line = f.readLine()
while line:
   print(line)
   line = f.readLine()

# 转换为海象运算符时
while line := f.readLine():
   print(line)
  1. 替换无限while循环中最有用
while True:
   p = input("Enter the password: ")
   if p == "the password":
      break 

# 当转换为海象运算符时

while (p := input("Enter the password: ")) != "the password":
   continue
  1. 减少函数的调用次数
scores = [22,54,75,89]
valid_scores = [
   longFunction(n)
   for n in scores
   if longFunction(n)
]

# 注意条件语句longFunction(n)了吗? 注意longFunction()被调用了两次吗?

scores = [22,54,75,89]
valid_scores = [
   result for n in scores
   result := longFunction(n)
]

# 在优化了的代码中,longFunction()仅被调用一次,隐含的降低了调用次数

5.总结

5.1 Python求数组的度

这题因为哈希表的结构比较特殊, 用python求数组的度的时候也采用正常的字典的形式, 但如果只是单独的求数组的度, python有更加简洁的方法, 直接利用counter类即可, 关于这个类, 我之前也详细讲解过, 可在此查看.

degree = max(Counter(nums).values())  # 数组的度

5.2 滑动窗口的思想

当然这题也是可以使用滑动窗口的思想的, 它的思路如下: j向右的条件是当前窗口的度小于数组的度, i向右的条件是当前窗口的度等于数组的度, 但这个方法的缺点也是很明显的: 每次都需要求子区间的度, 使用了max函数, 时间复杂度略高.

class Solution:
    def findShortestSubArray(self, nums: List[int]) -> int:
        degree = max(Counter(nums).values())  # 数组的度
        i = j = 0
        dic = defaultdict(int)
        res = len(nums)
        while j < len(nums):
            dic[nums[j]] += 1
            maxCnt = max(dic.values())
            while maxCnt >= degree:
                res = min(res, j - i + 1)
                dic[nums[i]] -= 1
                i += 1
                maxCnt = max(dic.values())
            j += 1
        return res

源码

Python:

class Solution:
    def findShortestSubArray(self, nums: List[int]) -> int:
        mp = dict() # 字典的值为长度为3的数组


        for i, num in enumerate(nums):
            if num in mp:  # 重复出现的情况
                mp[num][0] += 1 # 第一个数代表出现次数
                mp[num][2] = i  # 第三个数代表最后一次出现位置
            else:  # 第一次出现的情况
                mp[num] = [1, i, i]  # 第二个数代表第一次出现位置
        
        maxNum = minLen = 0
        for count, left, right in mp.values():
            if maxNum < count: # 寻找数组的度 和 最短连续子数组长度
                maxNum = count
                minLen = right - left + 1
            elif maxNum == count: # 若两个元素的度相同,比较谁的长度更短
                # 海象运算符:= 在表达式中为变量赋值,简化操作
                if minLen > (span := right - left + 1):
                    minLen = span
        
        return minLen

java:

class Solution {
    public int findShortestSubArray(int[] nums) {
        Map<Integer, int[]> map = new HashMap<Integer, int[]>(); // 值为长度为3的数组
        int n = nums.length;
        for (int i = 0; i < n; i++) {
            if (map.containsKey(nums[i])) { // 重复出现的情况
                map.get(nums[i])[0]++;   // 第一个数代表出现次数
                map.get(nums[i])[2] = i; // 第三个数代表最后一次出现位置
            } else { // 第一次出现的情况
                map.put(nums[i], new int[]{1, i, i}); // 第二个数代表第一次出现位置
            }
        }
        int maxNum = 0, minLen = 0;
        // 通过map中的entrySet方法获得所有键值对,它们的类型为Map.Entry内部类
        for (Map.Entry<Integer, int[]> entry : map.entrySet()) {
            int[] arr = entry.getValue();
            if (maxNum < arr[0]) { // 寻找数组的度 和 最短连续子数组长度
                maxNum = arr[0];
                minLen = arr[2] - arr[1] + 1;
            } else if (maxNum == arr[0]) { // 若两个元素的度相同,比较谁的长度更短
                if (minLen > arr[2] - arr[1] + 1) {
                    minLen = arr[2] - arr[1] + 1;
                }
            }
        }
        return minLen;
    }
}

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

各种电脑/软件/生活/音乐/动漫/电影技巧汇总(你肯定能够找到你需要的使用技巧)

力扣算法刷题 根据思维导图整理笔记快速记忆算法重点内容(欢迎和博主一起打卡刷题哦)

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

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

最值得收藏的 C++ 全部知识点思维导图整理(清华大学郑莉版), 东南大学软件工程初试906科目

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

最值得收藏的 算法分析与设计 全部知识点思维导图整理(北大慕课课程)

最值得收藏的 数据结构 全部知识点思维导图整理(王道考研), 附带经典题型整理

最值得收藏的 人工智能导论 全部知识点思维导图整理(王万良慕课课程)

最值得收藏的 数值分析 全部知识点思维导图整理(东北大学慕课课程)

最值得收藏的 数字图像处理 全部知识点思维导图整理(武汉大学慕课课程)

红黑树 一张导图解决红黑树全部插入和删除问题 包含详细操作原理 情况对比

各种常见排序算法的时间/空间复杂度 是否稳定 算法选取的情况 改进 思维导图整理

人工智能课件 算法分析课件 Python课件 数值分析课件 机器学习课件 图像处理课件

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

考研经验–东南大学软件学院软件工程(这些基础课和专业课的各种坑和复习技巧你应该知道)

东南大学 软件工程 906 数据结构 C++ 历年真题 思维导图整理

东南大学 软件工程 复试3门科目历年真题 思维导图整理

最值得收藏的 考研高等数学 全部知识点思维导图整理(张宇, 汤家凤), 附做题技巧/易错点/知识点整理

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

高等数学 中值定理 一张思维导图解决中值定理所有题型

考研思修 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理

考研近代史 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理

考研马原 知识点 做题技巧 同类比较 重要会议 1800易错题 思维导图整理

考研数学课程笔记 考研英语课程笔记 考研英语单词词根词缀记忆 考研政治课程笔记

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

Numpy常见用法全部OneNote笔记 全部笔记思维导图整理

Pandas常见用法全部OneNote笔记 全部笔记思维导图整理

Matplotlib常见用法全部OneNote笔记 全部笔记思维导图整理

PyTorch常见用法全部OneNote笔记 全部笔记思维导图整理

Scikit-Learn常见用法全部OneNote笔记 全部笔记思维导图整理

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

Spring springmvc Mybatis jsp

科技相关 小米手机

小米 红米 历代手机型号大全 发布时间 发布价格

常见手机品牌的各种系列划分及其特点

历代CPU和GPU的性能情况和常见后缀的含义 思维导图整理

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-01 17:08:43  更:2021-10-01 17:08:47 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 5:27:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码