堆------中等

目录

215. 数组中的第K个最大元素    中等

264. 丑数 II    中等

313. 超级丑数    中等

347. 前 K 个高频元素    中等

373. 查找和最小的K对数字    中等

378. 有序矩阵中第K小的元素    中等

451. 根据字符出现频率排序    中等

692. 前K个高频单词    中等

973. 最接近原点的 K 个点    中等

面试题

面试题 17.14. 最小K个数    中等


堆结构和堆排序

import java.util.Arrays;

public class MyMaxHeap {
    private int[] heap;
    private final int limit;
    private int heapSize;

    public MyMaxHeap(int limit) {
        this.limit = limit;
        heap = new int[limit];
        heapSize = 0;
    }

    public boolean isEmpty() {
        return heapSize == 0;
    }

    public boolean isFull() {
        return heapSize == limit;
    }

    public void push(int value) {
        if (heapSize == limit) {
            throw new RuntimeException("heap is full");
        }
        heap[heapSize] = value;
        heapInsert(heap, heapSize++);
    }

    public int pop() {
        int ans = heap[0];
        swap(heap, 0, --heapSize);
        heapify(heap, 0, heapSize);
        return ans;
    }

    private void heapInsert(int[] arr, int index) {
        //当arr[index]不比arr[index父]大了,或者index来到0位置了
        while (arr[index] > arr[(index - 1) / 2]) {
            swap(arr, index, (index - 1) / 2);
            index = (index - 1) / 2;
        }
    }

    //从index位置,往下看,不断的下沉
    private void heapify(int[] arr, int index, int heapSize) {
        int left = index * 2 + 1;
        while (left < heapSize) {
            int largest = left + 1 < heapSize && arr[left + 1] > arr[left] ? left + 1 : left;
            largest = arr[largest] > arr[index] ? largest : index;
            if (largest == index) {
                break;
            }
            swap(arr, largest, index);
            index = largest;
            left = index * 2 + 1;
        }
    }

    private void swap(int[] arr, int l, int r) {
        int temp = arr[l];
        arr[l] = arr[r];
        arr[r] = temp;
    }

    //从小到大进行排序
    public void heapSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        // O(N*log(N))
//        for (int i = 0; i < arr.length; i++) {
//            heapInsert(arr, i);
//        }
        // O(N)
        for (int i = arr.length - 1; i >= 0; i--) {
            heapify(arr, i, arr.length);
        }
        int size = arr.length;
        swap(arr, 0, --size);
        // O(N*logN)
        while (size > 0) {
            heapify(arr, 0, size);
            swap(arr, 0, --size);
        }
    }

    public static void main(String[] args) {
        int arr[] = {3, 6, 4, 8, 4, 8, 4, 9, 4, 76, 2, 5, 1};
        MyMaxHeap heap = new MyMaxHeap(arr.length);
        for (int i = 0; i < arr.length; i++) {
            heap.push(arr[i]);
        }
        for (int i = 0; i < arr.length; i++) {
            int val = heap.pop();
            System.out.print(val + " ");
        }
        System.out.println();
        heap.heapSort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

215. 数组中的第K个最大元素    中等

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5

示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4

说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> heap = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2.compareTo(o1);
            }
        });
        for (int num : nums) {
            heap.add(num);
        }
        int num = nums[0];
        for (int i = 0; i < k; i++) {
            num = heap.poll();
        }
        return num;
    }

解析:建立一个大顶堆

弹出k个元素即可

第k个元素即为求的答案

264. 丑数 II    中等

编写一个程序,找出第 n 个丑数。

丑数就是质因数只包含 2, 3, 5正整数

示例:

输入: n = 10
输出: 12
解释: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 是前 10 个丑数。

说明:  

  1. 1 是丑数。
  2. n 不超过1690。
class Solution {
    //数组+堆+set
    private int[] nums = new int[1690];

    public Solution() {
        Set<Long> set = new HashSet<>();
        PriorityQueue<Long> minHeap = new PriorityQueue<>();
        set.add(1L);
        minHeap.add(1L);
        int[] ugly = new int[]{2, 3, 5};
        long curr, temp;
        for (int i = 0; i < 1690; i++) {
            curr = minHeap.poll();
            nums[i] = (int) curr;
            for (int j : ugly) {
                temp = j * curr;
                if (!set.contains(temp)) {
                    set.add(temp);
                    minHeap.add(temp);
                }
            }
        }
    }

    public int nthUglyNumber(int n) {
        return nums[n - 1];
    }
}

解析:生成一个全局数组,预计算1679个元素

使用一个set,用于去重,使用一个堆,每次弹出最小的元素放入数组中

返回数组第n-1个即可

    //个人实现 不用预生成数组
    Set<Long> set = new HashSet<>();
    PriorityQueue<Long> minHeap = new PriorityQueue<>();
    private int res;
    public int nthUglyNumber(int n) {
        int[] ugly = new int[]{2, 3, 5};
        set.add(1L);
        minHeap.add(1L);
        long curr, temp;
        for (int i = 0; i < n; i++) {
            curr = minHeap.poll();
            res = (int) curr;
            for (int j : ugly) {
                temp = j * curr;
                if (!set.contains(temp)) {
                    set.add(temp);
                    minHeap.add(temp);
                }
            }
        }
        return res;
    }

解析:不用预生成数组,用一个变量代替

    //动态规划
    public int nthUglyNumber(int n) {
        int ugly, i2 = 0, i3 = 0, i5 = 0;
        int[] nums = new int[n];
        nums[0] = 1;
        for (int i = 1; i < n; i++) {
            ugly = Math.min(nums[i2] * 2, Math.min(nums[i3] * 3, nums[i5] * 5));
            nums[i] = ugly;
            if (ugly == nums[i2] * 2) {
                i2++;
            }
            if (ugly == nums[i3] * 3) {
                i3++;
            }
            if (ugly == nums[i5] * 5) {
                i5++;
            }
        }
        return nums[n - 1];
    }

解析:每次选出最小的值赋值给数组

313. 超级丑数    中等

编写一段程序来查找第 n 个超级丑数。

超级丑数是指其所有质因数都是长度为 k 的质数列表 primes 中的正整数。

示例:

输入: n = 12, primes = [2,7,13,19]
输出: 32 
解释: 给定长度为 4 的质数列表 primes = [2,7,13,19],前 12 个超级丑数序列为:[1,2,4,7,8,13,14,16,19,26,28,32] 。

说明:

  • 1 是任何给定 primes 的超级丑数。
  •  给定 primes 中的数字以升序排列。
  • 0 < k ≤ 100, 0 < n ≤ 106, 0 < primes[i] < 1000 。
  • 第 n 个超级丑数确保在 32 位有符整数范围内。
    //个人实现  堆+set
    private Set<Long> set = new HashSet<>();
    private PriorityQueue<Long> minHeap = new PriorityQueue<>();
    private int res;
    public int nthSuperUglyNumber(int n, int[] primes) {
        set.add(1L);
        minHeap.add(1L);
        long curr, temp;
        for (int i = 0; i < n; i++) {
            curr = minHeap.poll();
            res = (int) curr;
            for (int prime : primes) {
                temp = prime * curr;
                if (!set.contains(temp)) {
                    set.add(temp);
                    minHeap.add(temp);
                }
            }
        }
        return res;
    }

解析:和264丑数解法相同

347. 前 K 个高频元素    中等

给定一个非空的整数数组,返回其中出现频率前 高的元素。

示例 1:

输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]

示例 2:

输入: nums = [1], k = 1
输出: [1]

提示:

  • 你可以假设给定的 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
  • 你的算法的时间复杂度必须优于 O(n log n) , 是数组的大小。
  • 题目数据保证答案唯一,换句话说,数组中前 k 个高频元素的集合是唯一的。
  • 你可以按任意顺序返回答案。
    //堆  个人实现
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }
        PriorityQueue<Map.Entry<Integer, Integer>> maxHeap = new PriorityQueue<>(new Comparator<Map.Entry<Integer, Integer>>() {
            @Override
            public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
                return o2.getValue().compareTo(o1.getValue());
            }
        });
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            maxHeap.add(entry);
        }
        int res[] = new int[k];
        for (int i = 0; i < k && maxHeap.size() > 0; i++) {
            res[i] = maxHeap.poll().getKey();
        }
        return res;
    }

解析:map+堆

373. 查找和最小的K对数字    中等

给定两个以升序排列的整形数组 nums1nums2, 以及一个整数 k

定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2

找到和最小的 k 对数字 (u1,v1), (u2,v2) ... (uk,vk)

示例 1:

输入: nums1 = [1,7,11], nums2 = [2,4,6], k = 3
输出: [1,2],[1,4],[1,6]
解释: 返回序列中的前 3 对数:
     [1,2],[1,4],[1,6],[7,2],[7,4],[11,2],[7,6],[11,4],[11,6]

示例 2:

输入: nums1 = [1,1,2], nums2 = [1,2,3], k = 2
输出: [1,1],[1,1]
解释: 返回序列中的前 2 对数:
     [1,1],[1,1],[1,2],[2,1],[1,2],[2,2],[1,3],[1,3],[2,3]

示例 3:

输入: nums1 = [1,2], nums2 = [3], k = 3 
输出: [1,3],[2,3]
解释: 也可能序列中所有的数对都被返回:[1,3],[2,3]
    //堆  个人实现,效率低
    public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        PriorityQueue<List<Integer>> minHeap = new PriorityQueue<>(new Comparator<List<Integer>>() {
            @Override
            public int compare(List<Integer> o1, List<Integer> o2) {
                int num1 = o1.get(0) + o1.get(1);
                int num2 = o2.get(0) + o2.get(1);
                return Integer.compare(num1, num2);
            }
        });
        List<List<Integer>> res = new ArrayList<>();
        for (int num1 : nums1) {
            for (int num2 : nums2) {
                List<Integer> list = new ArrayList<>();
                list.add(num1);
                list.add(num2);
                minHeap.add(list);
            }
        }
        for (int i = 0; i < k && minHeap.size() > 0; i++) {
            res.add(minHeap.poll());
        }
        return res;
    }

解析:将相加的结果存入小顶堆中

遍历查找第k个即可

378. 有序矩阵中第K小的元素    中等

给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第 k 小的元素。
请注意,它是排序后的第 k 小元素,而不是第 k 个不同的元素。

示例:

matrix = [
   [ 1,  5,  9],
   [10, 11, 13],
   [12, 13, 15]
],
k = 8,

返回 13。

提示:
你可以假设 k 的值永远是有效的,1 ≤ k ≤ n2 

    //堆  个人实现,效率较低
    public int kthSmallest(int[][] matrix, int k) {
        PriorityQueue<Integer> minHeap = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                minHeap.add(matrix[i][j]);
            }
        }
        int res = matrix[0][0];
        for (int i = 0; i < k; i++) {
            res = minHeap.poll();
        }
        return res;
    }

解析:使用一个小顶堆将元素全部存储起来,找第k个即可

451. 根据字符出现频率排序    中等

给定一个字符串,请将字符串里的字符按照出现的频率降序排列。

示例 1:

输入:
"tree"

输出:
"eert"

解释:
'e'出现两次,'r'和't'都只出现一次。
因此'e'必须出现在'r'和't'之前。此外,"eetr"也是一个有效的答案。

示例 2:

输入:
"cccaaa"

输出:
"cccaaa"

解释:
'c'和'a'都出现三次。此外,"aaaccc"也是有效的答案。
注意"cacaca"是不正确的,因为相同的字母必须放在一起。

示例 3:

输入:
"Aabb"

输出:
"bbAa"

解释:
此外,"bbaA"也是一个有效的答案,但"Aabb"是不正确的。
注意'A'和'a'被认为是两种不同的字符。
    //堆  个人实现,效率较低
    Map<Character, Integer> map = new HashMap<>();
    public String frequencySort(String s) {
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            map.put(ch, map.getOrDefault(ch, 0) + 1);
        }
        PriorityQueue<Map.Entry<Character, Integer>> heap = new PriorityQueue<>(new Comparator<Map.Entry<Character, Integer>>() {
            @Override
            public int compare(Map.Entry<Character, Integer> o1, Map.Entry<Character, Integer> o2) {
                return o2.getValue().compareTo(o1.getValue());
            }
        });
        for (Map.Entry<Character, Integer> entry : map.entrySet()) {
            heap.add(entry);
        }
        StringBuilder builder = new StringBuilder();
        while (!heap.isEmpty()) {
            Map.Entry<Character, Integer> entry = heap.poll();
            for (int i = 0; i < entry.getValue(); i++) {
                builder.append(entry.getKey());
            }
        }
        return builder.toString();
    }

解析:使用map来存储每个字符及其出现的次数

将map放入一个大顶堆中

遍历放入builder中

返回即可

    //map+list排序实现
    private Map<Character, Integer> map = new HashMap<>();
    public String frequencySort(String s) {
        for (int i = 0; i < s.length(); i++) {
            char ch = s.charAt(i);
            map.put(ch, map.getOrDefault(ch, 0) + 1);
        }
        List<Map.Entry<Character, Integer>> list = new ArrayList<>(map.entrySet());
        list.sort(new Comparator<Map.Entry<Character, Integer>>() {
            @Override
            public int compare(Map.Entry<Character, Integer> o1, Map.Entry<Character, Integer> o2) {
                return o2.getValue().compareTo(o1.getValue());
            }
        });
        StringBuilder builder = new StringBuilder();
        for (Map.Entry<Character, Integer> entry : list) {
            for (int i = 0; i < entry.getValue(); i++) {
                builder.append(entry.getKey());
            }
        }
        return builder.toString();
    }

解析:使用map将字符及其数量存储起来

放入集合list中进行排序

遍历即可

692. 前K个高频单词    中等

给一非空的单词列表,返回前 个出现次数最多的单词。

返回的答案应该按单词出现频率由高到低排序。如果不同的单词有相同出现频率,按字母顺序排序。

示例 1:

输入: ["i", "love", "leetcode", "i", "love", "coding"], k = 2
输出: ["i", "love"]
解析: "i" 和 "love" 为出现次数最多的两个单词,均为2次。
    注意,按字母顺序 "i" 在 "love" 之前。

示例 2:

输入: ["the", "day", "is", "sunny", "the", "the", "the", "sunny", "is", "is"], k = 4
输出: ["the", "is", "sunny", "day"]
解析: "the", "is", "sunny" 和 "day" 是出现次数最多的四个单词,
    出现次数依次为 4, 3, 2 和 1 次。

注意:

  1. 假定 k 总为有效值, 1 ≤ k ≤ 集合元素数。
  2. 输入的单词均由小写字母组成。

扩展练习:

  1. 尝试以 O(n log k) 时间复杂度和 O(n) 空间复杂度解决。
    //个人实现 堆+map
    public List<String> topKFrequent(String[] words, int k) {
        Map<String, Integer> map = new HashMap<>();
        for (String word : words) {
            map.put(word, map.getOrDefault(word, 0) + 1);
        }
        PriorityQueue<Map.Entry<String, Integer>> maxHeap = new PriorityQueue<>(new Comparator<Map.Entry<String, Integer>>() {
            @Override
            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
                if (o1.getValue() != o2.getValue()) {
                    return o2.getValue().compareTo(o1.getValue());
                } else {
                    return o1.getKey().compareTo(o2.getKey());
                }
            }
        });
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            maxHeap.add(entry);
        }
        List<String> list = new ArrayList<>();
        for (int i = 0; i < k && maxHeap.size() > 0; i++) {
            list.add(maxHeap.poll().getKey());
        }
        return list;
    }

解析:使用堆+map实现

767. 重构字符串    中等

给定一个字符串S,检查是否能重新排布其中的字母,使得两相邻的字符不同。

若可行,输出任意可行的结果。若不可行,返回空字符串。

示例 1:

输入: S = "aab"
输出: "aba"

示例 2:

输入: S = "aaab"
输出: ""

注意:

  • S 只包含小写字母并且长度在[1, 500]区间内。
    public String reorganizeString(String S) {
        int n = S.length();
        Map<Character, Integer> map = new HashMap<>();
        for (int i = 0; i < S.length(); i++) {
            char ch = S.charAt(i);
            map.put(ch, map.getOrDefault(ch, 0) + 1);
        }
        List<Map.Entry<Character, Integer>> list = new ArrayList<>(map.entrySet());
        list.sort(new Comparator<Map.Entry<Character, Integer>>() {
            //从小到大排序
            @Override
            public int compare(Map.Entry<Character, Integer> o1, Map.Entry<Character, Integer> o2) {
                if (o1.getValue() != o2.getValue()) {
                    return o1.getValue().compareTo(o2.getValue());
                } else {
                    return o1.getKey().compareTo(o2.getKey());
                }
            }
        });
        int t = 1;
        char[] chars = new char[n];
        for (Map.Entry<Character, Integer> entry : list) {
            if (entry.getValue() > (n + 1) / 2) {
                return "";
            }
            for (int i = 0; i < entry.getValue(); i++) {
                if (t >= n) {
                    t = 0;
                }
                chars[t] = entry.getKey();
                t += 2;
            }
        }
        return String.valueOf(chars);
    }

解析:使用map将各个字符及其数量存储起来

隔空插入字符

class Solution {
    //map+堆+新类
    public String reorganizeString(String S) {
        int n = S.length();
        Map<Character, Integer> map = new HashMap<>();
        for (int i = 0; i < n; i++) {
            char ch = S.charAt(i);
            map.put(ch, map.getOrDefault(ch, 0) + 1);
        }
        PriorityQueue<MuitChar> maxHeap = new PriorityQueue<>(new Comparator<MuitChar>() {
            @Override
            public int compare(MuitChar o1, MuitChar o2) {
                if (o1.count != o2.count) {
                    return o2.count - o1.count;
                } else {
                    return o1.letter - o2.letter;
                }
            }
        });
        for (Map.Entry<Character, Integer> entry : map.entrySet()) {
            if (entry.getValue() > (n + 1) / 2) {
                return "";
            }
            maxHeap.add(new MuitChar(entry.getKey(), entry.getValue()));
        }
        StringBuilder builder = new StringBuilder();
        while (maxHeap.size() >= 2) {
            MuitChar muitChar1 = maxHeap.poll();
            MuitChar muitChar2 = maxHeap.poll();
            builder.append(muitChar1.letter);
            builder.append(muitChar2.letter);
            if (--muitChar1.count > 0) {
                maxHeap.add(muitChar1);
            }
            if (--muitChar2.count > 0) {
                maxHeap.add(muitChar2);
            }
        }
        if (maxHeap.size() > 0) {
            builder.append(maxHeap.poll().letter);
        }
        return builder.toString();
    }
}
class MuitChar{
    char letter;
    int count;

    public MuitChar(char letter, int count) {
        this.letter = letter;
        this.count = count;
    }
}

解析:先用一个map放入字符串及其数量

将map中的结果封装为MuitChar放入大顶堆中

每次取出堆中两个元素放入builder中

    //个人实现 map+堆
    public String reorganizeString(String S) {
        Map<Character, Integer> map = new HashMap<>();
        int n = S.length();
        for (int i = 0; i < n; i++) {
            char ch = S.charAt(i);
            map.put(ch, map.getOrDefault(ch, 0) + 1);
        }
        PriorityQueue<Map.Entry<Character, Integer>> maxHeap = new PriorityQueue<>(new Comparator<Map.Entry<Character, Integer>>() {
            @Override
            public int compare(Map.Entry<Character, Integer> o1, Map.Entry<Character, Integer> o2) {
                if (o1.getValue() != o2.getValue()) {
                    return o2.getValue().compareTo(o1.getValue());
                } else {
                    return o1.getKey().compareTo(o2.getKey());
                }
            }
        });
        for (Map.Entry<Character, Integer> entry : map.entrySet()) {
            if (entry.getValue() > (n + 1) / 2) {
                return "";
            }
            maxHeap.add(entry);
        }
        StringBuilder builder = new StringBuilder();
        while (maxHeap.size() >= 2) {
            Map.Entry<Character, Integer> entry1 = maxHeap.poll();
            Map.Entry<Character, Integer> entry2 = maxHeap.poll();
            builder.append(entry1.getKey());
            builder.append(entry2.getKey());
            if (entry1.getValue() - 1 > 0) {
                entry1.setValue(entry1.getValue() - 1);
                maxHeap.add(entry1);
            }
            if (entry2.getValue() - 1 > 0) {
                entry2.setValue(entry2.getValue() - 1);
                maxHeap.add(entry2);
            }
        }
        if (maxHeap.size() > 0) {
            builder.append(maxHeap.poll().getKey());
        }
        return builder.toString();
    }

解析:每次pop出两个元素

973. 最接近原点的 K 个点    中等

我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。

(这里,平面上两点之间的距离是欧几里德距离。)

你可以按任何顺序返回答案。除了点坐标的顺序之外,答案确保是唯一的。

示例 1:

输入:points = [[1,3],[-2,2]], K = 1
输出:[[-2,2]]
解释: 
(1, 3) 和原点之间的距离为 sqrt(10),
(-2, 2) 和原点之间的距离为 sqrt(8),
由于 sqrt(8) < sqrt(10),(-2, 2) 离原点更近。
我们只需要距离原点最近的 K = 1 个点,所以答案就是 [[-2,2]]。

示例 2:

输入:points = [[3,3],[5,-1],[-2,4]], K = 2
输出:[[3,3],[-2,4]]
(答案 [[-2,4],[3,3]] 也会被接受。)

提示:

  1. 1 <= K <= points.length <= 10000
  2. -10000 < points[i][0] < 10000
  3. -10000 < points[i][1] < 10000
    //个人实现  堆
    public int[][] kClosest(int[][] points, int K) {
        int[][] res = new int[K][2];
        PriorityQueue<int[]> minHeap = new PriorityQueue<>(new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                int num1 = o1[0] * o1[0] + o1[1] * o1[1];
                int num2 = o2[0] * o2[0] + o2[1] * o2[1];
                return Integer.compare(num1, num2);
            }
        });
        for (int i = 0; i < points.length; i++) {
            minHeap.add(points[i]);
        }
        for (int i = 0; i < K && minHeap.size() > 0; i++) {
            res[i] = minHeap.poll();
        }
        return res;
    }

解析:使用一个小顶堆,将每一个数组放入小顶堆中,从中选出K个数组

1054. 距离相等的条形码    中等

在一个仓库里,有一排条形码,其中第 i 个条形码为 barcodes[i]

请你重新排列这些条形码,使其中两个相邻的条形码 不能 相等。 你可以返回任何满足该要求的答案,此题保证存在答案。

示例 1:

输入:[1,1,1,2,2,2]
输出:[2,1,2,1,2,1]

示例 2:

输入:[1,1,1,1,2,2,3,3]
输出:[1,3,1,3,2,1,2,1]

提示:

  1. 1 <= barcodes.length <= 10000
  2. 1 <= barcodes[i] <= 10000
    //大顶堆+map
    public int[] rearrangeBarcodes(int[] barcodes) {
        Map<Integer, Integer> map = new HashMap<>();
        int n = barcodes.length;
        for (int barcode : barcodes) {
            map.put(barcode, map.getOrDefault(barcode, 0) + 1);
        }
        PriorityQueue<Map.Entry<Integer, Integer>> maxHeap = new PriorityQueue<>(new Comparator<Map.Entry<Integer, Integer>>() {
            @Override
            public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) {
                if (o1.getValue() != o2.getValue()) {
                    return o2.getValue().compareTo(o1.getValue());
                } else {
                    return o1.getKey().compareTo(o2.getKey());
                }
            }
        });
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if (entry.getValue() > (n + 1) / 2) {
                return new int[]{};
            }
            maxHeap.add(entry);
        }
        int res[] = new int[n];
        int t = 0;
        while (maxHeap.size() >= 2) {
            Map.Entry<Integer, Integer> entry1 = maxHeap.poll();
            Map.Entry<Integer, Integer> entry2 = maxHeap.poll();
            res[t++] = entry1.getKey();
            res[t++] = entry2.getKey();
            if (entry1.getValue() - 1 > 0) {
                entry1.setValue(entry1.getValue() - 1);
                maxHeap.add(entry1);
            }
            if (entry2.getValue() - 1 > 0) {
                entry2.setValue(entry2.getValue() - 1);
                maxHeap.add(entry2);
            }
        }
        if (maxHeap.size() > 0) {
            res[t++] = maxHeap.poll().getKey();
        }
        return res;
    }

解析:大顶堆+map

面试题

面试题 17.09. 第 k 个数    中等

有些数的素因子只有 3,5,7,请设计一个算法找出第 k 个数。注意,不是必须有这些素因子,而是必须不包含其他的素因子。例如,前几个数按顺序应该是 1,3,5,7,9,15,21。

示例 1:

输入: k = 5

输出: 9
    public int getKthMagicNumber(int k) {
        int res = 0;
        Set<Long> set = new HashSet<>();
        PriorityQueue<Long> minHeap = new PriorityQueue<>();
        set.add(1L);
        minHeap.add(1L);
        int arr[] = new int[]{3, 5, 7};
        long curr, temp;
        for (int i = 0; i < k; i++) {
            curr = minHeap.poll();
            res = (int) curr;
            for (int ele : arr) {
                temp = ele * curr;
                if (!set.contains(temp)) {
                    set.add(temp);
                    minHeap.add(temp);
                }
            }
        }
        return res;
    }

解析:就是丑数的题解

面试题 17.14. 最小K个数    中等

设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。

示例:

输入: arr = [1,3,5,7,2,4,6,8], k = 4
输出: [1,2,3,4]

提示:

  • 0 <= len(arr) <= 100000
  • 0 <= k <= min(100000, len(arr))
    //个人实现  堆
    public int[] smallestK(int[] arr, int k) {
        int[] res = new int[k];
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        for (int ele : arr) {
            minHeap.add(ele);
        }
        for (int i = 0; i < k && minHeap.size() > 0; i++) {
            res[i] = minHeap.poll();
        }
        return res;
    }

解析:将元素全部存储在堆中,选出前k个元素返回即可

猜你喜欢

转载自blog.csdn.net/qq_43204550/article/details/109020420