IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 截止目前为止,我遇到的最难的一道算法题:计算相邻两个数的最大差值 -> 正文阅读

[数据结构与算法]截止目前为止,我遇到的最难的一道算法题:计算相邻两个数的最大差值

hello,今天给大家带来一道算法题。这道算法题,是我目前为止,见过最难的一道题。那么到底是怎样的一道算法题呢?如下:

题目:给定一个数组, 求如果排序之后, 相邻两数的最大差值。 要求时间复杂度O(N), 且要求不能用非基于比较的排序

我查了一下,暂时没有找到一个在线OJ的链接,只能自己写一个对数器,手动测试了。

img

当初我看到这个题目的时候,说这怎么可能呢?在一个无序的数组中,求相邻两个数据的最大差值。可是我们都知道,现在基于比较的排序算法,最快也只能够达到O(N*logN)的水平,而题目明确限制时间复杂度要是O(N),所以想通过基于比较的排序,排序之后再进行遍历,时间复杂度肯定是达不到要求的。

有人可能也会想说,不是还有基于非比较的排序算法吗?比如计数排序、基数排序、桶排序。但是题目又明确规定了不能使用基于非比较的排序算法。

这样的话,想使用排序算法,进行排序,这条路肯定是行不通的。只能另外想其他的办法。

-------------------------------------------------------------------------------------------我是分割线-----------------------------------------------------------------------------------------

重头戏来了!!!整个代码的流程如下:

  1. 先遍历一遍数组,保存整个数组的最大值最小值

  2. 假设数组中一共有N个元素,那么我们就需要准备N+1个桶

    这每一个桶里面,可以存储一定范围内的数值,而具体可以存储多大范围内的数值,需要用公式去计算。比如:第一个桶存储0……9之间的数,第二个桶存储10……19的数……

  3. 我们再次遍历一遍数组,将每一个数,放入到相应的桶里。

解释:为什么需要进行以上这3个步骤???这是一个非常值得思考的问题!!!

由题可知,一共有N个数,但是我们准备了N+1个桶。也就是说我们将每个数放入相应的桶中,就算这N个数都在各自的桶里,无论怎么放入,始终会多出来1个空桶

而我们会根据一下这个公式,将每个数放入相应的桶:(arr【i】- min)* N / (max - min)。

以上这个公式,就能够计算出i位置的数,应该放入哪一个桶里。根据公式计算,最小值一定会放到第一个桶里,最大值也一定会放到最后一个桶里。那么既然第一个和最后一个桶肯定是有数据的,也就是说明那个空桶肯定是中间的某一个桶

正是因为这个空桶的存在,会将很多种计算的可能性直接抹杀掉。说的具体点,假设一个桶的存储数的范围是0~9,也就是这个桶能够存储10个数,既然有一个空桶的话,那么肯定最后的答案是大于10的。

那么既然大于10的话,这两个数肯定不会在同一个桶里。这样的话,我们就排除了桶里面两个数据的情况,只需要考虑相邻两个桶之间的数,才可能是最终的答案。

image-20211210150413098

就如上图的形式,将所有的数据都放入相应的桶里。因为有空桶的存在,所以我们的答案必然是在两个不同桶之间的数据进行相减。而我们在进行相减的时候,只需要记录每个桶的最大值和最小值即可。也就是说,用后一个桶的最小值,减前一个桶的最大值。以这样的形式,循环N次,将每两个相邻的桶进行计算,就能得到最终的答案。

既然我们只需要每个桶里的最大值和最小值,那就准备两个数组maxs和mins,分别存储即可。代码如下:

image-20211210154546050

以上就是这道题的所有代码,代码不多,但是其中的算法思想我觉得真的是很厉害,很难想象出,想到这个方法的是什么人。

核心就在于那个空桶的存在,抹杀很多的可能性。使其最终的答案只可能存在于相邻两个桶之间的数。

提问:假设给定的某一个数组,算出来桶的数据后,只有一个是空桶。那么最终的答案就一定是这个空桶右边桶的数据减去左边桶的数据吗?

最后,我将整个代码全部放到下面,包括了一个对数器,用于测试以上代码的正确性。

import java.util.Arrays;

public class Code01_CalcTwoNumDiv {
    public static void main(String[] args) {
        int testTime = 5000; //测试次数
        int N = 50; //数组长度
        int range = 1000; //数据范围
        boolean flag = true;
        for (int i = 0; i < testTime; i++) {
            int[] arr = generateArr(N, range);
            int p1 = calcTwoNumDiv(arr);
            int p2 = sortAfter(arr);
            if (p1 != p2) {
                flag = false;
                break;
            }
        }
        System.out.println(flag? "正确" : "错误");
    }

    public static int calcTwoNumDiv(int[] array) {
        if (array == null || array.length < 2) {
            return 0;
        }
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for (int i : array) { //先遍历一遍数组,求最大值最小值
            max = Math.max(max, i);
            min = Math.min(min, i);
        }
        if (max == min) {
            return 0; //如果最大值和最小值相等,说明这个数组只有这一个数据
        }
        int len = array.length;
        boolean[] hasNum = new boolean[len + 1];
        int[] maxs = new int[len + 1];
        int[] mins = new int[len + 1];
        //遍历数据
        for (int i = 0; i < array.length; i++) {
            int bit = getBit(array[i], len, max, min); //桶的位置
            maxs[bit] = hasNum[bit] ? Math.max(maxs[bit], array[i]) : array[i]; //更新最大值
            mins[bit] = hasNum[bit] ? Math.min(mins[bit], array[i]) : array[i]; //更新最小值
            hasNum[bit] = true; //始终更新为true
        }

        //第一个桶和最后一个桶,肯定是有数据的。
        int preMax = maxs[0];
        int res = Integer.MIN_VALUE; //最终的结果
        for (int i = 1; i <= len; i++) {
            if (hasNum[i]) {
                res = Math.max(res, mins[i] - preMax);
                preMax = maxs[i]; //更新前一个的最大值
            }
        }
        return res;
    }

    public static int getBit(int num, int len, int max, int min) {
        return ((num - min) * len) / (max - min); //计算num应该存储在哪个桶
    }

    public static int sortAfter(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }

        Arrays.sort(arr);
        int res = Integer.MIN_VALUE;
        for (int i = 1; i < arr.length; i++) {
            res = Math.max(res, arr[i] - arr[i - 1]);
        }
        return res;
    }

    public static int[] generateArr(int N , int range) {
        int[] arr = new int[N];
        for (int i = 0; i < N; i++) {
            arr[i] = (int)(Math.random() * range);
        }
        return arr;
    }
}

好啦,本期更新就到此结束啊!!!我们下期见吧!!!

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-12-13 13:06:58  更:2021-12-13 13:08:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 16:37:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码