演算法練習帖--53--將整數按權重排序(Java)
阿新 • • 發佈:2021-01-25
將整數按權重排序
一、題目簡介
我們將整數 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;
}
}