Skip to content

Commit 5e66755

Browse files
committed
Kotlin - Chapter 17: Sort and Search
* Dutch National Flag * Kth Largest Integer * Counting Sort * Quick Sort * Quick Sort [Optimized] * Sort Linked List
1 parent 3c4bb50 commit 5e66755

7 files changed

+225
-0
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
fun dutchNationalFlag(nums: MutableList<Int>) {
2+
var i = 0
3+
var left = 0
4+
var right = nums.size - 1
5+
while (i <= right) {
6+
// Swap 0s with the element at the left pointer.
7+
if (nums[i] == 0) {
8+
nums[i] = nums[left].also { nums[left] = nums[i] }
9+
left++
10+
i++
11+
// Swap 2s with the element at the right pointer.
12+
} else if (nums[i] == 2) {
13+
nums[i] = nums[right].also { nums[right] = nums[i] }
14+
right--
15+
} else {
16+
i++
17+
}
18+
}
19+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import java.util.PriorityQueue
2+
3+
fun kthLargestIntegerMinHeap(nums: List<Int>, k: Int): Int {
4+
val minHeap = PriorityQueue<Int>()
5+
for (num in nums) {
6+
// Ensure the heap has at least 'k' integers.
7+
if (minHeap.size < k) {
8+
minHeap.offer(num)
9+
// If 'num' is greater than the smallest integer in the heap, poll
10+
// off this smallest integer from the heap and offer 'num'.
11+
} else if (num > minHeap.peek()) {
12+
minHeap.poll()
13+
minHeap.offer(num)
14+
}
15+
}
16+
return minHeap.peek()
17+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
fun kthLargestIntegerQuickselect(nums: List<Int>, k: Int): Int {
2+
return quickselect(nums.toMutableList(), 0, nums.size - 1, k)
3+
}
4+
5+
fun quickselect(nums: MutableList<Int>, left: Int, right: Int, k: Int): Int {
6+
val n = nums.size
7+
if (left >= right) {
8+
return nums[left]
9+
}
10+
val randomIndex = (left..right).random()
11+
nums[randomIndex] = nums[right].also { nums[right] = nums[randomIndex] }
12+
val pivotIndex = partition(nums, left, right)
13+
// If the pivot comes before 'n - k', the ('n - k')th smallest
14+
// integer is somewhere to its right. Perform quickselect on the
15+
// right part.
16+
if (pivotIndex < n - k) {
17+
return quickselect(nums, pivotIndex + 1, right, k)
18+
// If the pivot comes after 'n - k', the ('n - k')th smallest integer
19+
// is somewhere to its left. Perform quickselect on the left part.
20+
} else if (pivotIndex > n - k) {
21+
return quickselect(nums, left, pivotIndex - 1, k)
22+
// If the pivot is at index 'n - k', it's the ('n - k')th smallest
23+
// integer.
24+
} else {
25+
return nums[pivotIndex]
26+
}
27+
}
28+
29+
fun partition(nums: MutableList<Int>, left: Int, right: Int): Int {
30+
val pivot = nums[right]
31+
var lo = left
32+
for (i in left until right) {
33+
if (nums[i] < pivot) {
34+
nums[lo] = nums[i].also { nums[i] = nums[lo] }
35+
lo++
36+
}
37+
}
38+
nums[lo] = nums[right].also { nums[right] = nums[lo] }
39+
return lo
40+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
fun sortArrayCountingSort(nums: List<Int>): List<Int> {
2+
if (nums.isEmpty()) return emptyList()
3+
val res = mutableListOf<Int>()
4+
// Count occurrences of each element in 'nums'.
5+
val counts = IntArray(nums.maxOrNull()!! + 1)
6+
for (num in nums) {
7+
counts[num]++
8+
}
9+
// Build the sorted array by appending each index 'i' to it a total
10+
// of 'counts[i]' times.
11+
for (i in counts.indices) {
12+
val count = counts[i]
13+
repeat(count) { res.add(i) }
14+
}
15+
// counts.forEachIndexed { i, count -> repeat(count) { res.add(i) } }
16+
return res
17+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
fun sortArray(nums: List<Int>): List<Int> {
2+
quicksort(nums.toMutableList(), 0, nums.size - 1)
3+
return nums
4+
}
5+
6+
fun quicksort(nums: MutableList<Int>, left: Int, right: Int) {
7+
// Base case: if the subarray has 0 or 1 element, it's already
8+
// sorted.
9+
if (left >= right) {
10+
return
11+
}
12+
// Partition the array and retrieve the pivot index.
13+
val pivotIndex = partition(nums, left, right)
14+
// Call quicksort on the left and right parts to recursively sort
15+
// them.
16+
quicksort(nums, left, pivotIndex - 1)
17+
quicksort(nums, pivotIndex + 1, right)
18+
}
19+
20+
fun partition(nums: MutableList<Int>, left: Int, right: Int): Int {
21+
val pivot = nums[right]
22+
var lo = left
23+
// Move all numbers less than the pivot to the left, which
24+
// consequently positions all numbers greater than or equal to the
25+
// pivot to the right.
26+
for (i in left until right) {
27+
if (nums[i] < pivot) {
28+
nums[lo] = nums[i].also { nums[i] = nums[lo] }
29+
lo++
30+
}
31+
}
32+
// After partitioning, 'lo' will be positioned where the pivot should
33+
// be. So, swap the pivot number with the number at the 'lo' pointer.
34+
nums[lo] = nums[right].also { nums[right] = nums[lo] }
35+
return lo
36+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
fun sortArray(nums: List<Int>): List<Int> {
2+
quicksortOptimized(nums.toMutableList(), 0, nums.size - 1)
3+
return nums
4+
}
5+
6+
fun quicksortOptimized(nums: MutableList<Int>, left: Int, right: Int) {
7+
if (left >= right) {
8+
return
9+
}
10+
// Choose a pivot at a random index.
11+
val randomIndex = (left..right).random()
12+
// Swap the randomly chosen pivot with the rightmost element to
13+
// position the pivot at the rightmost index.
14+
nums[right] = nums[randomIndex].also { nums[randomIndex] = nums[right] }
15+
val pivotIndex = partition(nums, left, right)
16+
quicksortOptimized(nums, left, pivotIndex - 1)
17+
quicksortOptimized(nums, pivotIndex + 1, right)
18+
}
19+
20+
fun partition(nums: MutableList<Int>, left: Int, right: Int): Int {
21+
val pivot = nums[right]
22+
var lo = left
23+
// Move all numbers less than the pivot to the left, which
24+
// consequently positions all numbers greater than or equal to the
25+
// pivot to the right.
26+
for (i in left until right) {
27+
if (nums[i] < pivot) {
28+
nums[lo] = nums[i].also { nums[i] = nums[lo] }
29+
lo++
30+
}
31+
}
32+
// After partitioning, 'lo' will be positioned where the pivot should
33+
// be. So, swap the pivot number with the number at the 'lo' pointer.
34+
nums[lo] = nums[right].also { nums[right] = nums[lo] }
35+
return lo
36+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import ds.ListNode
2+
3+
/*
4+
Definition of ListNode:
5+
data class ListNode(var value: Int = 0, var next: ListNode? = null)
6+
*/
7+
8+
fun sortLinkedList(head: ListNode?): ListNode? {
9+
// If the linked list is empty or has only one element, it's already
10+
// sorted.
11+
if (head == null || head.next == null) {
12+
return head
13+
}
14+
// Split the linked list into halves using the fast and slow pointer
15+
// technique.
16+
val secondHead = splitList(head)
17+
// Recursively sort both halves.
18+
val firstHalfSorted = sortLinkedList(head)
19+
val secondHalfSorted = sortLinkedList(secondHead)
20+
// Merge the sorted sublists.
21+
return merge(firstHalfSorted, secondHalfSorted)
22+
}
23+
24+
fun splitList(head: ListNode): ListNode {
25+
var slow = head
26+
var fast = head
27+
while (fast.next != null && fast.next!!.next != null) {
28+
slow = slow.next!!
29+
fast = fast.next!!.next!!
30+
}
31+
val secondHead = slow.next
32+
slow.next = null
33+
return secondHead!!
34+
}
35+
36+
fun merge(l1: ListNode?, l2: ListNode?): ListNode? {
37+
val dummy = ListNode()
38+
// This pointer will be used to append nodes to the tail of the
39+
// merged linked list.
40+
var tail = dummy
41+
var list1 = l1
42+
var list2 = l2
43+
// Continually append the node with the smaller value from each
44+
// linked list to the merged linked list until one of the linked
45+
// lists has no more nodes to merge.
46+
while (list1 != null && list2 != null) {
47+
if (list1.value < list2.value) {
48+
tail.next = list1
49+
list1 = list1.next
50+
} else {
51+
tail.next = list2
52+
list2 = list2.next
53+
}
54+
tail = tail.next!!
55+
}
56+
// One of the two linked lists could still have nodes remaining.
57+
// Attach those nodes to the end of the merged linked list.
58+
tail.next = list1 ?: list2
59+
return dummy.next
60+
}

0 commit comments

Comments
 (0)