zoukankan      html  css  js  c++  java
  • lc0327

    ✅ 面试题40. 最小的k个数

    https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/

    描述

    输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
    
     
    
    示例 1:
    
    输入:arr = [3,2,1], k = 2
    输出:[1,2] 或者 [2,1]
    示例 2:
    
    输入:arr = [0,1,2,1], k = 1
    输出:[0]
     
    
    限制:
    
    0 <= k <= arr.length <= 10000
    0 <= arr[i] <= 10000
    
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    

    解答

    c

    1.快排:
    
    class Solution {
        public int[] getLeastNumbers(int[] arr, int k) {
            if (k == 0 || arr.length == 0) {
                return new int[0];
            }
            // 最后一个参数表示我们要找的是下标为k-1的数
            return quickSearch(arr, 0, arr.length - 1, k - 1);
        }
    
        private int[] quickSearch(int[] nums, int lo, int hi, int k) {
            // 每快排切分1次,找到排序后下标为j的元素,如果j恰好等于k就返回j以及j左边所有的数;
            int j = partition(nums, lo, hi);
            if (j == k) {
                return Arrays.copyOf(nums, j + 1);
            }
            // 否则根据下标j与k的大小关系来决定继续切分左段还是右段。
            return j > k? quickSearch(nums, lo, j - 1, k): quickSearch(nums, j + 1, hi, k);
        }
    
        // 快排切分,返回下标j,使得比nums[j]小的数都在j的左边,比nums[j]大的数都在j的右边。
        private int partition(int[] nums, int lo, int hi) {
            int v = nums[lo];
            int i = lo, j = hi + 1;
            while (true) {
                //tt 快排手艺背诵!
                while (++i <= hi && nums[i] < v);
                while (--j >= lo && nums[j] > v);
                if (i >= j) {
                    break;
                }
                int t = nums[j];
                nums[j] = nums[i];
                nums[i] = t;
            }
            nums[lo] = nums[j];
            nums[j] = v;//tt 想象一种回归吧
            return j;
        }
    }
    2.大根堆
    
    // 保持堆的大小为K,然后遍历数组中的数字,遍历的时候做如下判断:
    // 1. 若目前堆的大小小于K,将当前数字放入堆中。
    // 2. 否则判断当前数字与大根堆堆顶元素的大小关系,如果当前数字比大根堆堆顶还大,这个数就直接跳过;
    //    反之如果当前数字比大根堆堆顶小,先poll掉堆顶,再将该数字放入堆中。
    class Solution {
        public int[] getLeastNumbers(int[] arr, int k) {
            if (k == 0 || arr.length == 0) {
                return new int[0];
            }
            // 默认是小根堆,实现大根堆需要重写一下比较器。
            Queue<Integer> pq = new PriorityQueue<>((v1, v2) -> v2 - v1);
            for (int num: arr) {
                if (pq.size() < k) {
                    pq.offer(num);
                } else if (num < pq.peek()) {
                    pq.poll();
                    pq.offer(num);
                }
            }
            
            // 返回堆中的元素
            int[] res = new int[pq.size()];
            int idx = 0;
            for(int num: pq) {
                res[idx++] = num;
            }
            return res;
        }
    }
    3.二叉搜索树
    
    class Solution {
        public int[] getLeastNumbers(int[] arr, int k) {
            if (k == 0 || arr.length == 0) {
                return new int[0];
            }
            // TreeMap的key是数字, value是该数字的个数。
            // cnt表示当前map总共存了多少个数字。
            TreeMap<Integer, Integer> map = new TreeMap<>();
            int cnt = 0;
            for (int num: arr) {
                // 1. 遍历数组,若当前map中的数字个数小于k,则map中当前数字对应个数+1
                if (cnt < k) {
                    map.put(num, map.getOrDefault(num, 0) + 1);
                    cnt++;
                    continue;
                } 
                // 2. 否则,取出map中最大的Key(即最大的数字), 判断当前数字与map中最大数字的大小关系:
                //    若当前数字比map中最大的数字还大,就直接忽略;
                //    若当前数字比map中最大的数字小,则将当前数字加入map中,并将map中的最大数字的个数-1。
                Map.Entry<Integer, Integer> entry = map.lastEntry();
                if (entry.getKey() > num) {
                    map.put(num, map.getOrDefault(num, 0) + 1);
                    if (entry.getValue() == 1) {
                        map.pollLastEntry();
                    } else {
                        map.put(entry.getKey(), entry.getValue() - 1);
                    }
                }
                
            }
    
            // 最后返回map中的元素
            int[] res = new int[k];
            int idx = 0;
            for (Map.Entry<Integer, Integer> entry: map.entrySet()) {
                int freq = entry.getValue();
                while (freq-- > 0) {
                    res[idx++] = entry.getKey();
                }
            }
            return res;
        }
    }
    计数排序
    class Solution {
        public int[] getLeastNumbers(int[] arr, int k) {
            if (k == 0 || arr.length == 0) {
                return new int[0];
            }
            // 统计每个数字出现的次数
            int[] counter = new int[10001];
            for (int num: arr) {
                counter[num]++;
            }
            // 根据counter数组从头找出k个数作为返回结果
            int[] res = new int[k];
            int idx = 0;
            for (int num = 0; num < counter.length; num++) {
                while (counter[num]-- > 0 && idx < k) {
                    res[idx++] = num;
                }
                if (idx == k) {
                    break;
                }
            }
            return res;
        }
    }
    

    py

    class Solution:
        def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
            my_list = sorted(arr)
            return my_list[:k]
            '''
    执行用时 :
    60 ms
    , 在所有 Python3 提交中击败了
    80.11%
    的用户
    内存消耗 :
    14.7 MB
    , 在所有 Python3 提交中击败了
    100.00%
    的用户
            '''
    

    ✅ 868. 二进制间距

    https://leetcode-cn.com/problems/binary-gap/

    描述

    给定一个正整数 N,找到并返回 N 的二进制表示中两个连续的 1 之间的最长距离。 
    
    如果没有两个连续的 1,返回 0 。
    
     
    
    示例 1:
    
    输入:22
    输出:2
    解释:
    22 的二进制是 0b10110 。
    在 22 的二进制表示中,有三个 1,组成两对连续的 1 。
    第一对连续的 1 中,两个 1 之间的距离为 2 。
    第二对连续的 1 中,两个 1 之间的距离为 1 。
    答案取两个距离之中最大的,也就是 2 。
    示例 2:
    
    输入:5
    输出:2
    解释:
    5 的二进制是 0b101 。
    
    示例 3:
    
    输入:6
    输出:1
    解释:
    6 的二进制是 0b110 。
    示例 4:
    
    输入:8
    输出:0
    解释:
    8 的二进制是 0b1000 。
    在 8 的二进制表示中没有连续的 1,所以返回 0 。
     
    
    提示:
    
    1 <= N <= 10^9
    
    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/binary-gap
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
    

    解答

    c

    不断右移,然后记着之前的一个1 的prevPos, 碰到新的1 就计算 新的最大位置。

    class Solution {
    public:
        int binaryGap(int N) {
            int cnt = 0, prev = -1, ans = 0;
            
            while (N) {
                if (N & 1) {
                    if (prev != -1) ans = max(ans, cnt - prev);
                    prev = cnt;
                }
                N >>= 1;
                cnt ++; // 坐标
            }
            return ans;
        }
    };
    

    py

    class Solution:
        def binaryGap(self, N: int) -> int:
            gaps = [len(_) for _ in bin(N)[2:].split('1')[1:-1]]
            return max(gaps) + 1 if len(gaps) > 0 else 0
    '''
    执行用时 :
    52 ms
    , 在所有 Python3 提交中击败了
    12.23%
    的用户
    内存消耗 :
    13.6 MB
    , 在所有 Python3 提交中击败了
    6.52%
    的用户
    '''
    
    

    学习py 语法

    bin(a_int)

    
    class Solution:
        def binaryGap(self, N: int) -> int:
            print(bin(N)[2:])
    '''输入
    22
    输出
    None
    预期结果
    2
    stdout
    10110'''
    

    split(a_char)

    class Solution:
        def binaryGap(self, N: int) -> int:
            print(bin(N)[2:].split('1'))
    
            '''
    输入
    22
    输出
    None
    预期结果
    2
    stdout
    ['', '0', '', '0']
            '''
    
    class Solution:
        def binaryGap(self, N: int) -> int:
            gaps = [len(_) for _ in bin(N)[2:].split('1')[1:-1]]
    
            '''
            [1: -1] 意思是 仅仅保留 中间的,不要第一个 和最后一个
    stdout
    ['0', '']
            '''
    
  • 相关阅读:
    思维导图
    Delphi 之弹出气泡消息提示
    delphi 响应鼠标进入控件消息
    Delphi 获取当前鼠标下的控件内容
    delphi TTBXToolBar 增加外部控件
    delphi button 实现下拉列表
    delphi 设置多屏幕
    电脑双屏改单屏后看不到文件问题的解决
    delphi ListView 设置固定列宽
    数字孪生(Digital twin)
  • 原文地址:https://www.cnblogs.com/paulkg12/p/12580179.html
Copyright © 2011-2022 走看看