输入: nums = [3,6,9,1]
输出: 3
解释: 排序后的数组是 [1,3,6,9], 其中相邻元素 (3,6) 和 (6,9) 之间都存在最大差值 3。
输入: nums = [10]
输出: 0
解释: 数组元素个数小于 2,因此返回 0。
xx.xx is not a valid value of type integer
1 )借用原生sort + 迭代取相邻最大值
function maximumGap(nums: number[]): number {
// 如果数组长度小于2返回0
if (nums.length < 2) return 0;
// 排序 这个在 leetcode 上要传入回调,否则排序是乱序的
nums.sort((a, b) => a - b);
// 用它来保存相邻元素的最大差值
let max = 0;
for (let i = 1; i < nums.length; i++) max = Math.max(max, nums[i] - nums[i - 1]);
return max;
};
2 )基数排序来解
// 基数排序
function radixSort(list: number[]) {
const len = list.length; // 获取数组长度
const max = Math.max(...list); // 获取数组中最大值
let i = 0; // 用于计数的数组
let radix = 1; // 基数(个:1, 十:10, 百: 100, ...)
const tmp = new Array(len); // 临时倒腾数组
while(max >= radix) {
// 初始化存储桶 0 ~ 9, 全0填充
const bucket = new Array(10).fill(0);
// 对当前基数下的值进行累加计算总数
for(i=0; i<len; i++) {
// 获取当前基数下的值, 也就是对应的桶的下标
const currentRadixNum = Math.floor(list[i] / radix) % 10;
bucket[currentRadixNum] ++; // 从 0 开始自增, 这里桶中存储的是当前下标下对应数据的累计个数
}
// 计算当前数据位置: 基于桶内每个下标对应数据的累计个数,计算当前元素在整个桶中的位置,并反向赋值给当前桶
for(i = 1; i<10; i++) {
bucket[i] += bucket[i-1];
}
// 将a[i]的值按照桶存储的位置倒腾到临时数组tmp中
for(i = len-1; i>=0; i--) {
const currentRadixNum = Math.floor(list[i] / radix) % 10; // 当前基数下的数字
const currentIndex = bucket[currentRadixNum] - 1; // bucket存储的是位置,位置-1为下标
tmp[currentIndex] = list[i]; // 根据桶存储的位置,
bucket[currentRadixNum] --; // 桶内当前元素累计值 自减
}
// 再将临时数组中的元素倒腾回list中,此时完成了一轮的基于基数的处理
list.splice(0, len, ...tmp);
radix *= 10; // 基数进位处理
}
}
function maximumGap(nums: number[]): number {
// 如果数组长度小于2返回0
if (nums.length < 2) return 0;
radixSort(nums);
// 用它来保存相邻元素的最大差值
let max = 0;
for (let i = 1; i < nums.length; i++) max = Math.max(max, nums[i] - nums[i - 1]);
return max;
};
3 )计数排序来解
function countSort(list:number[]) {
const len: number = list.length;
if (len < 2) return;
// 获取最大值和最小值
const max: number = Math.max(...list);
const min: number = Math.min(...list);
// 初始化计数数组
const countList: number[] = new Array(max - min + 1).fill(0);
// 初始化目标数组
const result: number[] = new Array(len);
// 对原数组的数据在计数数组中累计,原数组的值是计数数组的下标
for(let i:number = 0; i < len; i++) countList[list[i] - min]++; // 遍历完成后计数数组就变成了累计数组
// 计算位置: 由上面的累计结果,计算累加后的位置, countList数组从累计数组,变成了位置数组
for(let j = 1; j < max - min + 1; j++) {
countList[j] += countList[j - 1];
}
// 根据累加后的位置, 将原数组中的数据按照位置进行分配,就得到排好序的数组,备注:数据可能重复,使用过的数据记得-1,从后向前遍历更好理解
for (let k:number = len - 1; k >= 0; k--) {
const currentIndex = countList[list[k] - min] - 1;
result[currentIndex] = list[k]; // 将原数组的当前元素整合到 result数组对应的位置之中
countList[list[k] - min] --; // 使用一次后,累计的数量自减,防止重复使用导致错误
}
list.splice(0, len, ...result); // 重新洗牌,用 result 内元素替换
}
function maximumGap(nums: number[]): number {
// 如果数组长度小于2返回0
if (nums.length < 2) return 0;
countSort(nums);
// 用它来保存相邻元素的最大差值
let max = 0;
for (let i = 1; i < nums.length; i++) max = Math.max(max, nums[i] - nums[i - 1]);
return max;
};
[99999999, 2]
这类,则非常低效4 )桶排序
function maximumGap(nums: number[]): number {
const n: number = nums.length;
if (n < 2) return 0;
const minVal: number = Math.min(...nums);
const maxVal: number = Math.max(...nums);
const d: number = Math.max(1, Math.floor(maxVal - minVal) / (n - 1));
const bucketSize = Math.floor((maxVal - minVal) / d) + 1;
const bucket: number[][] = new Array(bucketSize).fill(0).map(x => new Array(2).fill(0));
for (let i: number = 0; i < bucketSize; ++i) {
bucket[i].fill(-1);
}
for (let i: number = 0; i < n; i++) {
const idx: number = Math.floor((nums[i] - minVal) / d);
if (bucket[idx][0] === -1) {
bucket[idx][0] = bucket[idx][1] = nums[i];
} else {
bucket[idx][0] = Math.min(bucket[idx][0], nums[i]);
bucket[idx][1] = Math.max(bucket[idx][1], nums[i]);
}
}
let max: number = 0;
let prev: number = -1;
for (let i: number = 0; i < bucketSize; i++) {
if (bucket[i][0] == -1) {
continue;
}
if (prev != -1) {
max = Math.max(max, bucket[i][0] - bucket[prev][1]);
}
prev = i;
}
return max;
};