Mar 13, 2023
Edit me
#. Problem
1. My approach
Merging to the one TreeNode as going through the loops.
It would take O(nk) time complexity, where n is the number of nodes and k is the number of lists.
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function mergeKLists(lists: Array<ListNode | null>): ListNode | null {
if(!lists.length) return null;
let main = lists[0];
for(let i = 1; i < lists.length; i++){
// console.log(`loop ${i} ::`);
let mainHead = main;
let subHead = lists[i];
let temp = new ListNode(), ptr = temp;
while(mainHead && subHead){
if(mainHead.val > subHead.val) {
ptr.next = subHead;
subHead = subHead.next;
} else {
ptr.next = mainHead;
mainHead = mainHead.next;
}
ptr = ptr.next;
}
// for(let tempPtr = temp; tempPtr; tempPtr = tempPtr.next) console.log(` ${tempPtr.val} ->`)
if(mainHead) ptr.next = mainHead;
if(subHead) ptr.next = subHead;
main = temp.next;
}
return main;
};
2. Better approach
Using a strategy of divide and conquer.
It would take O(n log k) time complexity, where n is the number of nodes and k is the number of lists.
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function mergeKLists(lists: Array<ListNode | null>): ListNode | null {
if(!lists.length) return null;
let newList = [...lists];
while(newList.length > 1){
const tempList = [];
for(let i = 0; i < newList.length; i += 2){
// console.log(`loop ${i} ::`);
let mainHead = newList[i];
let subHead = newList[i+1];
let temp = new ListNode(), ptr = temp;
while(mainHead && subHead){
if(mainHead.val > subHead.val) {
ptr.next = subHead;
subHead = subHead.next;
} else {
ptr.next = mainHead;
mainHead = mainHead.next;
}
ptr = ptr.next;
}
// for(let tempPtr = temp; tempPtr; tempPtr = tempPtr.next) console.log(` ${tempPtr.val} ->`)
if(mainHead) ptr.next = mainHead;
if(subHead) ptr.next = subHead;
tempList.push(temp.next);
}
newList = tempList;
}
return newList[0];
};
3. Epilogue
I didn’t expect them to have huge difference in terms of time complexity, because typescript is not a language that is optimized for speed.
But it turns out that the second approach is much faster than the first one.
The differences were more than 3 times.
1. my approach | 2. better approach |
---|---|
291 ms | 91 ms |
47.8 MB | 48.6 MB |
What I’ve learned from this exercise:
- Time complexity approach is still very important even for the language that is not optimized for speed.