随机题两题
逆序对
题目
给定一个数组,求其中有多少逆序对,要求时间复杂度不超过nlogn。
思路
- 使用归并排序的分治思想,将数组递归地分为左右两部分。
- 在合并两个有序子数组时,若左侧数组中的某个数大于右侧数组中的某个数,则可以确定该左侧数组中的这个数和右侧数组中当前及其后的所有元素形成逆序对。
- 递归合并的过程中,统计所有逆序对的数量。
代码
private static int countInversions(int[] num) {
int left = 0, right = num.length - 1;
int[] temp = new int[num.length];
return countSum(num,temp,left,right);
}
private static int countSum(int[] num, int[] temp, int left, int right) {
if(left>=right){
return 0;
}
int mid = left + (right - left) / 2;
int count = countSum(num,temp,left,mid);
count=count+countSum(num,temp,mid+1,right);
count=count+countNum(num,temp,left,mid,right);
return count;
}
private static int countNum(int[] num, int[] temp, int left, int mid,int right) {
int i=left,j=mid+1;
int k=0,count=0;
while(i<=mid&&j<=right){
if(num[i]<num[j]){
temp[k++]=num[i++];
}else{
temp[k++]=num[j++];
count = count+(mid-i+1);
}
}
while(i<=mid){
temp[k++]=num[i++];
}
while(j<=right){
temp[k++]=num[j++];
}
for(int p=left;p<=right;p++){
num[p]=temp[p];
}
return count;
}
均衡
题目
这是一个通过移动数组元素值实现尽量“均衡”的问题。目标是使数组中元素尽量相等,或者趋于相同的范围。每次只能移动 1 单位,只能移动相邻的数组。
例如数组【1,4,6】,下标为1的数组元素4,可以移动移动一单位给1或者6,将数组变为【2,3,6】或者【1,3,7】。
要求数组达到【3,4,4】,数组顺序不限。
思路
直接一个模拟
- 不断调整相邻的元素,逐步趋近于配平。
- 打印每次移动的过程,直到达到平衡或接近平衡。
代码
public static void balanceArray(int[] arr) {
int moves = 0;
int n = arr.length;
while (!isBalanced(arr)) {
for (int i = 0; i < n - 1; i++) {
if (arr[i] < arr[i + 1]) {
arr[i]++;
arr[i + 1]--;
moves++;
printArray(arr, moves);
}
else if (arr[i] > arr[i + 1]) {
arr[i]--;
arr[i + 1]++;
moves++;
printArray(arr, moves);
}
}
}
System.out.println("Total moves: " + moves);
}
private static boolean isBalanced(int[] arr) {
int total = Arrays.stream(arr).sum();
int remainder = total % arr.length;
int first = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] != first&&Math.abs(first-arr[i])>remainder) {
return false;
}
}
return true;
}
private static void printArray(int[] arr, int step) {
System.out.println("Step " + step + ": " + Arrays.toString(arr));
}