题1:给定两个排序后的数组A和B, 其中A的末端有足够的缓冲空间容纳B, 编写一个方法, 将B合并入A并排序
解题思路: 定义指针a和指针b,如果a>=b,a元素等于current元素,指针a左移一位,指标current左移一位,直到a指针或者b指针小于0, 这里考虑到如果数组B整体小于数组A,可能指针a走出了边界,指针b左边的元素全部挪过去,如果是指针b先出了边界,指针a左边的元素不需挪动,因为整体已经有序了,自己可以图画试试
代码如下
static void mergeSort(int[] A, int[] B) {
// 待插入元素的位置
int current = A.length - 1;
// 数组a待比较元素下标
int a = A.length - B.length - 1;
// 数组b待比较元素下标
int b = B.length - 1;
while (a >= 0 && b >= 0) {
if (A[a] >= B[b]) {
A[current] = A[a];
a--;
current--;
}
else {
A[current] = B[b];
b--;
current--;
}
}
// 考虑到数组B没走完
while (b >= 0) {
A[current] = B[b];
b--;
current--;
}
Util.printArr(A);
}
题2:逆序对个数 一个数列, 如果左边的数大, 右边的数小, 侧称这两个数为一个逆序对, 求一个数列有几个逆序对
解题思路1:暴力破解法,依次扫描数组中每个数在它右边的元素并比较, O(n²)
代码如下
/**
* @param arr 数组
* @param l 开始下标
* @param r 结束下标
* @param count 逆序对个数(初始化为0)
* @return 返回逆序对个数
*/
static int topic2(int[] arr, int l, int r, int count) {
// 边界, 当l走到r的位置, 说明没有需要比较的元素了, 直接返回count
if (l == r) {
return count;
}
// 不断更新l, i表示向右推进的指针
int i = l;
// 往右侧扫描比它小的数
while (i < r) {
if (arr[l] > arr[i+1]) // 如果比它小count++
count++;
i++;
}
return topic2(arr, l + 1, r,count);
}
解题思路2: 利用归并排序解题, 可以很好的优化时间复杂度, nlogn
代码如下
// 辅助空间数组
static int[] helper;
// 逆序对个数
static int niXu = 0;
private static void mergeSort(int[] arr) {
helper = new int[arr.length];
mergeSort(arr,0, arr.length-1);
}
private static void mergeSort(int[] arr, int l, int r) {
if (l < r) {
int mid = l + ((r - l) >> 1);
mergeSort(arr,l, mid);
mergeSort(arr, mid+1, r);
// 合并
merge(arr, l, mid, r);
}
}
public static void merge(int[] arr, int l, int mid, int r) {
//拷贝到辅助空间的相同位置
System.arraycopy(arr, l, helper, l, r - l + 1);
// 辅助数组的两个指针
int left = l, right = mid+1;
// 原始数组的指针
int current = l;
while (left <= mid && right <= r) {
if (helper[left] <= helper[right]) {
arr[current++] = helper[left++];
} else {
arr[current++] = helper[right++];
// 右边小说明有逆序对
niXu += mid-left+1;
}
}
while (left <= mid) {
arr[current] = helper[left];
current++;
left++;
}
}
有什么问题欢迎大佬指正