You are given three integers: lo
, hi
, and k
. Your task is to sort all integers in the range [lo, hi]
by their "power value" and return the k
-th integer in this sorted list.
The "power value" of an integer x
is defined as the number of steps required to transform x
into 1 using the following process:
x
is even, replace x
with x / 2
.x
is odd, replace x
with 3 * x + 1
.x
becomes 1.
You must sort the numbers from lo
to hi
(inclusive) by their power values in ascending order. If two numbers have the same power value, sort them by their integer value in ascending order. Return the k
-th integer (1-indexed) from this sorted list.
Constraints:
At first glance, the problem asks us to sort a range of numbers based on a custom metric ("power value") derived from the Collatz sequence rules. A brute-force approach would be to compute the power value for every number in the range, sort them, and return the k
-th smallest. However, since calculating the power value involves repeated computation for the same intermediate numbers, we can optimize by caching results (memoization).
The key insight is to:
k
-th element.Let's break down the solution step-by-step:
x
in the range [lo, hi]
, compute its power value.k-1
.This method ensures we only compute each power value once, sort efficiently, and select the correct output.
Input: lo = 12
, hi = 15
, k = 2
Let's walk through the steps:
13
.13
Brute-force approach:
[lo, hi]
, compute the power value individually without caching.The problem challenges us to sort numbers by a custom "power value" derived from the Collatz sequence. By combining recursion, memoization, and stable sorting, we efficiently compute and order the numbers, ensuring correctness and performance. The approach highlights the power of dynamic programming (memoization) for overlapping subproblems and demonstrates how to adapt sorting to custom criteria in coding interviews.
class Solution:
def getKth(self, lo: int, hi: int, k: int) -> int:
from functools import lru_cache
@lru_cache(None)
def power(x):
if x == 1:
return 0
if x % 2 == 0:
return 1 + power(x // 2)
else:
return 1 + power(3 * x + 1)
arr = []
for num in range(lo, hi + 1):
arr.append((power(num), num))
arr.sort()
return arr[k - 1][1]
class Solution {
public:
unordered_map memo;
int power(int x) {
if (x == 1) return 0;
if (memo.count(x)) return memo[x];
if (x % 2 == 0)
return memo[x] = 1 + power(x / 2);
else
return memo[x] = 1 + power(3 * x + 1);
}
int getKth(int lo, int hi, int k) {
vector> arr;
for (int i = lo; i <= hi; ++i) {
arr.push_back({power(i), i});
}
sort(arr.begin(), arr.end());
return arr[k - 1].second;
}
};
class Solution {
private Map memo = new HashMap<>();
private int power(int x) {
if (x == 1) return 0;
if (memo.containsKey(x)) return memo.get(x);
int res;
if (x % 2 == 0)
res = 1 + power(x / 2);
else
res = 1 + power(3 * x + 1);
memo.put(x, res);
return res;
}
public int getKth(int lo, int hi, int k) {
List arr = new ArrayList<>();
for (int i = lo; i <= hi; ++i) {
arr.add(new int[]{power(i), i});
}
arr.sort((a, b) -> a[0] != b[0] ? Integer.compare(a[0], b[0]) : Integer.compare(a[1], b[1]));
return arr.get(k - 1)[1];
}
}
var getKth = function(lo, hi, k) {
const memo = new Map();
function power(x) {
if (x === 1) return 0;
if (memo.has(x)) return memo.get(x);
let res;
if (x % 2 === 0)
res = 1 + power(x / 2);
else
res = 1 + power(3 * x + 1);
memo.set(x, res);
return res;
}
let arr = [];
for (let i = lo; i <= hi; ++i) {
arr.push([power(i), i]);
}
arr.sort((a, b) => a[0] !== b[0] ? a[0] - b[0] : a[1] - b[1]);
return arr[k - 1][1];
};