You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
4.6 KiB

2 years ago
package class40;
// 来自腾讯
// 比如arr = {3,1,2,4}
// 下标对应是0 1 2 3
// 你最开始选择一个下标进行操作,一旦最开始确定了是哪个下标,以后都只能在这个下标上进行操作
// 比如你选定1下标1下标上面的数字是1你可以选择变化这个数字比如你让这个数字变成2
// 那么arr = {3,2,2,4}
// 下标对应是0 1 2 3
// 因为你最开始确定了1这个下标所以你以后都只能对这个下标进行操作
// 但是,和你此时下标上的数字一样的、且位置连成一片的数字,会跟着一起变
// 比如你选择让此时下标1的数字2变成3
// 那么arr = {3,3,3,4} 可以看到下标1和下标2的数字一起变成3这是规则一定会一起变
// 下标对应是0 1 2 3
// 接下来你还是只能对1下标进行操作那么数字一样的、且位置连成一片的数字(arr[0~2]这个范围)都会一起变
// 决定变成4
// 那么arr = {4,4,4,4}
// 下标对应是0 1 2 3
// 至此所有数都成一样的了你在下标1上做了3个决定(第一次变成2第二次变成3第三次变成4)
// 因为联动规则arr全刷成一种数字了
// 给定一个数组arr最开始选择哪个下标你随意
// 你的目的是一定要让arr都成为一种数字注意联动效果会一直生效
// 返回最小的变化数
// arr长度 <= 200, arr中的值 <= 10^6
public class Code05_AllSame {
public static int allSame1(int[] arr) {
int ans = Integer.MAX_VALUE;
for (int i = 0; i < arr.length; i++) {
ans = Math.min(ans, process1(arr, i - 1, arr[i], i + 1));
}
return ans;
}
// 左边arr[0..left]如果left == -1说明没有左边了
// 右边arr[right...n-1]如果right == n说明没有右边了
// 中间的值是midV中间的值代表中间一整个部分的值中间部分有可能是一个数也可能是一堆数但是值都为midV
// 返回arr都刷成一样的最小代价是多少
// left 可能性 : N
// right 可能性 : N
// midV 可能性 : arr中的最大值
public static int process1(int[] arr, int left, int midV, int right) {
for (; left >= 0 && arr[left] == midV;) {
left--;
}
for (; right < arr.length && arr[right] == midV;) {
right++;
}
if (left == -1 && right == arr.length) {
return 0;
}
int p1 = Integer.MAX_VALUE;
if (left >= 0) {
p1 = process1(arr, left - 1, arr[left], right) + 1;
}
int p2 = Integer.MAX_VALUE;
if (right < arr.length) {
p2 = process1(arr, left, arr[right], right + 1) + 1;
}
return Math.min(p1, p2);
}
public static int allSame2(int[] arr) {
int ans = Integer.MAX_VALUE;
for (int i = 0; i < arr.length; i++) {
ans = Math.min(ans, process2(arr, i - 1, true, i + 1));
}
return ans;
}
// 左边arr[0..l]如果left == -1说明没有左边了
// 右边arr[r...n-1]如果right == n说明没有右边了
// 中间的值代表arr[l+1...r-1]这个部分的值已经刷成了一种
// 中间的值如果和arr[l+1]一样isLeft就是true
// 中间的值如果和arr[r-1]一样isLeft就是false
// 返回arr都刷成一样的最小代价是多少
// left 可能性 : N
// right 可能性 : N
// isLeft 可能性 : true/false,两种
public static int process2(int[] arr, int l, boolean isLeft, int r) {
int left = l;
for (; left >= 0 && arr[left] == (isLeft ? arr[l + 1] : arr[r - 1]);) {
left--;
}
int right = r;
for (; right < arr.length && arr[right] == (isLeft ? arr[l + 1] : arr[r - 1]);) {
right++;
}
if (left == -1 && right == arr.length) {
return 0;
}
int p1 = Integer.MAX_VALUE;
if (left >= 0) {
p1 = process2(arr, left - 1, true, right) + 1;
}
int p2 = Integer.MAX_VALUE;
if (right < arr.length) {
p2 = process2(arr, left, false, right + 1) + 1;
}
return Math.min(p1, p2);
}
// 如上的递归,请改动态规划,具体参考体系学习班,动态规划大章节!
// 为了测试
public static int[] randomArray(int maxSize, int maxNum) {
int size = 2 + (int) (Math.random() * maxSize);
int[] arr = new int[size];
for (int i = 0; i < size; i++) {
arr[i] = 1 + (int) (Math.random() * maxSize);
}
return arr;
}
// 为了测试
public static void main(String[] args) {
System.out.println("测试开始");
for (int i = 0; i < 10000; i++) {
int[] arr = randomArray(20, 10);
int ans1 = allSame1(arr);
int ans2 = allSame2(arr);
if (ans1 != ans2) {
System.out.println("出错了!!!");
for (int i1 : arr) {
System.out.print(i1 + " ");
}
System.out.println();
System.out.println(ans1);
System.out.println(ans2);
break;
}
}
System.out.println("测试结束");
}
}