首页 > 其他分享 >LeetCode 面试题 17.05. 字母与数字

LeetCode 面试题 17.05. 字母与数字

时间:2024-07-09 12:29:38浏览次数:15  
标签:面试题 下标 前缀 字母 17.05 数组 maxLength presum LeetCode

面试题 17.05. 字母与数字

给定一个放有字母和数字的数组,找到最长的子数组,且包含的字母和数字的个数相同。

返回该子数组,若存在多个最长子数组,返回左端点下标值最小的子数组。若不存在这样的数组,返回一个空数组。

示例 1:

输入: ["A","1","B","C","D","2","3","4","E","5","F","G","6","7","H","I","J","K","L","M"]

输出: ["A","1","B","C","D","2","3","4","E","5","F","G","6","7"]

示例 2:

输入: ["A","A"]

输出: []

提示:

  • array.length <= 100000

提示 1

是哪个字母或数字并不重要。你可以把该问题简化为只包含 A 和 B 的数组。然后寻找具有相同数量的 A 和 B 的最长子数组。


提示 2

从蛮力解法开始。


提示 3

如果你从一开始就计算 A 的个数和 B 的个数会怎样(试着构建数组构成的表并保存到目前为止 A 和 B 的数量)?


提示 4

当表中 A 和 B 的个数相等时,整个子数组(从索引 0 开始)的 A 和 B 的个数相等。如何使用该表来查找不以索引 0 开始的、符合条件的子数组?


提示 5

假设在这个表中,索引 i 满足 count(A, 0->i) = 3 和 count(B, 0->i) = 7。这意味着 B 比 A 多 4 个。如果你发现后面的某点 j 具有相同的差值(count(B, 0->j) - count(a, 0->j)),那么这表示子数组中有相同数量的 A 和 B。

解法1:转换 + 前缀和 + 哈希表

一个子数组包含的字母和数字的个数相同,等价于该子数组包含的字母和数字的个数之差为 0。因此可以将原数组做转换,每个字母对应 1,每个数字对应 −1,则转换后的数组中,每个子数组的元素和为该子数组对应的原始子数组的字母和数字的个数之差,如果转换后数组中的一个子数组的元素和为 0,则该子数组对应的原始子数组包含的字母和数字的个数相同。问题等价于在转换后的数组中寻找元素和为 0 的最长子数组。

为了在转换后的数组中寻找元素和为 0 的子数组,可以计算转换后的数组的前缀和,如果两个下标对应的前缀和相等,则这两个下标之间的子数组的元素和为 0。

如果同一个前缀和出现多次,则该前缀和对应的最长子数组的长度为该前缀和的第一次出现的下标与最后一次出现的下标之间的子数组,因此为了在转换后的数组中寻找元素和为 0 的最长子数组,需要记录每个前缀和第一次出现的下标。

使用哈希表记录每个前缀和第一次出现的下标。由于空前缀的前缀和是 0 且对应下标 −1,因此首先将前缀和 0 与下标 −1 存入哈希表。

从左到右遍历数组,遍历过程中维护元素和为 0 的最长子数组的长度 maxLength 与开始下标 startIndex,初始时 maxLength=0,startIndex=−1。当遍历到下标 i 时,如果前缀和是 sum,则执行如下操作。

  • 如果哈希表中已经存在前缀和 sum,则从哈希表中得到前缀和 sum 第一次出现的下标 firstIndex,以下标 i 结尾的元素和为 0 的最长子数组的长度是 i−firstIndex,该最长子数组的下标范围是 [firstIndex+1,i]。如果 i−firstIndex>maxLength,则将 maxLength 更新为 i−firstIndex,将 startIndex 更新为 firstIndex+1;如果 i−firstIndex≤maxLength,则不更新 maxLength 与 startIndex。
  • 如果哈希表中不存在前缀和 sum,则下标 i 为前缀和 sum 第一次出现的下标,将前缀和 sum 与下标 i 存入哈希表。

遍历结束之后,根据 maxLength 与 startIndex 的值返回结果。

  • 如果 maxLength>0,则原数组中存在字母和数字的个数相同的子数组,根据 maxLength 与 startIndex 得到原数组中包含的字母和数字的个数相同的最长子数组,返回该最长子数组。
  • 如果 maxLength=0,则原数组中不存在字母和数字的个数相同的子数组,返回空数组。

从左到右遍历数组的过程中,只有当遇到的子数组长度大于已有的最大长度时才会更新最大子数组的长度与开始下标,因此每次更新最大子数组的长度与开始下标之后,不存在长度等于已有的最大长度且开始下标更小的子数组。如果有多个最长子数组,则 startIndex 为这些最长子数组中的最小的左端点下标值。

实现方面,不需要创建并计算转换后的数组,只需要将原数组中的字母和数字分别对应 1 和 −1,在遍历过程中计算前缀和即可。

Java版:

在Java中,System类包包含一个名为arraycopy()的方法来复制数组。

arraycopy(Object src, int srcPos,Object dest, int destPos, int length)

这里,

  • src -您要复制的源数组

  • srcPos -源数组中的起始位置(索引)

  • dest -目标数组,将从源中复制元素

  • destPos -目标数组中的起始位置(索引)

  • length -要复制的元素数

class Solution {
    public String[] findLongestSubarray(String[] array) {
        int maxLength = 0;
        int start = -1;
        int presum = 0;
        Map<Integer, Integer> map = new HashMap<>();
        map.put(0, -1);
        for (int i = 0; i < array.length; i++) {
            if (Character.isLetter(array[i].charAt(0))) {
                presum++;
            } else {
                presum--;
            }
            if (map.containsKey(presum)) {
                if (i - map.get(presum) > maxLength) {
                    maxLength = i - map.get(presum);
                    start = map.get(presum) + 1;
                }
            } else {
                map.put(presum, i);
            }
        }
        if (maxLength == 0) {
            return new String[0];
        }
        String[] ans = new String[maxLength];
        System.arraycopy(array, start, ans, 0, maxLength);
        return ans;
    }
}

Python3版:

class Solution:
    def findLongestSubarray(self, array: List[str]) -> List[str]:
        maxLength = 0
        start = -1
        presum = 0
        dic = dict()
        dic[0] = -1
        for i in range(len(array)):
            if array[i].isdigit():
                presum += 1
            else:
                presum -= 1
            if presum in dic:
                if i - dic[presum] > maxLength:
                    maxLength = i - dic[presum]
                    start = dic[presum] + 1
            else:
                dic[presum] = i
        
        if maxLength == 0:
            return []
        return array[start: start + maxLength]

复杂度分析

  • 时间复杂度:O(n),其中 n 是数组的长度。需要遍历数组一次计算符合要求的最长子数组的长度与开始下标,对于数组中的每个元素的操作时间都是 O(1),因此遍历时间是 O(n),生成结果数组需要 O(n) 的时间。
  • 空间复杂度:O(n),其中 n 是数组的长度。哈希表需要 O(n) 的空间。

标签:面试题,下标,前缀,字母,17.05,数组,maxLength,presum,LeetCode
From: https://blog.csdn.net/m0_56090828/article/details/140291854

相关文章

  • LeetCode 1546. 和为目标值且不重叠的非空子数组的最大数目
    1546.和为目标值且不重叠的非空子数组的最大数目给你一个数组 nums 和一个整数 target 。请你返回 非空不重叠 子数组的最大数目,且每个子数组中数字和都为 target 。示例1:输入:nums=[1,1,1,1,1],target=2输出:2解释:总共有2个不重叠子数组(加粗数字表示)[1,......
  • 面试题整理
    现在给你三百台服务器,你怎么对他们进行管理?管理3百台服务器的方式:1)设定跳板机,使用统一账号登录,便于安全与登录的考量。2)使用salt、ansiable、puppet进行系统的统一调度与配置的统一管理。3)建立简单的服务器的系统、配置、应用的cmdb信息管理。便于查阅每台服务器上的各......
  • 经典C语言笔试面试题目
    01.请填写bool,float,指针变量与“零值”比较的if语句。提示:这里“零值”可以是0,0.0,FALSE或者“空指针”。例如intn与“零值”比较的if语句为:if(n==0)if(n!=0)以此类推。请写出boolflag与“零值”比较的if语句:if(flag){}if(!fl......
  • 代码随想录-DAY⑤-哈希表——leetcode 242 | 349 | 202
    242思路先遍历字符串1,记录每个字符的个数,然后遍历字符串2,挨个减去字符个数,出现小于零的个数说明字符总数不重合。时间复杂度:O(n)空间复杂度:O(1)代码classSolution{public:boolisAnagram(strings,stringt){if(s.length()!=t.length()){......
  • SVN 80道面试题及参考答案(2万字长文)
    目录解释SVN的全称和主要功能。SVN与CVS相比,有哪些主要改进?描述SVN的工作流程。什么是版本库(repository)?它存储了什么?解释工作副本(workingcopy)的概念。SVN如何处理文件的版本控制?SVN中的“commit”是什么意思?解释“update”操作的作用。如何查看一个文件的历史版......
  • 那些年背过的面试题——JVM篇
    本文是技术人面试系列JVM篇,面试中关于JVM都需要了解哪些基础?一文带你详细了解,欢迎收藏!JVM内存划分1、JVM运行时数据区域堆、方法区(元空间)、虚拟机栈、本地方法栈、程序计数器。Heap(堆):对象的实例以及数组的内存都是要在堆上进行分配的,堆是线程共享的一块区域,用......
  • LeetCode【跳跃游戏】
    55.跳跃游戏给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。示例 1:输入:nums=[2,3,1,1,4]输出:true解释:可以先跳1步,从下......
  • Python面试题-8
    41.请解释Python中的切片操作。在Python中,切片(Slicing)是一种获取序列(如字符串、列表、元组等)的子集或部分的操作。切片操作使用方括号[],并且可以在方括号中指定开始索引、结束索引和步长。其基本语法如下:sequence[start:end:step]start是切片开始的索引,默认为0(序列的......
  • 【js面试题】深入理解尾递归及其在JavaScript中的应用
    面试题:举例说明尾递归的理解,以及应用场景引言:在编程中,递归是一种常见的解决问题的方法,它允许函数调用自身来解决问题。然而,递归如果不当使用,可能会导致栈溢出错误,特别是在处理大量数据时。尾递归是一种特殊的递归形式,它能够优化递归调用,避免栈溢出的问题。本文将深入探......
  • LeetCode42(接雨水)[三种解法:理解动态规划,双指针,单调栈]
    接雨水给定n个非负整数表示每个宽度为1的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。这是一道困难题,难度确实有点层次.我们先来朴素思想走一波.要求能接多少雨水,我们可以具化到每个硅谷,每个硅谷能存多少雨水,那么答案就是每个硅谷的雨水所加之和.对......