算法练习帖--53--将整数按权重排序(Java)

将整数按权重排序

一、题目简介

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

如果 x 是偶数,那么 x = x / 2
如果 x 是奇数,那么 x = 3 * x + 1
比方说,x=3 的权重为 7 。因为 3 需要 7 步变成 1 (3 --> 10 --> 5 --> 16 --> 8 --> 4 --> 2 --> 1)。

给你三个整数 lo, hi 和 k 。你的任务是将区间 [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. Arrays排序覆盖+递归+记忆化
题解区大佬方法

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;
    }
}

猜你喜欢

转载自blog.csdn.net/Inmaturity_7/article/details/113094634