【Leetcode 每日一题】1387. 将整数按权重排序

news/2024/12/23 16:18:44/

问题背景

我们将整数 x x x权重 定义为按照下述规则将 x x x 变成 1 1 1 所需要的步数:

  • 如果 x x x 是偶数,那么 x = x / 2 x = x / 2 x=x/2
  • 如果 x x x 是奇数,那么 x = 3 × x + 1 x = 3 \times x + 1 x=3×x+1

比方说, x = 3 x = 3 x=3 的权重为 7 7 7。因为 3 3 3 需要 7 7 7 步变成 1 1 1 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1 3 \rightarrow 10 \rightarrow 5 \rightarrow 16 \rightarrow 8 \rightarrow 4 \rightarrow 2 \rightarrow 1 3105168421)。
给你三个整数 l o lo lo h i hi hi k k k。你的任务是将区间 [ l o , h i ] [lo, hi] [lo,hi] 之间的整数按照它们的权重 升序排序 ,如果大于等于 2 2 2 个整数有 相同 的权重,那么按照数字自身的数值 升序排序
请你返回区间 [ l o , h i ] [lo, hi] [lo,hi] 之间的整数按权重排序后的第 k k k 个数。
注意,题目保证对于任意整数 x x x l o ≤ x ≤ h i lo \le x \le hi loxhi) ,它变成 1 1 1 所需要的步数是一个 32 32 32 位有符号整数。

数据约束

  • 1 ≤ l o ≤ h i ≤ 1000 1 \le lo \le hi \le 1000 1lohi1000
  • 1 ≤ k ≤ h i − l o + 1 1 \le k \le hi - lo + 1 1khilo+1

解题过程

这题的本质要求是将数组中的两个属性当作不同的标准,完成二级排序。
刻画双重标准有两种做法,一种是定义一个二维数组,把数字和权重组成一个长为二的数对,对这个数对进行排序;另一种是用两个数组分别存储数字和权重,存储权重的数组可以看作哈希表,只作为标准来使用,不参与排序。
从效率上来说,第二种方法可以预处理计算所有可能的权重,还可以避免重复后续重复计算之前已经得到的权重,是更好的方法。实际上这题数据量不是很大,选哪种方案都能搞定。

题目明确要求权重相同的按元素本身大小升序排列,其实就是要求实际排序的流程是稳定的。
常见的排序算法,包括 Java 本身提供的排序方法,归并排序 这些当然都能解决问题。但如果进一步考虑到数据规模小,计数排序 显然是最优的选择。

在这种情况下,最好不要选择不稳定的算法
题中要求第 K K K 大的数,虽然使用非荷兰国旗问题的一般快排划分,能够在 O ( N ) O(N) O(N) 这个量级的时间下得到结果,但实际上完全没必要(仅考虑本题的话,有计数排序兜底)。
我也尝试实现了随机快排和堆排,发现要将不稳定的排序算法改造成能按多个标准排序是比较麻烦的,浪费了相当多的时间。
几分钟就做完的题,尝试改算法改了一上午还没成功,还是不折磨自己了,今天是讨厌快排的一天。

具体实现

调用 API

class Solution {private static final int MAX_N = 1010;private static final int[] memo = new int[MAX_N];public int getKth(int lo, int hi, int k) {int n = hi - lo + 1;        for(int i = 0; i < n; i++) {int curIndex = i + lo;memo[curIndex] = memo[curIndex] != 0 ? memo[curIndex] : calcWeight(curIndex);}Integer[] nums = new Integer[n];Arrays.setAll(nums, i -> i + lo);Arrays.sort(nums, (o1, o2) -> memo[o1] != memo[o2] ? memo[o1] - memo[o2] : o1 - o2);return nums[k - 1];}private int calcWeight(int n) {int res = 0;while(n != 1) {if((n & 1) == 1) {n = 3 * n + 1;} else {n >>>= 1;}res++;}return res;}
}

归并排序

class Solution {private static final int MAX_N = 1010;private static final int[] memo = new int[MAX_N];private static final int[] temp = new int[MAX_N];public int getKth(int lo, int hi, int k) {int n = hi - lo + 1;        for(int i = 0; i < n; i++) {int curIndex = i + lo;memo[curIndex] = memo[curIndex] != 0 ? memo[curIndex] : calcWeight(curIndex);}int[] nums = new int[n];Arrays.setAll(nums, i -> i + lo);mergeSort(nums, 0, n - 1);return nums[k - 1];}private int calcWeight(int n) {int res = 0;while(n != 1) {if((n & 1) == 1) {n = 3 * n + 1;} else {n >>>= 1;}res++;}return res;}private void merge(int[] arr, int left, int mid, int right) {int index1 = left, index2 = mid + 1, index = left;while(index1 <= mid && index2 <= right) {temp[index++] = memo[arr[index1]] <= memo[arr[index2]] ? arr[index1++] : arr[index2++];}while(index1 <= mid) {temp[index++] = arr[index1++];}while(index2 <= right) {temp[index++] = arr[index2++];}System.arraycopy(temp, left, arr, left, right - left + 1);}private void mergeSort(int[] arr, int left, int right) {if(left == right) {return;}int mid = left + ((right - left) >>> 1);mergeSort(arr, left, mid);mergeSort(arr, mid + 1, right);merge(arr, left, mid, right);}
}

计数排序

class Solution {private static final int MAX_N = 1010;private static final int[] memo = new int[MAX_N];public int getKth(int lo, int hi, int k) {int n = hi - lo + 1;        for(int i = 0; i < n; i++) {int curIndex = i + lo;memo[curIndex] = memo[curIndex] != 0 ? memo[curIndex] : calcWeight(curIndex);}int[] nums = new int[n];Arrays.setAll(nums, i -> i + lo);countingSort(nums);return nums[k - 1];}private int calcWeight(int n) {int res = 0;while(n != 1) {if((n & 1) == 1) {n = 3 * n + 1;} else {n >>>= 1;}res++;}return res;}private void countingSort(int[] arr) {int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;for(int item : arr) {min = Math.min(min, memo[item]);max = Math.max(max, memo[item]);}int range = max - min + 1;int[] count = new int[range];for(int item : arr) {count[memo[item] - min]++;}for(int i = 1; i < count.length; i++) {count[i] += count[i - 1];}int[] res = new int[arr.length];for(int i = arr.length - 1; i >= 0; i--) {int cur = arr[i];res[--count[memo[cur] - min]] = cur;}System.arraycopy(res, 0, arr, 0, arr.length);}
}

http://www.ppmy.cn/news/1557510.html

相关文章

Go怎么做性能优化工具篇之 trace工具

一、什么是 trace trace 是 Go 语言的一个非常强大的性能分析工具&#xff0c;它用于追踪和记录 Go 程序的执行过程。与 CPU 和内存性能分析工具&#xff08;如 pprof&#xff09;不同&#xff0c;trace 侧重于在时间维度上分析程序的行为&#xff0c;帮助开发者理解程序执行中…

RHEL 7.5 源码安装 mysql-5.7.17 数据库

RHEL 7.5 mysql-5.7.17 源码安装 1、解决依赖包并下载源码包 # yum -y install gcc gcc-c ncurses ncurses-devel bison # wget https://sourceforge.net/projects/boost/files/boost/1.59.0/boost_1_59_0.tar.gz # tar -zxvf boost_1_59_0.tar.gz # mv boost_1_59_0 /usr/loc…

QtitanChart组件——高效、灵活的Qt数据可视化解决方案

在现代应用开发中&#xff0c;数据可视化已经成为不可或缺的一部分。无论是商业分析工具、财务报表、工程图表&#xff0c;还是科学实验数据展示&#xff0c;如何以直观、易理解的方式展示数据&#xff0c;往往决定了软件的可用性与用户体验。对于Qt开发者来说&#xff0c;Qtit…

SWIFT基本使用

安装 # 全量能力 pip install ms-swift[all] -U # 仅使用LLM pip install ms-swift[llm] -U # 仅使用AIGC pip install ms-swift[aigc] -U # 仅使用Adapters pip install ms-swift -U or git clone https://github.com/modelscope/ms-swift.git cd ms-swift pip install -e …

单片机与MQTT协议

MQTT 协议简述 MQTT&#xff08;Message Queuing Telemetry Transport&#xff0c;消息队列遥测传输协议&#xff09;&#xff0c;是一种基于发布 / 订阅&#xff08;publish/subscribe&#xff09;模式的 “轻量级” 通讯协议&#xff0c;该协议构建于 TCP/IP 协议上&#xf…

【证书】免费的证书+1 Ai Prompt Engineer

碎片化的时间利用起来&#xff0c;获得个免费&#x1f193;的证书&#x1f4d6;吧。 简单了解下相关知识&#xff0c;然后考试&#xff0c;几分钟&#x1f570;️就可以获得&#x1f250;个&#x1f193;的证书。超级超级简单的&#x1f495;&#x1f495;。 没什么含金量的哈…

前端数据可视化库介绍Echarts、D3.js、Plotly、Matplotlib

目录 一、Echarts 1. 简介 2. 优点 3. 缺点 4. 代码示例 二、D3.js 1. 简介 2. 优点 3.缺点 4. 代码示例 三、Plotly 1.简介 2.优点 3.缺点 四、Matplotlib 1.简介 2.优点 3.缺点 一、Echarts 1. 简介 Echarts 是一个由百度开源的数据可视化库&#xff0c;…

jenkins针对大文件进行拉取

pipeline { agent { kubernetes { inheritFrom maven containerTemplate{ name maven image jenkins_pipiline_base:latest } } } stages { stage(构建发布) { steps { container(maven) { script { …