排序有关的问题在面试题中相当多。对于参加面试的人来说,最基本的merge sort和quick sort肯定是必须掌握的,而且要能快速地写出bug free的代码。这次总结的是两道mergeSort-like问题。
Question 1:
qaz is a value for a number where this number is less than the other next values which have indexes larger than the index of this number.
for example: 33 , 25 , 26 , 58 , 41 , 59 -> qaz of (33) = 3 where 33 less than 3 numbers (58 , 41 , 59), qaz of (25) = 4 and not 5 because the index of 33 is less than the index of 25, qaz of (26) = 3 , qaz of (58) = 1 , qaz of (41) = 1 , qaz of (59) = 0.
Naive的算法就是brute force,检测每一对元素的大小关系,时间复杂度为O(N^2)。仔细一看就能发现题目的本质就是排序的算法。如果你用tree sort的思路来建立平衡二叉树,自然也可以解决这个问题(建立一颗空树,依次插入元素,节点存储比它大的元素的个数,时间复杂度为O(Nlog(N)),空间复杂度为O(N))。但这对于面试题来说显然是自找麻烦。很容易想到的方法即merge sort(时间复杂度为O(Nlog(N)),空间复杂度为O(N)),而merge sort中改变元素位置的操作是merge操作。因此,在merge操作中A数组(左边)和B数组(右边)合并时,若选择的元素a在A数组,则qaz(a)+=B剩余的元素数量,因为这些数原本出现在a右边并大于a;若选择的元素a在B数组,则不需要更新qaz(a)的值。
public class mergeSort1 { public static void main(String arcg[]){ mergeSort1 h = new mergeSort1(); int[] array = {33,25,26,58,41,59}; pair[] array2 = new pair[array.length]; for(int i=0;i<array.length;i++){ array2[i] = h.new pair(array[i]); } h.sort(array2); for(int i=0;i<array2.length;i++){ System.out.println(array2[i].val + ": " + array2[i].qaz); } } class pair{ int val; int qaz; public pair(int val){ this.val = val; qaz = 0; } } private pair[] array; private pair[] helper; void sort(pair[] array){ this.array = array; this.helper = new pair[array.length]; mergeSort(0,array.length-1); } void mergeSort(int low, int high){ if(low < high){ int mid = low+(high-low)/2; mergeSort(low, mid); mergeSort(mid+1, high); merge(low,mid,high); } } void merge(int low, int mid, int high){ for(int i=low;i<=high;i++) helper[i] = array[i]; int i=low, j=mid+1,k=low; while(i<=mid && j<=high){ if(helper[i].val<=helper[j].val){ array[k] = helper[i++]; array[k].qaz += high-j+1; } else{ array[k] = helper[j++]; } k++; } while(i<=mid) array[k++] = helper[i++]; } }
Question 2:
Counting inversion.
Finding "similarity" between two rankings. Given a sequence of n numbers 1..n (assume all numbers are distinct). Define a measure that tells us how far this list is from being in ascending order. The value should be 0 if a_1 < a_2 < ... < a_n and
should be higher as the list is more "out of order".
Example
2 4 1 3 5
1 2 3 4 5
The sequence 2, 4, 1, 3, 5 has three inversions (2,1), (4,1), (4,3).
和第一题同样的思路,在merge操作时当选择的元素在B数组中的时候,会产生A数组剩余元素数量的逆序。
public class mergeSort2 { public static void main(String arcg[]){ int[] input = {2,4,1,3,5}; sort(input); System.out.println(invertionCount); } private static int[] array; private static int[] helper; private static int invertionCount; public static void sort(int[] input){ array = input; helper = new int[array.length]; mergeSort(0,array.length-1); } public static void mergeSort(int low, int high){ if(low<high){ int mid = low+(high-low)/2; mergeSort(low,mid); mergeSort(mid+1,high); merge(low,mid,high); } } public static void merge(int low, int mid, int high){ for(int i=low;i<=high;i++) helper[i] = array[i]; int i=low,j=mid+1,k=low; while(i<=mid && j<=high){ if(helper[i] < helper[j]){ array[k++] = helper[i++]; } else{ invertionCount+=mid-i+1; array[k++] = helper[j++]; } } while(i<=mid) array[k++] = helper[i++]; } }