整数を重みで並べ替える
1.はじめに
整数xの重みは、次の規則に従ってxを1に変更するために必要なステップ数として定義されます。
xが偶数の場合、x = x / 2
xが奇数の場合、x = 3 * x + 1
たとえば、x = 3の重みは7です。3は1になるために7つのステップを必要とするため(3-> 10-> 5-> 16-> 8-> 4-> 2-> 1)。
lo、hi、kの3つの整数を与えます。あなたの仕事は、間隔[lo、hi]の整数を重みの昇順でソートすることです。2つ以上の整数が同じ重みを持っている場合は、それらを独自の値の昇順でソートします。
重みでソートされた区間[lo、hi]内のk番目の整数を返します。
タイトルは、任意の整数x(lo <= x <= hi)に対して、1になるために必要なステップ数が32ビットの符号付き整数であることを保証していることに注意してください。
(件名:LeetCode)
示例 1:
输入:lo = 12, hi = 15, k = 2
输出:13
解释:12 的权重为 9(12 --> 6 --> 3 --> 10 --> 5 --> 16 --> 8 --> 4 --> 2 --> 1)
13 的权重为 9
14 的权重为 17
15 的权重为 17
区间内的数按权重排序以后的结果为 [12,13,14,15] 。对于 k = 2 ,答案是第二个整数也就是 13 。
注意,12 和 13 有相同的权重,所以我们按照它们本身升序排序。14 和 15 同理。
示例 2:
输入:lo = 1, hi = 1, k = 1
输出:1
示例 3:
输入:lo = 7, hi = 11, k = 4
输出:7
解释:区间内整数 [7, 8, 9, 10, 11] 对应的权重为 [16, 3, 19, 6, 14] 。
按权重排序后得到的结果为 [8, 10, 11, 7, 9] 。
排序后数组中第 4 个数字为 7 。
示例 4:
输入:lo = 10, hi = 20, k = 5
输出:13
示例 5:
输入:lo = 1, hi = 1000, k = 777
输出:570
提示:
1 <= lo <= hi <= 1000
1 <= k <= hi - lo + 1
二、解決策
1.暴力法
class Solution {
public int getKth(int lo, int hi, int k) {
int length=hi-lo+1;
//存储区间数字的数组
List<Integer> nums=new ArrayList<>();
for (int i = 0; i <length; i++) {
//存储当前数字
nums.add(i+lo);
}
//定义排序规则
Collections.sort(nums, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
//如果权值相等,则比较原数
if(getWeight(o1)==getWeight(o2)){
return o1-o2;
}else{
//否则比较权值
return getWeight(o1)-getWeight(o2);
}
}
});
return nums.get(k-1);
}
public int getWeight(int currentNum){
//权值
int weight=0;
//循环获取权值
while(currentNum!=1){
currentNum=(currentNum&1)==0?(currentNum>>1):(3*currentNum+1);
weight++;
}
return weight;
}
}
2.再帰+メモ化
class Solution {
Map<Integer,Integer> map=new HashMap<>();
public int getKth(int lo, int hi, int k) {
int length=hi-lo+1;
//存储区间数字的数组
List<Integer> nums=new ArrayList<>();
for (int i = 0; i <length; i++) {
int currentNum=i+lo;
//存储当前数字
nums.add(currentNum);
//获取权值
getWeight(currentNum);
}
//定义排序规则
Collections.sort(nums, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
//map中已经将数字对应权值全部计算完了,此时直接在map中取就可以了
//如果权值相等,则比较原数
if(map.get(o1)==map.get(o2)){
return o1-o2;
}else{
//否则比较权值
return map.get(o1)-map.get(o2);
}
}
});
return nums.get(k-1);
}
public int getWeight(int currentNum){
//递归,并将所求得的权值存储在map中
if(!map.containsKey(currentNum)){
if (currentNum == 1) {
//等于直接存储权值0
map.put(1, 0);
} else if ((currentNum & 1) != 0) {
//如果不是偶数,则currentNum对应的权值也就是(currentNum * 3 + 1)的权值+1
map.put(currentNum, getWeight(currentNum * 3 + 1) + 1);
} else {
//如果是偶数,则currentNum对应的权值也就是(currentNum*2)的权值+1
map.put(currentNum, getWeight(currentNum>>1) + 1);
}
}
return map.get(currentNum);
}
}
3.カバレッジ+再帰+メモ化を並べ替える配列
エリアボス法の問題解決
class Solution {
Map<Integer,Integer> map=new HashMap<>();
public int getKth(int lo, int hi, int k) {
if(lo==hi) return hi;
//二维数组存储数字及其对应的权值
int[][] weight=new int[hi-lo+1][2];
for (int i = lo; i <= hi; i++) {
//一维数组的第一个数存储权值
weight[i-lo][0]=getWeight(i);
//一维数组的第二个数存储数字
weight[i-lo][1]=i;
}
//自定义排序规则
Arrays.sort(weight, (a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
return weight[k-1][1];
}
public int getWeight(int currentNum){
//递归,并将所求得的权值存储在map中
if(!map.containsKey(currentNum)){
if (currentNum == 1) {
//等于直接存储权值0
map.put(1, 0);
} else if ((currentNum & 1) != 0) {
//如果不是偶数,则currentNum对应的权值也就是(currentNum * 3 + 1)的权值+1
map.put(currentNum, getWeight(currentNum * 3 + 1) + 1);
} else {
//如果是偶数,则currentNum对应的权值也就是(currentNum*2)的权值+1
map.put(currentNum, getWeight(currentNum>>1) + 1);
}
}
return map.get(currentNum);
}
}
4.小さなルートヒープ(ここでの記憶はより長く実行され、より長くかかります)
コメントエリアボス方式
class Solution {
public int getKth(int lo, int hi, int k) {
//自定义排序规则
Queue<int[]> queue = new PriorityQueue<>((o1, o2) -> o1[1] != o2[1] ? o2[1] - o1[1] : o2[0] - o1[0]);
for (int i = lo; i <= hi; ++i) {
//添加数字及其对应的权值
queue.offer(new int[]{
i, getP(i)});
if (i - lo + 1 > k) {
//将第k个数字前面的全部移出队列
queue.poll();
}
}
return queue.poll()[0];
}
private int getP(int currentNum) {
//权值
int weight = 0;
//循环获取当前数字对应的权值
while (currentNum != 1) {
if ((currentNum & 1) == 1) {
currentNum += (x << 1) + 1;
} else {
currentNum >>= 1;
}
++weight ;
}
return weight;
}
}