A better approach for dividing overlapping intervals and combining identical ones for greater efficiency

Trying to optimize the process of splitting overlapped intervals and merging duplicates. A unique condition in this scenario: if a merged interval starts where an original one ends, it is incremented by 1; if it ends where an original starts, it is decremented by 1. Sample data and expected result provided:

interface Interval {
    start: number;
    end: number;
    type: Array<number>;
}

// initial data
const arr: Array<Interval> = [
    { start: 0, end: 16, type: [42] },
    { start: 6, end: 30, type: [95] },
    { start: 11, end: 24, type: [126] },
    { start: 32, end: 47, type: [42] }
].sort((a, b) => a.start - b.start);

// split and merge logic here

// expected resulting array
const end_arr: Array<Interval> = [
    { start: 0, end: 5, type: [42] },
    { start: 6, end: 10, type: [42, 95] },
    { start: 11, end: 16, type: [42, 95, 126] },
    { start: 17, end: 24, type: [95, 126] },
    { start: 25, end: 30, type: [95] },
    { start: 32, end: 47, type: [42] },
];

An existing solution uses nested loops but lacks efficiency. Any improvements welcome. Here's the current approach:

let startIndexArray: Array<number> = [];

let endIndexArray: Array<number> = [];

for (let i = 0; i < arr.length; i++) {
    startIndexArray.push(arr[i].start);
    endIndexArray.push(arr[i].end);
}

startIndexArray = startIndexArray.sort((a, b) => a - b);
endIndexArray = endIndexArray.sort((a, b) => a - b);

const indexArray = [...startIndexArray, ...endIndexArray].sort((a, b) => a - b);

const result: Array<Interval> = [];

arr.forEach((currentInterval) => {
    for (let i = currentInterval.start; i < currentInterval.end; i++) {
        if (indexArray.includes(i)) {
            const position = indexArray.indexOf(i);

            if (position !== indexArray.length - 1) {
                let start = i;
                let next = indexArray[position + 1];

                if (endIndexArray.includes(start)) {
                    start = start + 1;
                }

                if (startIndexArray.includes(next)) {
                    next = next - 1;
                }

                let in_result = false;
                result.forEach((mergedInterval) => {
                    if (mergedInterval.start === start && mergedInterval.end === next) {
                        mergedInterval.type = [...mergedInterval.type, ...currentInterval.type];
                        in_result = true;
                    }
                });
                if (!in_result) {
                    result.push({ start: start, end: next, type: [...currentInterval.type]});
                }
            }
        }
    }
});

// output matches expected result
console.log(result);

Answer №1

After much consideration, I have devised an algorithm that maximizes efficiency while maintaining simplicity. In testing with the sample array provided, it performs on par with your previous code. However, as the size of the array increases, this algorithm shows superior performance compared to yours. Of course, without an extensive set of test cases, these assumptions are provisional.

The core concept revolves around defining a data structure called a Partition, which represents a sorted array of non-overlapping intervals covering all integers from -Infinity to Infinity.

type Partition = Array<Interval>;

In understanding the structure of Partition, we can infer certain relationships such as partition[0].start === -Infinity,

partition[partition.length-1].end === Infinity
, and for any index i < partition.length - 1,
partition[i].end + 1 === partition[i+1].start
.


An advantageous aspect of a partition is that it inherently contains precisely one interval for any given position. This inherent characteristic alleviates the complexities associated with edge cases. So, when presented with a partition: Partition and a position: number, finding the index of the interval within the partition that encompasses the position becomes straightforward:

// binary search of the partition to find the index of the interval containing position
// startIndex is a hint, where partition[startIndex].start <= position
// endIndex is a hint, where partition[startIndex].end > position
function findIndex(
    partition: Partition,
    position: number,
    startIndex: number = 0,
    endIndex: number = partition.length
) {
    // Implementation goes here...
}

This approach utilizes a binary search technique, allowing for hints concerning start and end indices if prior knowledge about the position in the partition exists. With a partition of length 𝑛, this algorithm should perform at 𝖮(𝗅𝗈𝗀 𝑛).


Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for showcasing with [displayWith] in Material2's AutoComplete feature

My API returns an array and I am using Material2#AutoComplete to filter it. While it is working, I am facing an issue where I need to display a different property instead of the currently binded value in the option element. I understand that I need to uti ...

Developing Dynamic Key-Driven State Management in ReactJS Using JavaScript

I am facing a challenge with a specific aspect of my ReactJS code, which is more about my comprehension of how JavaScript key/value arrays operate than anything else. How can I allow the key to be passed-in dynamically in the given example? The issue lies ...

Encountering TS2304 error message while running TypeScript files indicates the inability to locate the name 'PropertyKey', in addition to another error - TS2339

I encountered an issue while attempting to execute a spec.ts file in the Jasmine Framework. After installing @types/core-js version 0.9.46 using the command npm i @types/core-js, I started receiving the following error messages: > ../../node_modules/ ...

Best Practices for Implementing Redux Prop Types in Typescript React Components to Eliminate TypeScript Warnings

Suppose you have a React component: interface Chat { someId: string; } export const Chat = (props: Chat) => {} and someId is defined in your mapStateToProps: function mapStateToProps(state: State) { return { someId: state.someId || '' ...

Is there a way to verify if an integer array is sorted that doesn't involve employing an "if" statement?

Is there a way to modify this Java code to achieve the desired outcome without using an if statement? I attempted to use a while loop, but it did not yield the results I wanted. After further investigation, I realized my mistake in utilizing the while lo ...

How can I adjust the column width in OfficeGen?

Currently, I am utilizing officeGen for the purpose of generating word documents. <sup> let table = [ [ { val: "TT", fontFamily: "Times New Roman", }, { val: "Ten hang", ...

Can someone provide guidance on utilizing the map function to iterate through intricate components in TypeScript?

I am facing a challenge while trying to iterate through a complex object containing 'inner objects'. When using the map function, I can only access one level below. How can I utilize map and TypeScript to loop through multiple levels below? Whene ...

Error: Angular - encountering undefined response when making HTTP request

When making a HTTP GET request to my backend, it returns the following JSON data: "{\"instID\":\"2018#10#30\",\"procID\":1161006,\"threadNum\":0,\"status\":2}", "{\"instID\":\"2018#1 ...

Unable to successfully generate work item through VSO SDK

A team is attempting to develop a custom widget on VSTS to facilitate group code reviews. One of the tasks is to create a new work item with the type "Code Review Response" and link it to code changes. However, the current code is not functioning as expect ...

What is the process for changing a specific value in an array using a specified index?

When working with arrays, I have the ability to modify a specific cell by referencing its position using a number. In this case, the cell I need to modify is identified by $i. pomme[${i}]="" Even after attempting without the backticks (`), the command do ...

Is it possible for a button to be assigned to a variable upon creation, but encounter an error when trying to

const button:Element = document.createElement("button");//This works fine const button:HTMLButtonElement = document.createElement("button");//This works too const button2:Element = document.getElementsByTagName("button");//Why does this give an error? con ...

Integrating TypeScript into an established create-react-app project

Struggling to integrate TypeScript into an existing create-react-app? I've always added it at the beginning of a project using create-react-app my-app --scripts-version=react-scripts-ts, but that's not working this time. The only "solution" I co ...

Alert: Attempting to access attribute of an object that is not defined in CURL response

Hey there, I've been experimenting with an API but keep encountering a strange error. Despite my efforts to find a solution online, I haven't been able to resolve it. The error message I'm getting is: "Notice: Trying to get property of non- ...

What's the best way to invoke a component method from an asynchronous function?

Here is my code snippet: export class TestComponent implements OnInit { constructor() { } ngOnInit() { FB.getLoginStatus(function (response) { this.ParseFacebookLoginStatus(response); }); } ParseFacebookLoginStatus(response) { ...

Is there a way to dynamically create a property and assign a value to it on the fly?

When retrieving data from my API, I receive two arrays - one comprising column names and the other containing corresponding data. In order to utilize ag-grid effectively, it is necessary to map these columns to properties of a class. For instance, if ther ...

Typescript fails to identify the parameter type of callbacks

I am facing a challenge with the function below and its callback type: type Callbacks = { onSuccess: (a: string) => void; }; function myFunction(event: string, ...args: [...any, Callbacks]) { } The function works correctly except for one issue - ...

Managing 10,000 data points within an array without compromising performance in Javascript - what's the best approach?

My current challenge involves retrieving 10,000 data entries from the server to store in an array. However, upon initial loading, I noticed a significant delay in rendering this data on the DOM. In an attempt to address this issue, I experimented with brea ...

The KeyConditionExpression is invalid due to the use of multiple attribute names within a single condition

I am trying to query a DynamoDB table using GraphQL TableName: "JobInfo", IndexName: "tableauGSI", KeyConditionExpression: "tableauGSI_Tableau = tableau AND #D BETWEEN :startDate AND :endDate", ExpressionAttributeNames: { "#D": "date" }, ...

Utilizing TypeScript to import and export modules under a single namespace

Have a look at this query that's quite similar to mine: https://github.com/Microsoft/TypeScript/issues/4529 Consider the following code snippet: //exported imports export {ISumanOpts, IGlobalSumanObj} from 'suman-types/dts/global'; export ...

What is the best way to forward all URLs to one central page?

I've recently started working with Angular and I'm currently developing a web app project using Angular 9. I could really use your help with this. My goal is to have a dynamic URL structure for the web app, such as https://www.myMainURL.com/***, ...