题目要求
** 解法一:**
建立空数组存储结果,全部初始化为1。 从头开始遍历数组,如果出现比之前一个小的数,则反向继续遍历,将原来的分数进行更新(更新过程中需要比较新分数和原来久分数的大小,取最大值)。如果出现比之前的数组大,则原有的数+1。继续下一个数的判断。
Time: O(n^2) Space: O(n)
代码:
import java.util.*;
class Program {
public static int minRewards(int[] scores) {
// Write your code here.
int[] res = new int[scores.length];
res[0] = 1;
// Arrays.fill(res, 1);
for (int i = 1; i < scores.length; i++) {
int j = i - 1;
if (scores[i] < scores[j]) {
res[i] = 1;
while (j >= 0 && scores[j] > scores[j + 1]) {
res[j] = Math.max(res[j + 1] + 1, res[j]);
j--;
}
} else {
res[i] = res[i - 1] + 1;
}
}
return sum(res);
}
public static int sum (int[] array) {
int sum = 0;
for (int num : array) {
sum += num;
}
return sum;
}
}
解法二:
只通过一次遍历数组就得出结果。首先找到数组的localMin的索引并存储。依次处理每个localMin的点,分别向左和向右进行更改分数(更新过程中需要比较新分数和原来久分数的大小,取最大值)。
Corner case:要注意最左边和最右边的极端的点,只有一侧递增。容易越界。
Time: O(n) Space: O(n)
代码:
import java.util.*;
class Program {
public static int minRewards(int[] scores) {
// Write your code here.
if (scores.length == 1) return 1;
int[] res = new int[scores.length];
Arrays.fill(res, 1);
List<Integer> localMinIdxs = getLocalMinIdxs(scores);
for (Integer localMinIdx : localMinIdxs) {
calculateRewards(scores, localMinIdx, res);
}
return sum(res);
}
public static List<Integer> getLocalMinIdxs(int[] array) {
List<Integer> localMinIdxs = new ArrayList<>();
for (int i = 0; i < array.length; i++) {
if (i == 0 && array[i] < array[i + 1]) localMinIdxs.add(0);
if (i == array.length - 1 && array[i] < array[i - 1]) localMinIdxs.add(i);
if (i == 0 || i == array.length - 1) continue;
if (array[i] < array[i - 1] && array[i] < array[i + 1]) {
localMinIdxs.add(i);
}
}
return localMinIdxs;
}
public static void calculateRewards(int[] scores, Integer localMinIdx, int[] res) {
int left = localMinIdx - 1;
while (left >= 0 && scores[left] > scores[left + 1]) {
res[left] = Math.max(res[left], res[left + 1] + 1);
left--;
}
int right = localMinIdx + 1;
while (right < scores.length && scores[right] > scores[right - 1]) {
res[right] = Math.max(res[right], res[right - 1] + 1);
right++;
}
}
public static int sum (int[] array) {
int sum = 0;
for (int num : array) {
sum += num;
}
return sum;
}
}
解法三:
总体来讲和第二种解法思路一样,只不过不需要记录localMin的索引,从前和从后分别遍历一遍,只找后一个数比自己大的去更新分数(更新过程中需要比较新分数和原来久分数的大小,取最大值)。这个方法模拟了找localMin的处理方法。
Time: O(n) Space: O(n)
代码:
import java.util.*;
class Program {
public static int minRewards(int[] scores) {
// Write your code here.
int[] res = new int[scores.length];
Arrays.fill(res, 1);
for (int i = 1; i < scores.length; i++) {
if (scores[i] > scores[i - 1]) {
res[i] = Math.max(res[i], res[i - 1] + 1);
}
}
for (int i = scores.length - 2; i >= 0; i--) {
if (scores[i] > scores[i + 1]) {
res[i] = Math.max(res[i], res[i + 1] + 1);
}
}
return sum(res);
}
public static int sum (int[] array) {
int sum = 0;
for (int num : array) {
sum += num;
}
return sum;
}
}
解法四:
直接把第一个reward设置为0,从头扫描一遍,如遇递增则a[i] = a[i-1] + 1,否则为a[i] = a[i-1] - 1,期间记录a[i]的最小值,单独处理头递增/尾递减,最后统一处理负数。
Time: O(n) Space: O(n)
代码:
import java.util.*;
class Program {
public static int minRewards(int[] scores) {
// Write your code here.
int len = scores.length;
int[] res = new int[len];
int sum = 0;
int minVal = 1;
for (int i = 1; i < len; i++) {
if (scores[i] > scores[i - 1]) {
res[i] = res[i - 1] + 1;
}
else res[i] = res[i - 1] - 1;
sum += res[i];
minVal = Math.min(res[i], minVal);
}
if (scores[0] < scores[1]) {
sum = sum - res[0] + minVal;
}
if (scores[len - 1] < scores[len - 2]) {
sum = sum - res[len - 1] + minVal;
}
return sum + (Math.abs(minVal) + 1) * len;
}
}