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.

110 lines
3.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_10_1_week;
import java.util.Arrays;
// 来自学员问题
// 商场中有一展柜A其大小固定现已被不同的商品摆满
// 商家提供了一些新商品B需要对A中的部分商品进行更新替换
// B中的商品可以自由使用也就是可以用B中的任何商品替换A中的任何商品
// A中的商品一旦被替换就认为消失了而不是回到了B中
// 要求更新过后的展柜中,商品严格按照价格由低到高进行排列
// 不能有相邻商品价格相等的情况
// A[i]为展柜中第i个位置商品的价格B[i]为各个新商品的价格
// 求能够满足A中商品价格严格递增的最小操作次数若无法满足则返回-1
public class Code03_MakeASortedMinSwaps {
// 可以用B里的数字替换A里的数字想让A严格递增
// 返回至少换几个数字
public static int minSwaps(int[] A, int[] B) {
// 根据题意B里的数字随意拿
// 所以B里的数字排序不会影响拿
// 同时A如果从左往右考虑依次被B替换上去的数字肯定是从小到大的
// 这是一定的比如B = {5,3,2,9}
// 可能先用5替换A的某个左边的数再用2替换A的某个右边的数吗不可能
// 所以将B排序
Arrays.sort(B);
int ans = process(A, B, 0, 0, 0);
return ans == Integer.MAX_VALUE ? -1 : ans;
}
// 参数解释:
// A[0...ai-1]范围上已经做到升序了
// 接下来请让A[ai....]范围上的数字做到升序
// 之前的过程中B里可能已经拿过一些数字了
// 拿过的数字都在B[0...bi-1]范围上,不一定都拿了
// 但是最后拿的数字一定是B[bi-1]
// 如果想用B里的数字替换当前的A[ai]请在B[bi....]范围上考虑拿数字
// pre : 表示之前的A[ai-1]被替换了没有,
// 如果pre==0表示A[ai-1]没被替换
// 如果pre==1表示A[ai-1]被替换了被谁替换的被B[bi-1]替换的!
// 返回值让A[ai....]范围上的数字做到升序最少还要在B[bi...]上拿几个数字
// 如果返回值是Integer.MAX_VALUE表示怎么都做不到
// 这就是一个三维动态规划,自己改!
// ai 是N范围
// bi 是M范围
// pre 只有0、1两种值
// 所以时间复杂度O(N*M*logM)
// 这个logM怎么来的二分来的看代码
public static int process(int[] A, int[] B, int ai, int bi, int pre) {
if (ai == A.length) {
return 0;
}
// 之前的数是什么
int preNum = 0;
if (ai == 0) {
preNum = Integer.MIN_VALUE;
} else {
if (pre == 0) {
preNum = A[ai - 1];
} else {
preNum = B[bi - 1];
}
}
// 可能性1搞定当前的A[ai],不依靠交换
int p1 = preNum < A[ai] ? process(A, B, ai + 1, bi, 0) : Integer.MAX_VALUE;
// 可能性2搞定当前的A[ai],依靠交换
int p2 = Integer.MAX_VALUE;
// 在B[bi....]这个范围上,找到>preNum最左的位置
// 这一步是可以二分的因为B整体有序
int nearMoreIndex = bs(B, bi, preNum);
if (nearMoreIndex != -1) {
int next2 = process(A, B, ai + 1, nearMoreIndex + 1, 1);
if (next2 != Integer.MAX_VALUE) {
p2 = 1 + next2;
}
}
return Math.min(p1, p2);
}
// 在B[start....]这个范围上,找到>num最左的位置
public static int bs(int[] B, int start, int num) {
int ans = -1;
int l = start;
int r = B.length - 1;
int m = 0;
while (l <= r) {
m = (l + r) / 2;
if (B[m] > num) {
ans = m;
r = m - 1;
} else {
l = m + 1;
}
}
return ans;
}
public static void main(String[] args) {
int[] A1 = { 1, 8, 3, 6, 9 };
int[] B1 = { 1, 3, 2, 4 };
System.out.println(minSwaps(A1, B1));
int[] A2 = { 4, 8, 3, 10, 5 };
int[] B2 = { 1, 3, 2, 4 };
System.out.println(minSwaps(A2, B2));
int[] A3 = { 1, 8, 3, 6, 9 };
int[] B3 = { 4, 3, 1 };
System.out.println(minSwaps(A3, B3));
}
}