[路飞]煎饼排序,任务调度器

122 阅读3分钟

一.#### 煎饼排序

给你一个整数数组 arr ,请使用 煎饼翻转 完成对数组的排序。

一次煎饼翻转的执行过程如下:

选择一个整数 k ,1 <= k <= arr.length 反转子数组 arr[0...k-1](下标从 0 开始) 例如,arr = [3,2,1,4] ,选择 k = 3 进行一次煎饼翻转,反转子数组 [3,2,1] ,得到 arr = [1,2,3,4] 。

以数组形式返回能使 arr 有序的煎饼翻转操作所对应的 k 值序列。任何将数组排序且翻转次数在 10 * arr.length 范围内的有效答案都将被判断为正确。

**解题思路:**本题就是想把一组数据通过不断翻转指导是从小到大排序位置,本题思路是先找到最大数,将最大数通过索引位置翻转到数组第一个位置,然后再利用最大数翻转到最后,这样就将最大数归位了,次大数依次这样翻转,代码如下:

var pancakeSort = function(arr) {
    //记录每个数字的索引
    let ind = {};
    //记录翻转个数
    let ret = [];
    //indSort()方法每次更新数字的索引
    ind = indSort(arr);
    let i = 0
    //循环每个数
    while(i < arr.length){
        //数组最大数就是数组的长度,所以可以找到数组最大数
        let max = arr.length - i;
        //如果最大数已经在相对应的位置,所以不用翻转,最大数如果是1也不需要翻转了
        if(ind[max] !== max - 1 && max > 1 ){
            //保存最大数组的索引,翻转maxIndex就将最大数翻转到第一个位置了
            let maxIndex = ind[max];
            //如果最大索引小于一就没不要翻转了  
            if(maxIndex > 0){
                 //因为索引是从0开始的,所以实际翻转个数要加一
                 ret.push(maxIndex + 1);
                 //将arr数组进行翻转,翻转maxIndex个
                 arr = arrSort(arr,maxIndex);
                 //更新每个数的索引
                 ind = indSort(arr);
            }
            //将最大值由第一个翻转到正确位置,如果最大值是1就不需要翻转了
           if(max > 1){
                 //记录翻转位置,就是本身长度
                 ret.push(max);
                 //数组翻转
                 arr = arrSort(arr,max - 1);
                 //更新索引
                 ind = indSort(arr);   
           }
        }
        //翻转下一个数组
        i ++;
    }
    return ret;
};
//更新数组数字索引
var indSort = function(arr){
    let ind = {}
    //更新索引
    for(let i = 0; i < arr.length; i ++){
        ind[arr[i]] = i;
    }
    return ind;
}
//翻转数组
var arrSort = function(arr,k){
    //定义一个空的数组,接受翻转后的数组
    let newArr = [];
    for(let i = k, j = 0; j < arr.length; i --, j ++){
        //i大于0是未反转前的数字
        if(i >= 0){
             newArr.push(arr[i]);
        }else {
            //i小于0此时剩下的就是已归位的数字,直接赋值就好了
            newArr.push(arr[j]);
        }
    }
    return newArr;
}

二.#### 任务调度器

给你一个用字符数组 tasks 表示的 CPU 需要执行的任务列表。其中每个字母表示一种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。在任何一个单位时间,CPU 可以完成一个任务,或者处于待命状态。

然而,两个 相同种类 的任务之间必须有长度为整数 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。

你需要计算完成所有任务所需要的 最短时间 。

**解题思路:**因为相同任务之间要间隔n秒才能执行,所以可以先将最多的任务找出来,先执行最多的任务,其他任务可以从多到少,安排在冷却的位置,可以知道最多任务的时间是:(i(最多任务的个数) - 1) * (n + 1) + i.这个是最多任务的执行时间,如果同时存在多个相同多的任务,后面还要加几个,如果任务的个数大于最多人事执行时间,name最短时间就是总任务长度,代码如下:

  var leastInterval = function(tasks, n) {
    //记录每个任务的个数
    let typeJson = {};
    //记录最多任务的名称
    let maxText = '';
    //统计每个任务的数量
    let index = 0;
    //开始循环任务
    for(let i = 0; i < tasks.length; i ++){
        //相同的任务不重复计算
        if(!typeJson[tasks[i]]){
            //重置新任务数量
            index = 1;
            //统计相同任务
            for(let k = i + 1; k < tasks.length; k ++){
                //相同任务index加一
                if(tasks[i] === tasks[k]) index ++;
            }
            //将任务的总数记录到typeJson中
            typeJson[tasks[i]] = index;
            //找最多任务的名称
            if(i < 1){
               //默认最多任务是第一个任务
                maxText = tasks[i];
            }else{
               //判断当前任务是否大于maxText,更新最多任务名称
               maxText = index > typeJson[maxText] ? tasks[i] : maxText
            }          
        } ; 
    }
    //计算最多任务执行的最少时间,实际还需要加一,实际还需要加一,因为下面for循环是从第一个开始的,所以这里就不加一了,下面会加
    let maxLength = (typeJson[maxText] - 1) * (n + 1);
    //查找有多少个跟最多任务一样做的任务,如果有就加一,
    for(var key in typeJson){
        if(typeJson[maxText] === typeJson[key]){
            maxLength ++;
        }
    }
    //此时已经计算出最小时间了,判断任务的总长度是否大于最小时间,如果总任务长度大于最小时间就返回任务长度,
    if(maxLength < tasks.length) return tasks.length;
    return maxLength;
};