1.给定两个排序后的数组A和B,其中A的末端有足够的缓冲空容纳B。编写一个方法,将B合并入A并排序。
思路:从数组A和B的末端元素开始,将最大的元素放到数组A的末端。
public static void merge(int[] a, int[] b, int lastA, int lastB) { int indexA = lastA - 1; int indexB = lastB - 1; int indexMerged = lastB + lastA - 1; while (indexA >= 0 && indexB >= 0) { if (a[indexA] > b[indexB]) { a[indexMerged] = a[indexA]; indexMerged--; indexA--; } else { a[indexMerged] = b[indexB]; indexMerged--; indexB--; } } while (indexB>= 0) { a[indexMerged] = b[indexB]; indexMerged--; indexB--; } }
2.编写一个方法,对字符串数组进行排序,将所有变位词排在相邻的位置。
解法一:套用一种标准排序算法,比如归并排序或快速排序,并修改比较器(comparator)。这个比较器用来指示两个字符串互为变位词就是相等的。
检查两个词是否为变位词的方法?(1)数一数每个字符串中各个字符出现的次数,两者相同则返回true。(2)对字符串进行排序,若两个字符串互为变位词,排序后就相同。
//比较器实现代码 public class AnagramComparator implements Comparator<String> { public String sortChars(String s) { char[] content = s.toCharArray(); Arrays.sort(content); return new String(content); } public int compare(String s1, String s2) { return sortChars(s1).compareTo(sortChars(s2)); } } //利用这个比较器对数组进行排序 Arrays.sort(array, new AnagramComparator());
这个算法的时间复杂度是O(nlogn)。
解法二:使用散列表将排序后的单词映射到它的一个变位词列表。例:acre会映射到列表{acre, race, care}。一旦将所有同为变位词的单词分组在一起,就可以将它们放回到数组中。
public static void sort(String[] array) { Hashtable<String, LinkedList<String>> hash = new Hashtable<String, LinkedList<String>>(); //将同为变位词的单词分在同一组 for (String s : array) { String key = sortChars(s); if (!hash.containsKey(key)) { hash.put(key, new LinkedList<String>()); } LinkedList<String> anagrams = hash.get(key); anagrams.push(s); } //将散列表转换为数组 int index = 0; for (String key : hash.keySet()) { LinkedList<String> list = hash.get(key); for (String t : list) { array[index] = t; index++; } } } public static String sortChars(String s) { char[] content = s.toCharArray(); Arrays.sort(content); return new String(content); }
3.给定一个排序后的数组,包含n个整数,但这个数组已被旋转过很多次,次数不详。请编写代码找出数组中的某个元素。可以假定数组元素原先是按从小到大的顺序排列的。
解法:《九章算法》chapter two search-in-rotated-sorted-array
4.设想你有一个20GB的文件,每一行一个字符串。请说明将如何对这个文件进行排序。
思路:只将部分数据载入内存。将整个文件划分成许多块,每个块xMB,其中x是可用的内存大小。每个块各自进行排序,然后存回文件系统。各个块一旦完成排序,便将这些块逐一合并在一起,最终就能得到全都排好序的文件。这个算法被称为外部排序(external sort)。
5.有个排序后的字符串数组,其中散布着一些空字符串,编写一个方法,找出给定字符串的位置。
思路:如果没有那些空字符串,就可以直接使用二分查找法。比较待查找字符串str和数组的中间元素,然后继续搜索下去。针对此题,可对二分查找法稍作修改,所需的修改就是与mid进行比较的地方,如果mid为空字符串,就将mid换到离它最近的非空字符串的位置。
public static int findString(String[] a, String key) { int left = 0; int right = a.length - 1; while (left <= right) { int mid = (left + right) / 2; while (mid < right && a[mid] == "") { mid++; } while (mid > left && a[mid] == "") { mid--; } if (key.equals(a[mid])) { return mid; } else if (key.compareTo(a[mid]) < 0){//key小于a[mid] right = mid - 1;//搜索左半边 } else { left = mid + 1; } } return -1; }
6.给定M* N矩阵,每一行、每一列都按升序排列,请编写代码找出某元素。
解法:《九章算法》chapter two search-a-2d-matrix
7.有个马戏团正在设计叠罗汉的表演节目,一个人要站在另一人的肩膀上。出于实际和美观的考虑,在上面的人要比下面的人矮一点、轻一点。已知马戏团每个人的高度和重量,请编写代码计叠罗汉最多能叠几个人。
问题实质:给定一个列表,每个元素由一对项目组成。找出最长的子序列,其中第一项和第二项均以非递减的顺序排列。
8.假设你正在读取一串整数。每隔一段时间,你希望能找出数字x的秩(小于或等于x的值的数目)。请实现数据结构和算法支持这些操作。也就是说,实现track(int x)方法,每读入一个数字都会调用该方法;以及getRankOfNumber(int x)方法,返回值为小于或等于x的元素个数(不包括x本身)。