forked from realpacific/algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathReorderList.kt
172 lines (156 loc) · 4.78 KB
/
ReorderList.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
package questions
import questions.common.LeetNode
import utils.assertIterableSame
import java.util.*
/**
* You are given the head of a singly linked-list. The list can be represented as `L0 → L1 → … → Ln - 1 → Ln`
*
* Reorder the list to be on the following form: `L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …`
* You may not modify the values in the list's nodes. Only nodes themselves may be changed.
*
* [Source](https://leetcode.com/problems/reorder-list)
*/
private fun reorderList(head: LeetNode?) {
if (head == null) return
if (head.next == null) return
val stack = LinkedList<LeetNode>()
var current: LeetNode? = head
while (current != null) {
stack.addLast(current) // add the nodes to a stack
current = current.next
}
val lengthToSwapsRequired = mapOf(
1 to 0, 2 to 0, // if there are 1 or 2 items, no swaps required
3 to 1, 4 to 1, // if there are 3 or 4 items, just 1 swap required
5 to 2, 6 to 2, // if there are 5 or 6 items, just 2 swap required
7 to 3, 8 to 3,
9 to 4, // case for 9 or 10 items (10 is not possible, but if totalLength=0,
10 to 4, // ...it can be safely considered that the items is in multiple of 10
)
fun numberOfSwapsRequired(totalLength: Int): Int {
if (totalLength <= 10) {
return lengthToSwapsRequired[totalLength]!!
}
// From my observation, the behavior of totalLength to swaps required is:
//
// Length | swaps
// * 1 -> 0
// * 2 -> 0
// * 9 -> 4
// * 10 -> 4
// * 11 -> 5 ( lengthToSwapsRequired[10] + lengthToSwapsRequired[11 % 10] = 4 ) + 1
// * 12 -> 5 ( lengthToSwapsRequired[10] + lengthToSwapsRequired[12 % 10] = 4 ) + 1
// * 13 -> 6 ( lengthToSwapsRequired[10] + lengthToSwapsRequired[13 % 10] = 5 ) + 1
// * 20 -> 9
// * 21 -> 10
// extra 1 for every 10
// each 10s adds a 4
// each 10s adds a 1
// subtract 10 from it and do it again
return 4 + 1 + numberOfSwapsRequired(totalLength - 10)
}
val totalSwapsRequired = numberOfSwapsRequired(stack.size)
var previous: LeetNode? = head
current = head.next
var swapsDone = 0
while (current != null) {
val toBeInserted =
stack.removeLastOrNull() ?: break // pop the stack to put it in the middle of prev and current
swapsDone++
// place [toBeInserted] in the middle
previous?.next = toBeInserted
toBeInserted.next = current
// move to next insertion point
previous = toBeInserted.next
current = previous?.next
if (swapsDone > totalSwapsRequired) {
// no more required
current?.next = null // nullify the end
break
}
}
}
fun main() {
run {
val input = LeetNode.from(IntRange(1, 49).toList().toIntArray())
reorderList(input)
assertIterableSame(
actual = input.toList(),
expected = LeetNode.from(
1,
49,
2,
48,
3,
47,
4,
46,
5,
45,
6,
44,
7,
43,
8,
42,
9,
41,
10,
40,
11,
39,
12,
38,
13,
37,
14,
36,
15,
35,
16,
34,
17,
33,
18,
32,
19,
31,
20,
30,
21,
29,
22,
28,
23,
27,
24,
26,
25
).toList()
)
}
run {
val input = LeetNode.from(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)
reorderList(input)
assertIterableSame(
actual = input.toList(),
expected = LeetNode.from(1, 11, 2, 10, 3, 9, 4, 8, 5, 7, 6).toList()
)
}
run {
val input = LeetNode.from(1, 2, 3, 4)
reorderList(input)
assertIterableSame(
actual = input.toList(),
expected = LeetNode.from(1, 4, 2, 3).toList()
)
}
run {
val input = LeetNode.from(1, 2, 3, 4, 5)
reorderList(input)
assertIterableSame(
actual = input.toList(),
expected = LeetNode.from(1, 5, 2, 4, 3).toList()
)
}
}