-
Notifications
You must be signed in to change notification settings - Fork 0
/
min-rewards.go
149 lines (121 loc) · 3.51 KB
/
min-rewards.go
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
package main
import (
"fmt"
"reflect"
)
/*
Imagine that you're a teacher who's just graded the final exam in a class. You
have a list of student scores on the final exam in a particular order (not
necessarily sorted), and you want to reward your students. You decide to do so
fairly by giving them arbitrary rewards following two rules:
1) All students must receive at least one reward.
2) Any given student must receive strictly more rewards than an adjacent
student (a student immediately to the left or to the right) with a lower
score and must receive strictly fewer rewards than an adjacent student with
a higher score.
Write a function that takes in a list of scores and returns the minimum number
of rewards that you must give out to students to satisfy the two rules.
You can assume that all students have different scores; in other words, the
scores are all unique.
expample:
input: [8, 4, 2, 1, 3, 6, 7, 9, 5]
output: 25 // rewards: [4, 3, 2, 1, 2, 3, 4, 5, 1]
*/
// Time: O(n), Space: O(n)
func minRewards(scores []int) int {
if len(scores) < 2 {
return 1
}
// Initialize all the rewards' array with 1
// since every student must receive at leat 1 reward.
rewards := make([]int, len(scores))
fill(rewards, 1)
// Get local mins indexes
localMinIndexes := getLocalMinIndexes(scores)
for _, idx := range localMinIndexes {
expandFromLocalMin(idx, scores, rewards)
}
return sum(rewards)
}
func fill(arr []int, commonValue int) {
for i := 0; i < len(arr); i++ {
arr[i] = commonValue
}
}
func getLocalMinIndexes(arr []int) []int {
// Local min is a number which is lower than both numbers on its side.
if len(arr) < 1 {
return []int{0}
}
localMinIndexes := []int{}
for i := 0; i < len(arr); i++ {
// At the start of the array, only right side can be compared.
if i == 0 && arr[i] < arr[i+1] {
localMinIndexes = append(localMinIndexes, i)
}
// At the end of the array, only left side can be compared.
if i == len(arr)-1 && arr[i] < arr[i-1] {
localMinIndexes = append(localMinIndexes, i)
}
// To avoid index out of range
if i == 0 || i == len(arr)-1 {
continue
}
if arr[i] < arr[i-1] && arr[i] < arr[i+1] {
localMinIndexes = append(localMinIndexes, i)
}
}
return localMinIndexes
}
func expandFromLocalMin(localMinIdx int, scores []int, rewards []int) {
leftIdx := localMinIdx - 1
for leftIdx >= 0 && scores[leftIdx] > scores[leftIdx+1] {
rewards[leftIdx] = max(rewards[leftIdx], rewards[leftIdx+1]+1)
leftIdx--
}
rightIdx := localMinIdx + 1
for rightIdx < len(scores) && scores[rightIdx] > scores[rightIdx-1] {
rewards[rightIdx] = rewards[rightIdx-1] + 1
rightIdx++
}
}
func max(value1, value2 int) int {
if value1 > value2 {
return value1
}
return value2
}
func sum(arr []int) int {
sum := 0
for i := range arr {
sum += arr[i]
}
return sum
}
func main() {
want := 25
got := minRewards([]int{8, 4, 2, 1, 3, 6, 7, 9, 5})
if !reflect.DeepEqual(want, got) {
fmt.Printf("want: %v, got: %v\n", want, got)
}
want = 1
got = minRewards([]int{1})
if !reflect.DeepEqual(want, got) {
fmt.Printf("want: %v, got: %v\n", want, got)
}
want = 3
got = minRewards([]int{5, 10})
if !reflect.DeepEqual(want, got) {
fmt.Printf("want: %v, got: %v\n", want, got)
}
want = 3
got = minRewards([]int{10, 5})
if !reflect.DeepEqual(want, got) {
fmt.Printf("want: %v, got: %v\n", want, got)
}
want = 52
got = minRewards([]int{2, 20, 13, 12, 11, 8, 4, 3, 1, 5, 6, 7, 9, 0})
if !reflect.DeepEqual(want, got) {
fmt.Printf("want: %v, got: %v\n", want, got)
}
}