一个处理Range List的面试题解法

大纲

  • 题目
  • 解法
    • Range
      • add
      • remove
    • Tools
    • RangeList
      • add
      • remove
  • 代码

最近看到一个比较有意思的面试题。题目不算难,但是想把效率优化做好,也没那么容易。
我们先看下题目

题目

// Task: Implement a class named 'RangeList'
// A pair of integers define a range, for example: [1, 5). This range includes integers: 1, 2, 3, and 4.
// A range list is an aggregate of these ranges: [1, 5), [10, 11), [100, 201)
/**
*
 * NOTE: Feel free to add any extra member variables/functions you like.
*/
class RangeList {
	/**
	*
	* Adds a range to the list
	* @param {Array<number>} range - Array of two integers that specify beginning and
	end of range.
	*/
	add(range) {
		// TODO: implement this
	}
	
	/**
	*
	* Removes a range from the list
	* @param {Array<number>} range - Array of two integers that specify beginning and
	end of range.
	*/
	remove(range) {
		// TODO: implement this
	}
	
	/**
	*
	* Convert the list of ranges in the range list to a string
	* @returns A string representation of the range list
	*/
	toString() {
		// TODO: implement this
	}
}
// Example run
const rl = new RangeList();
rl.toString(); // Should be ""
rl.add([1, 5]);
rl.toString(); // Should be: "[1, 5)"
rl.add([10, 20]);
rl.toString(); // Should be: "[1, 5) [10, 20)"
rl.add([20, 20]);
rl.toString(); // Should be: "[1, 5) [10, 20)"
rl.add([20, 21]);
rl.toString(); // Should be: "[1, 5) [10, 21)"
rl.add([2, 4]);
rl.toString(); // Should be: "[1, 5) [10, 21)"
rl.add([3, 8]);
rl.toString(); // Should be: "[1, 8) [10, 21)"
rl.remove([10, 10]);
rl.toString(); // Should be: "[1, 8) [10, 21)"
rl.remove([10, 11]);
rl.toString(); // Should be: "[1, 8) [11, 21)"
rl.remove([15, 17]);
rl.toString(); // Should be: "[1, 8) [11, 15) [17, 21)"
rl.remove([3, 19]);
rl.toString(); // Should be: "[1, 3) [19, 21)

这题大体的意思是:设计一个RangeList类,它保存了一批左闭右开的区间。它支持add操作,可以新增一个包含区间,但是可能会影响之前的区间,比如之前的区间是:[3,5) [7,9),新增区间[5,7)之后,区间就变成[3,9);它还支持remove操作,可以删除一个区间,也可能影响之前的区间,比如之前的区间是[3,9),删除[5,7)之后,变成[3,5) [7,9)。
在这里插入图片描述

还有一种特殊区间需要考虑,就是左右值相等的区间。比如[5,5)代表的是一个空区间。

解法

Range

首先我们设计一个Range类,它只是单个区间。

add

如果对其进行add操作,即新增一个区间,则要考虑这两个区间是否相交。如果相交,则返回一个重新整合过的区间;如果不相交,则抛出异常。
在这里插入图片描述

    # add the other range to this range.For example, [1, 5) add [5, 7) is [1, 7).
    # @param other - the other range to add to this range
    # @return - the new range after adding
    # @throws TypeError if other is not a Range object or a list of integers
    # @throws ValueError if other is not a list of 2 integers
    # @throws TypeError if other range is not overlap with this range
    def add(self, other) -> object:
        other = self.conv(other)
        
        if self.end < other.start or self.start > other.end:
            raise ValueError("other range must be overlap with this range")
        if self.start >= other.start and self.end <= other.end:
            return Range(other.start, other.end)
        if self.start >= other.start and self.end > other.end:
            return Range(other.start, self.end)
        if self.start < other.start and self.end <= other.end:
            return Range(self.start, other.end)
        if self.start < other.start and self.end > other.end:
            return Range(self.start, self.end)

remove

如果对其进行remove操作,即删除一个区间,也要考虑两个区间相交的情况。如果相交,则返回一个Range数组,其中可能0~2个区间。
在这里插入图片描述

    # remove the other range from this range.For example, [1, 5) remove [2, 3) is [1, 2) [3, 5).
    # @param other - the other range to remove from this range.the other range must be a Range object or a list of 2 integers
    # @return - a list of Range objects that are the result of removing other from this range
    # @throws TypeError if other is not a Range object or a list of integers
    # @throws ValueError if other is not a list of 2 integers
    def remove(self, other) -> list:
        other = self.conv(other)
        
        if self.end < other.start or self.start > other.end:
            return [self]
        if self.start >= other.start and self.end <= other.end:
            return []
        if self.start >= other.start and self.end > other.end:
            return [Range(other.end, self.end)]
        if self.start < other.start and self.end <= other.end:
            return [Range(self.start, other.start)]
        if self.start < other.start and self.end > other.end:
            return [Range(self.start, other.start), Range(other.end, self.end)]

Tools

在设计完Range类后,我们还需要解决下面两个问题:

  • 被修正的区间有哪些
  • 需要调整位置的区间有哪些
    在这里插入图片描述
    上图中标红的表示可能要调整区间的区域。
    对于没有没有需要调整的区域,则要找到临近的区域。比如上图中第一组中,[7,8)需要找到[5,6)这组区间。如果是add操作,则需要将[7,8)插入到区间数组的[5,6)后面。
#!/usr/bin/env python
# -*- coding: utf-8; py-indent-offset:4 -*-
# ======================================================================================================================
# Copyrigth (C) 2024 fangliang <304646673@qq.com>
#
# This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later
# version.
#
# ======================================================================================================================

from rangelist.range import Range

class Tools(object):          
        
    # search the index of the range which contains the value.First value is the index of the range where to compare with the value, 
    # second value is True if the range contains the value, False otherwise.  
    # @param ranges - the list of ranges
    # @param value - the value to search
    # @param start_index - the start index of the ranges to search
    # @return the index of the range where to compare with the value, True if the range contains the value, False otherwise
    @staticmethod
    def search(ranges, value, start_index = 0):
        if start_index < 0:
            start_index = 0
        end_index = len(ranges) - 1
        while start_index <= end_index:
            mid = (start_index + end_index) // 2
            if ranges[mid].start <= value and ranges[mid].end >= value:
                return (mid, True)
            elif ranges[mid].end < value:
                start_index = mid + 1
            else:
                end_index = mid - 1
        
        return (end_index, False)
    
    # search the index of the ranges which overlap with the search range.
    # First value is the index of the range where to compare with the value, second value is True if the range contains the value,
    # False otherwise.
    # @param ranges - the list of ranges
    # @param search_range - the range to search
    # @return a list of (index, overlap) of the ranges which overlap with the search range
    @staticmethod
    def search_overlap(ranges, search_range):
        if search_range.start == search_range.end:
            return []
        
        start = Tools.search(ranges, search_range.start)
        end = Tools.search(ranges, search_range.end, start[0])
        index_list = [start]
        for i in range(start[0]+1, end[0]+1):
            index_list.append((i, True))
        return index_list

search_overlap方法返回的数据如下:

[(-1, False), (0, True), (1, True)]

-1代表对比的区间(可能是新增或者删除)的起始值在第0个区间的左侧。
True和False表示区间是否会调整(因为有覆盖)。

RangeList

RangeList用于保存一组Range序列。
这题的解法也主要依赖于其add和remove方法。

add

    # add a range to the list.For example, [[1, 5)] add [2, 3) is [[1, 5)].[[1, 5)] add [6, 8) is [[1, 5) [6, 8)].
    # @param other - the other range to compare with
    # @return True if the other range is overlap with this range, False otherwise
    # @throws TypeError if other is not a Range object or a list of integers
    # @throws ValueError if other is not a list of 2 integers
    def add(self, other):
        other = Range.conv(other)
        
        indexes = Tools.search_overlap(self.ranges, other)
        del_start_index = -1
        for i in indexes:
            if i[1]:
                other = self.ranges[i[0]].add(other)
                if -1 == del_start_index:
                    del_start_index = i[0]
                    
        if -1 != del_start_index:
            del self.ranges[del_start_index : indexes[-1][0]+1]
            self.ranges.insert(del_start_index, other)
        elif len(indexes) > 0:
            self.ranges.insert(indexes[0][0]+1, other)
        
        return self

add方法会让一个Range不停“合并”被其覆盖的Range。然后删除被覆盖的Range,把新组合的Range插入到第一个覆盖的Range位置。
如果没有覆盖的区间,则在适当的位置插入。

remove

# remove the other range from this range.For example, [[1, 5) [10, 14)]] remove [2, 3) is [[1, 2) [3, 5) [10, 14)]].
    # @param other - the other range to remove from this range
    # @return - the new range after removing
    # @throws TypeError if other is not a Range object or a list of integers
    # @throws ValueError if other is not a list of 2 integers
    def remove(self, other):
        other = Range.conv(other)
        
        indexes = Tools.search_overlap(self.ranges, other)
        del_start_index = -1
        range_list_from_remove_all = []
        for i in indexes:
            if i[1]:
                range_list_from_remove = self.ranges[i[0]].remove(other)
                if range_list_from_remove != None:
                    range_list_from_remove_all.extend(range_list_from_remove)
                if -1 == del_start_index:
                    del_start_index = i[0]
        
        if -1 != del_start_index:
            del self.ranges[del_start_index : indexes[-1][0]+1]
            self.ranges[del_start_index:del_start_index] = range_list_from_remove_all
        
        return self

remove方法则是让Range List中Range不停remove待删除Range,最后把切割的Range重新插入到Range List中。

代码

https://github.com/f304646673/rangelist.git

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/344480.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

解决 ssh: connect to host github.com port 22: Connection timed out

问题 今天使用git克隆github上的代码时&#xff0c;一直报错 原以为是公钥过期了&#xff0c;就尝试修改配置公钥&#xff0c;但是尝试了几次都不行&#xff0c;最终在博客上找到了解决方案&#xff0c;在次记录一下&#xff0c;以备不时之需 解决ssh-connect-to-host-github…

【实战教程】一文读懂防火墙本地Portal认证:让你的网络更安全!

往期精彩 【实战教程】防火墙设备登录配置&#xff0c;让你轻松掌握网络安全&#xff01;【实战教程】防火墙安全区域与策略实战指南&#xff1a;让你的网络安全防护如虎添翼&#xff01;【实战教程】防火墙常见NAT技术&#xff0c;让你一次看个够&#xff01;【实战教程】从零…

机器学习之聚类-2D数据类别划分

无监督学习&#xff08;Unsupervised Learning&#xff09; 机器学习的一种方法&#xff0c;没有给定事先标记过的训练示例&#xff0c;自动对输入的数据进行分类或分群。 方式一&#xff1a;站着或坐着 方式二&#xff1a;全身或半身 方式三&#xff1a;蓝眼球或不是蓝眼球 …

RocketMQ-Windows版本安装

RocketMQ-Windows版本安装 1.环境准备 JDK和maven需要先安装好&#xff0c;我这里使用的JDK1.8版本 Maven 3.8.6版本。需要注意的是&#xff0c;这里配置java时需要指定JAVA_HOME环境变量 RokectMQ才能正常启动。 2.下载RocketMQ 官网下载: https://rocketmq.apache.org/z…

苹果手机怎么还原?本文教你一键操作!

苹果手机作为一系列备受瞩目的智能设备&#xff0c;以其流畅的用户体验和出色的性能而备受用户喜爱。然而&#xff0c;在某些情况下&#xff0c;例如设备出现故障、需要清理空间、或者想要将手机还原至出厂设置&#xff0c;用户可能会考虑进行苹果手机的还原。在本文中&#xf…

OpenCV书签 #余弦相似度的原理与相似图片/相似文件搜索实验

1. 介绍 余弦相似度&#xff08;Cosine Similarity&#xff09;&#xff0c;又称为余弦相似性&#xff0c;是通过计算两个向量的夹角余弦值来评估他们的相似度。余弦相似度仅仅与向量的指向方向相关&#xff0c;与向量的长度无关&#xff0c;它将向量根据坐标值绘制到向量空间…

HelpLook支持同步企微组织架构,管理内部知识库更方便!

内部知识库是企业用来集中存储、管理和分享内部信息的系统。它类似一个知识仓库&#xff0c;员工可以在这里查找和获取所需的资料、流程和策略。同时保护公司的核心知识不会因员工的流动而流失&#xff0c;也能推动公司的创新和决策的精准性&#xff0c;对于公司的日常运营和长…

Leetcode—2788. 按分隔符拆分字符串【简单】(stringstream的应用)

2023每日刷题&#xff08;八十六&#xff09; Leetcode—2788. 按分隔符拆分字符串 实现代码 class Solution { public:vector<string> splitWordsBySeparator(vector<string>& words, char separator) {vector<string> res;for(auto word: words) {st…

性能优化-HVX架构简介

来自 「发表于知乎专栏《移动端算法优化》」 本文主要介绍Hexagon DSP的HVX技术&#xff0c;旨在通过简单的语言讲清HVX技术。 &#x1f3ac;个人简介&#xff1a;一个全栈工程师的升级之路&#xff01; &#x1f4cb;个人专栏&#xff1a;高性能&#xff08;HPC&#xff09;开…

【MySQL索引特性】

文章目录 1. 没有索引&#xff0c;可能会有什么问题2. 认识磁盘2.1 MySQL与存储2.2 先来研究一下磁盘&#xff1a;2.3 磁盘随机访问(Random Access)与连续访问(Sequential Access) 3. MySQL 与磁盘交互基本单位4. 建立共识5. 索引的理解5.1 建立测试表5.2 插入多条记录5.3 查看…

宝马X5原车氙气灯升级采用搭载FP7208升压LED驱动模块的双光透镜,效果立竿见影

目录 一、LED车灯的内部组成结构 二、FP7208驱动板详解 三、FP7208的优势 1.模拟和数字调光、无频闪 2.拥有多种功能&#xff0c;有效提高LED灯珠寿命 结论&#xff1a; 在夜晚的道路上&#xff0c;车灯的亮度对于驾驶安全至关重要。然而&#xff0c;许多车主常常对汽车灯…

网络组件、设备和关系网络图【推荐】

目录 网络上的设备&#xff1a; 设备和台式计算机&#xff1a; 防火墙&#xff1a; 服务器&#xff1a; 集线器和交换机&#xff1a; 路由器&#xff1a; 调制解调器和无线接入点调制解调器&#xff1a; 无线接入点&#xff1a; 网络架构&#xff08;有时称为网络设计&…

【思路合集】talking head generation+stable diffusion

1 以DiffusionVideoEditing为baseline&#xff1a; 改进方向 针对于自回归训练方式可能导致的漂移问题&#xff1a; 训练时&#xff0c;在前一帧上引入小量的面部扭曲&#xff0c;模拟在生成过程中自然发生的扭曲。促使模型查看身份帧以进行修正。在像VoxCeleb或LRS这样的具…

学会使用ubuntu——ubuntu22.04使用WebCatlog

Ubuntu22.04使用WebCatlog WebCatlog是适用于Gnu / Linux&#xff0c;Windows或Mac OS X系统的桌面程序。 引擎基于铬&#xff0c;它用于在我们的桌面上处理Web服务。简单点就是把网页单独一个窗口出来显示&#xff0c;当一个app用。本文就是利用WebCatlog安装后的notion编写的…

知识图谱符号表示比较:特性图、RDF和OWL

目录 前言1 特性图&#xff1a;灵活的图结构表示1.1 优势与灵活性1.2 存储优化与查询优势1.3 挑战&#xff1a;缺乏工业标准支持 2 RDF&#xff08;Resource Description Framework&#xff09;&#xff1a;面向Web的数据标准2.1 三元组结构的优势2.2 语义标准与词汇丰富性2.3 …

为你推荐十款顶级CAD制图软件,助力绘图工作更轻松!

市场上有各种各样的CAD绘图软件。国外和国内的相关软件都比较成熟&#xff0c;但目前CAD三维绘图还略有欠缺。这里推荐的10款非常好用的CAD绘图软件&#xff0c;包括支持2D和3D的&#xff0c;大部分都是免费的CAD绘图工具&#xff0c;还有一些功能完善的收费软件。点击下面的软…

增删改查接口

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; 增删改查 RestController RequestMapping("system/mappingCode") Slf4j Api(tags "系统管理 - 映射码") public class SystemMappingCodeEndpo…

设备通过GB28181注册到EasyCVR,平台看不到设备信息的排查方法汇总

智慧安防平台EasyCVR能在复杂的网络环境中&#xff08;专网、局域网、广域网、VPN、公网等&#xff09;将前端海量的设备进行统一集中接入与视频汇聚管理&#xff0c;平台支持设备通过4G、5G、WIFI、有线等方式进行视频流的接入与传输&#xff0c;支持的接入协议包括&#xff1…

【Elasticsearch篇】详解使用RestClient操作索引库的相关操作

文章目录 &#x1f354;什么是Elasticsearch&#x1f33a;什么是RestClient&#x1f386;代码操作⭐初始化RestClient⭐使用RestClient操作索引库⭐使用RestClient删除索引库⭐使用RestClient判断索引库是否存在 &#x1f354;什么是Elasticsearch Elasticsearch是一个开源的分…

OpenCV第 1 课 计算机视觉和 OpenCV 介绍

文章目录 第 1 课 计算机视觉和 OpenCV 介绍1.机器是如何“看”的2.机器视觉技术的常见应用3.图像识别介绍4. 图像识别技术的常见应用5.OpenCV 介绍6.图像在计算机中的存储形式 第 1 课 计算机视觉和 OpenCV 介绍 1.机器是如何“看”的 我们人类可以通过眼睛看到五颜六色的世界…