`

百度笔试题:一个已经排序好的很大的数组,现在给它划分成m段,每段长度不定,段长最长为k,然后段内打乱顺序,请设计一个算法对其进行重新排序

阅读更多

import java.util.Arrays;

/**
 * 最早是在陈利人老师的微博看到这道题:
 * #面试题#An array with n elements which is K most sorted,就是每个element的初始位置和它最终的排序后的位置的距离不超过常数K
 * 设计一个排序算法。It should be faster than O(n*lgn)。
 * 
 * 英文原题是:
 * Given an array of n elements, where each element is at most k away from its target position, devise an algorithm that sorts in O(n log k) time. 
 * For example, let us consider k is 2, an element at index 7 in the sorted array, can be at indexes 5, 6, 7, 8, 9 in the given array.
 * 
 * 微博里面的回复提到这道题的另一个表述:
 * @castomer:回复@华仔陶陶:今年百度校园招聘笔试题目我遇到了一道题和这个基本一样。“
 * 一个已经排序好的很大的数组,现在给它划分成m段,每段长度不定,段长最长为k,然后段内打乱顺序,请设计一个算法对其进行重新排序” 
 * 
 * 两种解法:
 * 1、插入排序,时间复杂度是O(n*k)
 *    由于“K most sorted”,寻找位置时最多只会寻找k位,因此复杂度从最坏情况的O(n*n)下降到O(n*k), 但插入排序没有充分利用“K most sorted”这个条件
 * 2、最小堆
 *    @castomer 认为堆的大小是k
 *    这要看k most sorted怎么理解了
 *    例如,如果对于{4, 3, 2, 1}认为k=3,那么堆的大小就应该是4。因为如果取3的话,第一次最小堆{2, 3, 4}排序后取出最小值2,第二次最小堆排序后取出最小值1,2排在1前面,显然不合理
 *    
 *    最小堆的时间复杂度是O(k) + (n-k) * O(lgk):
 *    建堆:O(k),k为堆的大小
 *    堆排序:(n-k) * O(lgk)
 *    
 */
public class KSortedArray {

    public static void main(String[] args) {
        int k = 3;
        int[] array = {2, 6, 3, 12, 56, 8};
        insertSort(array);
        minHeapSort(array, k);
    }
    
    public static void insertSort(int[] arrayToSort) {

        //...略去输入合法性检查
        
        //复制数组,不影响原数组
        int len = arrayToSort.length;
        int[] array = new int[len];
        System.arraycopy(arrayToSort, 0, array, 0, len);
        
        for (int i = 1; i < len; i++) {
            int itemToInsert = array[i];
            while(i > 0 && itemToInsert < array[i - 1]) {
                array[i] = array[i - 1];
                i--;
            }
            array[i] = itemToInsert;
        }
        
        System.out.println(Arrays.toString(array));
    }

    public static void minHeapSort(int[] arrayToSort, int k) {
        
        int len = arrayToSort.length;
        int[] array = new int[len];
        System.arraycopy(arrayToSort, 0, array, 0, len);
        
        int[] sortedArray = new int[len];
        int[] heapValues = new int[k + 1];
        System.arraycopy(array, 0, heapValues, 0, k + 1);
        MinHeap heap = new MinHeap(heapValues);
        
        //将剩下的元素陆续推入堆里,并“吐”出最小值
        int j = 0;
        for (int i = k + 1; i < len; i++) {
            sortedArray[j++] = heap.getRootValue();
            heap.replaceRootValueWith(array[i]);
            heap.reheap();
        }
        
        //没有更多元素进入了,此时剩下k个元素,堆不断收缩,直至为0
        //事实上这个while循环可以并入上面的for循环
        while (j < len) {
            sortedArray[j++] = heap.getRootValue(); 
            heap.minimize();
        }
        
        System.out.println(Arrays.toString(sortedArray));
    }
}


/**
 * 最小堆,只将本次排序中调用到的方法声明为public
 */
class MinHeap {
    
    private int[] values;
    private int lastIndex;
    
    public MinHeap(int[] values) {
        init(values);
    }
    
    public void reheap() {
        reheapCore(0, values.length - 1);
    }
    
    public int getRootValue() {
        return values[0];
    }
    
    public void replaceRootValueWith(int newRootValue) {
        values[0] = newRootValue;
    }
    
    public void minimize() {
        if (lastIndex > 0) {
            this.replaceRootValueWith(values[lastIndex]);
            lastIndex--;
            this.reheapCore(0, lastIndex);
        }
    }
    
    private void init(int[] values) {
        int size = values.length;
        this.lastIndex = size - 1;
        this.values = new int[size];
        System.arraycopy(values, 0, this.values, 0, size);
        int lastIndex = size - 1;
        int lastRootIndex = getRootIndex(lastIndex);
        for (int rootIndex = lastRootIndex; rootIndex >= 0; rootIndex--) {
            reheapCore(rootIndex, lastIndex);
        }
    }
    
    private void reheapCore(int rootIndex, int lastIndex) {
        if (!(isValidIndex(rootIndex) && isValidIndex(lastIndex))) {
            System.out.println("invalid parameters");
            return;
        }
        int orphan = values[rootIndex];
        int leftIndex = getLeftIndex(rootIndex);
        boolean done = false;
        while (!done && leftIndex <= lastIndex) {
            int rightIndex = getRightIndex(rootIndex);
            int smallerIndex = leftIndex;
            if (rightIndex <= lastIndex && values[rightIndex] < values[leftIndex]) {
                smallerIndex = rightIndex;
            } 
            if (values[smallerIndex] < values[rootIndex]) {
                swap(values, smallerIndex, rootIndex);
                rootIndex = smallerIndex;
                leftIndex = getLeftIndex(rootIndex);
            } else {
                done = true;
            }
        }
        values[rootIndex] = orphan;
        //System.out.println(Arrays.toString(values));
    }
    
    private int getLeftIndex(int rootIndex) {
        return rootIndex * 2 + 1;
    }
    
    private int getRightIndex(int rootIndex) {
        return rootIndex * 2 + 2;
    }
    
    private int getRootIndex(int childIndex) {
        return (childIndex - 1) / 2;
    }
    
    private boolean isValidIndex(int index) {
        return index >=0 && index < values.length;
    }
    
    private void swap(int[] array, int i, int j) {
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }
    
}
2
1
分享到:
评论

相关推荐

    百度笔试题之数组差值(题目与源码)

    百度笔试题之数组差值(题目与源码) ********************************* 给定一个长度为n并且只含有非负整数的数组A,显然这个数组一共有n*(n+1)/2个区间(每个区间至少有一个元素)。给定m个查询值K,对于每个...

    百度笔试题——一套完整的百度笔试题

    【百度笔试题】是应聘者在申请百度职位时可能会遇到的测试内容,涵盖了一系列的编程基础知识,主要包括排序算法、多线程同步、内存管理、网络协议、数据结构和操作系统等主题。下面是对这些知识点的详细解释: 1. *...

    百度笔试试题(很齐全)

    - 如果第一个数组指针所指元素小于第二个数组指针所指元素,则移动第一个数组的指针;反之则移动第二个数组的指针。 ### 2. 数据结构与算法问题 #### 知识点概述: 这部分涉及到了数据结构的选择、查询效率优化...

    百度笔试题 百度笔试题

    【百度笔试题】涵盖的内容广泛,涉及编程、算法、系统设计等多个方面,下面将逐一解析这些题目中的知识点。 1. **编程题 - 字符串判断**: 这道题目要求编写一个函数来判断字符串b的所有字符是否都在字符串a中出现...

    百度笔试题(含部分参考答案)

    归并排序是一种分治算法,它将数组分为两半,分别排序,然后合并,因此排序过程不受初始顺序影响。 2. 多线程对整型变量x的操作中,需要同步的是那些可能改变x值的写操作,包括B. x++、C. ++x和D. x=1。同步是为了...

    百度历年笔试题

    百度笔试题常常涉及到算法与数据结构的运用,如排序算法(快速排序、归并排序等)、查找算法(二分查找、哈希查找)以及常用的数据结构(链表、栈、队列、树、图)。这些基础知识是解决问题的基础,熟练掌握能提高...

    百度公司笔试题

    从给定的百度公司笔试题中,我们可以提炼出多个IT领域的知识点,主要集中在数据结构、算法、编程语言特性以及操作系统原理上。以下是对这些知识点的详细解析: ### 数据结构与算法 1. **排序算法的特性**:题目...

    python笔试例题(快速排序、二分查找、最长无重复子串、最长回文串长度、输出数组中两数相加=target的下标、用两.pdf

    它的基本思想是通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,然后分别对这两部分记录继续进行排序,以达到整个序列有序。在Python中,可以通过递归实现快速排序,如...

    百度java笔试题

    对于一个长度为N的数组,循环左移m位,可以先创建一个新的数组,然后从原数组的m个位置开始复制剩余元素到新数组,最后将原数组的前m个元素复制到新数组的后m个位置。时间复杂度为O(N),空间复杂度为O(N)。 6. **...

    百度网上笔试题及答案

    ### 百度网上笔试题及答案解析 #### 题目一:字符串倒序函数实现 **题目描述:** 编写一个C语言函数`revert`,该函数接收一个字符串作为参数,并将其在原地倒序。 **代码示例:** ```c char* revert(char* str) { ...

    百度历年笔试试题汇总

    【百度历年笔试试题汇总】是一份集合了百度公司历年技术类笔试题目的资源,涵盖了算法、数据结构等多个核心IT领域。这些题目旨在测试应聘者的编程能力、逻辑思维以及对计算机科学基础知识的理解。 1. **数据库通知...

    腾讯百度笔试题

    在IT行业中,尤其是在招聘环节,大公司的笔试题往往成为衡量应聘者技术能力的重要标准。"腾讯百度笔试题"集合了这两家互联网巨头历年来的技术笔试题目,覆盖了多个关键领域,如C语言、数据结构和操作系统等。这些...

    笔试题:输入0123456789对应输出一二三四五六七八九

    本篇文档描述的是一个在线笔试题的解答过程,题目要求是将输入的数字0到9转换成中文的“一二三四五六七八九”。从描述中我们可以了解到,这是一个程序设计相关的题目,要求编程者不仅要处理个位数的转换,还要处理两...

    中级笔试算法题 剑指offer 数组 排序 数据结构 字符串.zip

    排序是处理数据的重要手段,常见的排序算法有冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序等。不同的排序算法有不同的时间复杂度和空间复杂度,选择合适的排序算法对程序性能至关重要。例如,快速排序...

    百度最全笔试题

    【标题】:“百度最全笔试题”所涵盖的IT知识点主要集中在Java编程语言上,这是一份集合了大量关于Java的面试与笔试问题的资源。Java作为广泛应用的面向对象编程语言,其知识点广泛且深入,涵盖了语法基础、数据结构...

    08百度笔试题(北京)

    【标题解析】:“08百度笔试题(北京)”指的是2008年百度公司在北京市进行的一次技术笔试,主要针对系统开发工程师等职位。题目旨在考察应聘者的编程能力、算法理解和系统设计思维。 【描述解析】:16号的百度北京...

    百度校园招聘笔试题 Baidu必备

    3. 百度笔试题汇总:这是一个集合了历年来百度笔试题目的文档,可能包含多届、多岗位的题目,有助于应聘者全面了解百度的出题风格和考察重点。 4. 百度2006,2007笔试题:这部分内容可能包含了百度在2006年和2007年...

    百度笔试题+简介

    根据给定文件中的标题、描述、标签以及部分内容,我们可以从中提炼出有关百度笔试题的相关知识点。下面将逐一解析这些知识点: ### 百度运维部笔试题 #### 知识点概述 - **运维基础知识**:考察对服务器硬件、操作...

    百度技术研发笔试题

    ### 百度技术研发笔试题知识点解析 #### 数据结构与算法 **知识点1:概率计算算法** - **问题描述**:给定两个整数`x`和`y`以及另一个整数`n`,求随机生成`x`个大小在`[1, y]`之间的正整数,使得这些数之和等于`n...

Global site tag (gtag.js) - Google Analytics