Android实习面试准备——数据结构与算法(六)

1、旋转输出矩阵

public int[][] generateMatrix(int n) {
        if(n<1)
            return null;
        int[][] matrix = new int[n][n];
        int startX = 0;
        int startY = 0;
        int loop = n/2;
        int mid = n/2;
        int i;
        int j;
        int offset = 1;
        int count = 1;
        while(loop!=0) {
            i = startX;
            j = startY;
            for(j = startY; j < startY + n - offset; j++) 
                matrix[i][j] = count++;
            for(i=startX; i < startX + n - offset; i++)
                matrix[i][j] = count++;
            for(; j > startY; j--) 
                matrix[i][j] = count++;
            for(; i > startX; i--)
                matrix[i][j] = count++;
            startX++;
            startY++;
            offset += 2;
            loop--;
        }
        if(n%2!=0)
            matrix[mid][mid] = count;
        return matrix;
    }

2、给定一个矩阵 int matrix [m][n],每行每列都是增序的,实现一个算法去寻找矩阵中的某个元素 

//从右上角开始搜索
public boolean searchMatrix(int[][] matrix, int target) {
        int rows = matrix.length;
        int columns = matrix[0].length;
        boolean found = false;
        if(matrix != null && rows > 0 && columns > 0) {
            int row = 0;
            int column = columns - 1;
            while(row < rows && column >= 0) {
                if(matrix[row][column] == target) {
                    found = true;
                    break;
                }
                else if(matrix[row][column] > target)
                    column--;
                else row++;
            }
        }
        return found;
    }

3、top-k排序(求最小的k个元素)

思路1:最基本的思路,将N个数进行完全排序,从中选出排在前K的元素。目前来看快速排序、堆排序和归并排序都能达到O(NlogN)的时间复杂度。

思路2:可以采用数据池的思想,选择其中前K个数作为数据池,后面的N-K个数与这K个数进行比较,若小于其中的任何一个数,则进行替换。这种思路的算法复杂度是O(N*K)

从思路2可以想到,剩余的N-K个数与前面K个数比较的时候,是顺序比较的,算法复杂度是K。采用堆可以进一步降低时间复杂度。

思路3:大根堆维护一个大小为K的数组,目前该大根堆中的元素是排名前K的数,其中根是最大的数。此后,每次从原数组中取一个元素与根进行比较,如小于根的元素,则将根元素替换并进行堆调整(下沉),即保证大根堆中的元素仍然是排名前K的数,且根元素仍然最大;否则不予处理,取下一个数组元素继续该过程。该算法的时间复杂度是O(N*logK),该算法不需要一次将原数组中的内容全部加载到内存中,而这正是海量数据处理必然会面临的一个关卡。

        要自己实现一个堆非常麻烦,可以询问一下面试官是否可以使用java中的API。

public int[] getLeastNumbers(int[] arr, int k) {
        int[] result = new int[k];
        if(k == 0) 
            return result;
        PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;
            }
        });
        for (int i = 0; i < k; i++) {
            queue.offer(arr[i]);
        }
        for (int i = k; i < arr.length; i++) {
            if (queue.peek() > arr[i]) {
                queue.poll();
                queue.offer(arr[i]);
            }
        }
        for(int i=0;i<k;i++){
            result[i] = queue.poll();
        }
        return result;
    }

思路4:借鉴快速排序的思想。快排的划分函数每次执行完后都能将数组分成两个部分,小于等于分界值 pivot 的元素的都会被放到数组的左边,大于的都会被放到数组的右边,然后返回分界值的下标。与快速排序不同的是,快速排序会根据分界值的下标递归处理划分的两侧,而这里我们只处理划分的一边,时间复杂度是O(N)

public int[] getLeastNumbers(int[] arr, int k) {
        randomSelected(arr, 0, arr.length - 1, k);
        int[] result = new int[k];
        for (int i = 0; i < k; i++) {
            result[i] = arr[i];
        }
        return result;
    }

    private void randomSelected(int[] arr, int left, int right, int k) {
        if (left >= right)
            return;
        int position = randomPartition(arr, left, right);
        int num = position - left + 1;
        if(k == num)
            return;
        else if(k < num) {
            randomSelected(arr, left, position - 1, k);
        }
        else randomSelected(arr, position + 1, right, k - num);
    }

    private int randomPartition(int[] arr, int start, int end) {
        //注意这个随机数产生的方法,不能忘了后面再加一个start
        int index = new Random().nextInt(end - start + 1) + start;
        swap(arr, index, end);
        int pivot = arr[end];
        int small = start - 1;
        for(index = start; index < end; index++) {
            if(arr[index] <= pivot) {
                small++;
                if(small != index) {
                    swap(arr, index, small);
                }
            }
        }
        swap(arr, ++small, end);
        return small;
    }

    private void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

4、冒泡排序

public static void bubbleSort(int[] arr) {
        if(arr == null || arr.length < 2)
            return;
        for (int i = 0; i < arr.length - 1; i++) {
            for (int j = 0; j < arr.length - i - 1; j++) {
                if(arr[j] > arr[j+1]) {
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }

5、堆排序

public static void heapSort(int[] arr) {
        for (int i = arr.length / 2 - 1; i >= 0; i--) {
            adjustHeap(arr, i, arr.length);
        }
        for(int i = arr.length - 1; i > 0; i--) {
            swap(arr, 0, i);
            adjustHeap(arr, 0, i);
        }
    }

    private static void adjustHeap(int[] arr, int i, int length) {
        int temp = arr[i];
        for (int k = 2 * i + 1; k < length; k = k * 2 + 1) {
            if (k + 1 < length && arr[k] < arr[k + 1])
                k++;
            if (arr[k] > temp) {
                arr[i] = arr[k];
                i = k;
            } else {
                break;
            }
        }
        arr[i] = temp;
    }

    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

6、椭圆形场地有两个赛道,可以同时提供两匹马比赛,两匹马比赛后,可以获知两匹马中跑的快的那匹马,但是没有计时工具。问题,如何最优的算法(比赛次数最少),获知10匹马中速度最快的三匹马

        这道题其实和top-k的意思是一样的,最少的次数其实就是最优的时间复杂度,选择思路4,使用快速排序的思路。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值