Skip to content

Commit a6c4e6a

Browse files
committed
Add reverse linkedlist based on range
1 parent dab26e0 commit a6c4e6a

File tree

6 files changed

+241
-19
lines changed

6 files changed

+241
-19
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ List of Programs related to data structures and algorithms
109109

110110
### LinkedList
111111

112-
1. Reverse substring: [JavaScript](https://livecodes.io/?console&x=https://github.com/sudheerj/datastructures-algorithms/blob/master/src/javascript/algorithms/linkedlist/reverseSubstring.js)
112+
1. Reverse substring: [JavaScript](https://livecodes.io/?console&x=https://github.com/sudheerj/datastructures-algorithms/blob/master/src/javascript/algorithms/linkedlist/1.reverseSublist/reverseSublist.js)
113113

114114
2. Detect cycle in a linkedlist: [JavaScript](https://livecodes.io/?console&x=https://github.com/sudheerj/datastructures-algorithms/blob/master/src/javascript/algorithms/linkedlist/detectLoop.js)
115115

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package java1.algorithms.linkedlist.reverseSublist;
2+
3+
class Node {
4+
public int value;
5+
public Node next;
6+
7+
Node(int value) {
8+
this.value = value;
9+
this.next = null;
10+
}
11+
}
12+
13+
public class ReverseSublist {
14+
private Node head;
15+
private Node tail;
16+
private int length;
17+
18+
ReverseSublist() {
19+
head = null;
20+
tail = null;
21+
length = 0;
22+
}
23+
24+
public void append(int value) {
25+
Node newNode = new Node(value);
26+
if(head == null) {
27+
head = newNode;
28+
tail = newNode;
29+
} else {
30+
newNode.next = tail;
31+
tail = newNode;
32+
}
33+
34+
length++;
35+
}
36+
37+
public Node reverseBetween(int left, int right) {
38+
if(head == null || head.next == null || left == right) return head;
39+
40+
Node dummy = new Node(0);
41+
dummy.next = head;
42+
43+
Node leftPrev = dummy;
44+
Node current = head;
45+
46+
for (int i = 0; i < left-1; i++) {
47+
leftPrev = current;
48+
current = current.next;
49+
}
50+
51+
Node prev = null;
52+
53+
for (int i = 0; i < right-left+1; i++) {
54+
Node temp = current.next;
55+
current.next = prev;
56+
prev = current;
57+
current = temp;
58+
}
59+
60+
leftPrev.next.next = current;
61+
leftPrev.next = prev;
62+
63+
head = dummy.next;
64+
65+
return head;
66+
}
67+
68+
public void printList() {
69+
Node temp = head;
70+
while(temp != null) {
71+
System.out.println(temp.value);
72+
temp = temp.next;
73+
}
74+
}
75+
76+
public static void main(String[] args) {
77+
ReverseSublist myReverseSublist = new ReverseSublist();
78+
myReverseSublist.append(1);
79+
myReverseSublist.append(2);
80+
myReverseSublist.append(3);
81+
myReverseSublist.append(4);
82+
myReverseSublist.append(5);
83+
myReverseSublist.append(6);
84+
85+
myReverseSublist.reverseBetween(2, 5);
86+
87+
myReverseSublist.printList();
88+
}
89+
}
90+
91+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
**Problem statement:**
2+
Given the `head` of a singly linked list and two integers `left` and `right` where left <= right. Reverse the nodes of the list that fall between the positions `left` and `right` (inclusive), and return the reversed list.
3+
4+
**Note:** The positions are 1-indexed(not 0-indexed). i.e, 1 <= left <= right <= n. Where `n` is the length of list.
5+
6+
7+
## Examples:
8+
Example 1:
9+
10+
Input: head = [1,2,3,4,5,6], left=2, right=5
11+
Output: [1,5,4,3,2,6]
12+
13+
Example 2:
14+
15+
Input: head = [1,2,3,4,5,6], left=1, right=3
16+
Output: [3,2,1,4,5,6]
17+
18+
Example 3:
19+
20+
Input: head = [4], left=1, right=1
21+
Output: [4]
22+
23+
**Algorithmic Steps**
24+
This problem is solved by understanding the concept of full reversal of linkedlist and keeping the pointers for the nodes at the boundaries where we actually reverse the sublist. Later, these boundary pointers are helpful to connect the reversed list with the remaining parts of the non-reversed linkedlist. The algorithmic approach can be summarized as follows:
25+
26+
1. Handle the base case scenarios such as empty list ,or list with one node, or left and right pointers are equal. In these cases, there is no need of reversal of linkedlist.(i.e, Just return the original list)
27+
28+
2. Create a dummy node(`dummy`) to simplify the edge case handling, such as when reversing the list from the first node itself.
29+
30+
3. Connect the dummy node to the head node.
31+
32+
4. Declare the boundary pointers `leftPrev` and `current` pointing to the dummy node and head nodes respectively. These pointers are helpful to point the node before the reversal and beginning of the reversal list respectively.
33+
34+
5. Iterate the loop `left-1` times to reach the boundary section.
35+
36+
6. Implement the reversal of sublist starting from `current` node and keep tracking the previous node `prev` initialized with `null`. This reversal logic needs to be looped `right-left+1` times.
37+
38+
7. Upon reversing the references of sublist, connect the non-reversed sublists with reversed section.
39+
40+
8. At last, return the head node(`this.dummy.next`) which contains the reversed nodes of linkedlist.
41+
42+
43+
**Time and Space complexity:**
44+
This algorithm has a time complexity of `O(n)`, where `n` is the number of nodes in a linkedlist. This is because we are traversing the list at most once.
45+
46+
Here, we don't use any additional datastructure other than few pointers for the node. Hence, the space complexity will be `O(1)`.

src/javascript/algorithms/linkedlist/reverseSubstring.js src/javascript/algorithms/linkedlist/1.reverseSublist/reverseSublist.js

+55-17
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@ class Node {
66
}
77

88
class LinkedList {
9-
constructor(value) {
10-
const newNode = new Node(value);
11-
this.head = newNode;
12-
this.head = newNode;
13-
this.tail = newNode;
14-
this.length = 1;
9+
constructor() {
10+
this.head = null;
11+
this.tail = null;
12+
this.length = 0;
1513
}
1614

1715
push(value) {
@@ -27,29 +25,62 @@ class LinkedList {
2725
return this;
2826
}
2927

30-
reverseBetween(m, n) {
28+
reverseBetween1(left, right) {
29+
if(!this.head || this.head.next !== null || left === right) return this.head;
30+
31+
let dummy = new Node(0);
32+
dummy.next = this.head;
33+
34+
let leftPrev = dummy;
35+
let current = this.head;
36+
37+
for (let i = 0; i < left-1; i++) {
38+
leftPrev = current;
39+
current = current.next;
40+
}
41+
42+
let prev = null;
43+
for (let i = 0; i < right-left+1; i++) {
44+
let temp = current.next;
45+
current.next = prev;
46+
prev = current;
47+
current = temp;
48+
}
49+
50+
leftPrev.next.next = current;
51+
leftPrev.next = prev;
52+
53+
this.head = dummy.next;
54+
55+
return this.head;
56+
}
57+
58+
reverseBetween2(left, right) {
3159
if (this.head === null) return;
3260

3361
const dummy = new Node(0);
3462
dummy.next = this.head;
3563
let prev = dummy;
3664

37-
for (let i = 0; i < m; i++) {
65+
for (let i = 0; i < left-1; i++) {
3866
prev = prev.next;
3967
}
4068

4169
let current = prev.next;
42-
for (let i = 0; i < n - m; i++) {
70+
for (let i = 0; i < right - left; i++) {
4371
const temp = current.next;
4472
current.next = temp.next;
4573
temp.next = prev.next;
4674
prev.next = temp;
4775
}
4876

4977
this.head = dummy.next;
78+
79+
return this.head;
5080
}
5181

52-
reverseBetweenUsingReverseList(m, n) {
82+
//UsingReverseList
83+
reverseBetween3(left, right) {
5384
if(!this.head) return;
5485

5586
let current = this.head;
@@ -59,14 +90,14 @@ class LinkedList {
5990
let revEndNext = null;
6091
let i = 0;
6192

62-
while(current && i <= n) {
63-
if(i < m) {
93+
while(current && i <= right) {
94+
if(i < left) {
6495
revPrev = current;
6596
}
66-
if(i === m) {
97+
if(i === left) {
6798
revBegin = current;
6899
}
69-
if(i === n) {
100+
if(i === right) {
70101
revEnd = current;
71102
revEndNext = current.next;
72103
}
@@ -100,12 +131,19 @@ class LinkedList {
100131

101132
}
102133

103-
const myLinkedList = new LinkedList(1);
134+
const myLinkedList = new LinkedList();
135+
myLinkedList.push(1);
104136
myLinkedList.push(2);
105137
myLinkedList.push(3);
106138
myLinkedList.push(4);
107139
myLinkedList.push(5);
140+
myLinkedList.push(6);
141+
142+
const myLinkedList1 = new LinkedList();
143+
myLinkedList1.push(4);
108144

109-
myLinkedList.reverseBetween(2, 4);
110-
myLinkedList.reverseBetweenUsingReverseList(1, 3);
145+
console.dir(myLinkedList.reverseBetween1(2, 5), {depth: null});
146+
console.dir(myLinkedList.reverseBetween2(2, 5), {depth: null});
147+
console.dir(myLinkedList.reverseBetween3(1, 3), {depth: null});
148+
console.dir(myLinkedList1.reverseBetween1(1, 1));
111149

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
**Problem statement:**
2+
Given the `head` of a singly linked list and two integers `left` and `right` where left <= right. Reverse the nodes of the list that fall between the positions `left` and `right` (inclusive), and return the reversed list.
3+
4+
**Note:** The positions are 1-indexed(not 0-indexed). i.e, 1 <= left <= right <= n. Where `n` is the length of list.
5+
6+
7+
## Examples:
8+
Example 1:
9+
10+
Input: head = [1,2,3,4,5,6], left=2, right=5
11+
Output: [1,5,4,3,2,6]
12+
13+
Example 2:
14+
15+
Input: head = [1,2,3,4,5,6], left=1, right=3
16+
Output: [3,2,1,4,5,6]
17+
18+
Example 3:
19+
20+
Input: head = [4], left=1, right=1
21+
Output: [4]
22+
23+
**Algorithmic Steps**
24+
This problem is solved by understanding the concept of full reversal of linkedlist and keeping the pointers for the nodes at the boundaries where we actually reverse the sublist. Later, these boundary pointers are helpful to connect the reversed list with the remaining parts of the non-reversed linkedlist. The algorithmic approach can be summarized as follows:
25+
26+
1. Handle the base case scenarios such as empty list ,or list with one node, or left and right pointers are equal. In these cases, there is no need of reversal of linkedlist.(i.e, Just return the original list)
27+
28+
2. Create a dummy node(`dummy`) to simplify the edge case handling, such as when reversing the list from the first node itself.
29+
30+
3. Connect the dummy node to the head node.
31+
32+
4. Declare the boundary pointers `leftPrev` and `current` pointing to the dummy node and head nodes respectively. These pointers are helpful to point the node before the reversal and beginning of the reversal list respectively.
33+
34+
5. Iterate the loop `left-1` times to reach the boundary section.
35+
36+
6. Implement the reversal of sublist starting from `current` node and keep tracking the previous node `prev` initialized with `null`. This reversal logic needs to be looped `right-left+1` times.
37+
38+
7. Upon reversing the references of sublist, connect the non-reversed sublists with reversed section.
39+
40+
8. At last, return the head node(`this.dummy.next`) which contains the reversed nodes of linkedlist.
41+
42+
43+
**Time and Space complexity:**
44+
This algorithm has a time complexity of `O(n)`, where `n` is the number of nodes in a linkedlist. This is because we are traversing the list at most once.
45+
46+
Here, we don't use any additional datastructure other than few pointers for the node. Hence, the space complexity will be `O(1)`.

src/javascript/datastructures/singlyLinkedList/singlyLinkedList.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ class LinkedList {
113113
}
114114

115115
reverse() {
116-
if(length == 0) return undefined;
116+
if(this.length === 0) return undefined;
117117

118118
let temp = this.head;
119119
this.head = this.tail;
@@ -131,6 +131,7 @@ class LinkedList {
131131
}
132132

133133
const myLinkedList = new LinkedList();
134+
console.log(myLinkedList.push(1));
134135
console.log(myLinkedList.push(2));
135136
console.log(myLinkedList.push(3));
136137

0 commit comments

Comments
 (0)