leetcode
leetcode 1251 ~ 1300
将整数按权重排序

将整数按权重排序

难度:

标签:

题目描述

代码结果

运行时间: 47 ms, 内存: 16.2 MB


/*
 * 思路:
 * 1. 使用Stream API来处理区间 [lo, hi] 的整数。
 * 2. 计算每个整数的权重,并将整数和权重映射为数组。
 * 3. 按照权重和数值进行排序。
 * 4. 提取排序后的第 k 个元素。
 */

import java.util.Comparator;
import java.util.stream.IntStream;

public class Solution {
    public int getWeight(int x) {
        int steps = 0;
        while (x != 1) {
            if (x % 2 == 0) {
                x = x / 2;
            } else {
                x = 3 * x + 1;
            }
            steps++;
        }
        return steps;
    }

    public int getKth(int lo, int hi, int k) {
        return IntStream.rangeClosed(lo, hi)
            .mapToObj(i -> new int[]{i, getWeight(i)})
            .sorted(Comparator.<int[]>comparingInt(a -> a[1]).thenComparingInt(a -> a[0]))
            .mapToInt(a -> a[0])
            .skip(k - 1)
            .findFirst()
            .orElse(-1);
    }
}

解释

方法:

题解的核心思想是使用动态规划来计算每个整数x的权重,即变成1所需的步骤数。这里利用了缓存装饰器@cache,它存储每个已计算过的整数的权重,以避免重复计算。函数f(x)负责计算一个给定的x的权重。如果x是偶数,则x除以2;如果x是奇数,则变为3*x+1,重复此过程直到x变为1。主要的函数getKth()使用这个计算权重的函数作为排序键值,对区间[lo, hi]中的所有整数进行排序,并返回第k小的整数。

时间复杂度:

O(n log n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
在题解中使用@cache装饰器的原因是什么?这种缓存方法如何帮助提高计算权重的效率?
在题解中使用 @cache 装饰器是为了缓存函数f(x)的结果。这种方法可以避免对相同的整数x重复计算权重,特别是在计算过程中经常会遇到重复的数值。例如,在递归过程中,不同的起始值可能会导致相同的中间结果,使用缓存可以直接从存储中读取这些中间结果的权重,而不需要再次进行计算。这大大提高了算法的效率,尤其是在处理大范围整数时,可以显著减少计算时间。
🦆
函数f(x)在处理x变为1的过程中,如何确保不会进入无限循环,尤其是对于大整数的情况?
函数f(x)依据的是著名的Collatz猜想(3x + 1猜想),该猜想虽然未被严格证明,但广泛的数学实验表明,对任何正整数应用此过程,最终都会收敛至1。尽管对于非常大的整数,数值在增长到一定阶段后可能会出现很大的值,但根据猜想,这些值最终都将回归到较小的数值,并最终达到1。因此,在目前的理解下,函数f(x)不会进入无限循环,这基于对Collatz猜想的普遍接受和验证。
🦆
题解的算法是否考虑了整数溢出的问题,特别是在执行3*x + 1操作时?
题解中没有特别提到关于整数溢出的处理措施。在Python中,整数类型支持长整数计算,因此理论上可以处理非常大的数而不会发生溢出。然而,在其他语言中,如C++或Java,这种3*x + 1的操作确实可能导致整数溢出,特别是当x的值非常大时。在这种情况下,可能需要采用更大范围的整数类型或进行特定的溢出检查来确保算法的正确性和安全性。

相关问题