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--;
        }
    }
View Code

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());
View Code

这个算法的时间复杂度是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);
    }
View Code

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;
    }
View Code

6.给定M* N矩阵,每一行、每一列都按升序排列,请编写代码找出某元素。

解法:《九章算法》chapter two search-a-2d-matrix

7.有个马戏团正在设计叠罗汉的表演节目,一个人要站在另一人的肩膀上。出于实际和美观的考虑,在上面的人要比下面的人矮一点、轻一点。已知马戏团每个人的高度和重量,请编写代码计叠罗汉最多能叠几个人。

问题实质:给定一个列表,每个元素由一对项目组成。找出最长的子序列,其中第一项和第二项均以非递减的顺序排列。

8.假设你正在读取一串整数。每隔一段时间,你希望能找出数字x的秩(小于或等于x的值的数目)。请实现数据结构和算法支持这些操作。也就是说,实现track(int x)方法,每读入一个数字都会调用该方法;以及getRankOfNumber(int x)方法,返回值为小于或等于x的元素个数(不包括x本身)。