• [Leetcode Weekly Contest]262


    链接:LeetCode

    [Leetcode]5894. 至少在两个数组中出现的值

    给你三个整数数组 nums1、nums2 和 nums3 ,请你构造并返回一个 不同 数组,且由 至少 在 两个 数组中出现的所有值组成。数组中的元素可以按 任意 顺序排列。

    遍历即可。

    class Solution
    {
        public List<Integer> twoOutOfThree(int[] nums1, int[] nums2, int[] nums3)
        {
            Set<Integer> us1 = new HashSet<>();
            for (int x: nums1)  us1.add(x);
            Set<Integer> us2 = new HashSet<>();
            for (int x : nums2) us2.add(x);
            Set<Integer> us3 = new HashSet<>();
            for (int x : nums3) us3.add(x);
    
            Set<Integer> us = new HashSet<>();
            us.addAll(us1);
            us.addAll(us2);
            us.addAll(us3);
    
            List<Integer> res = new ArrayList<>();
            for (int x : us)
            {
                int f1 = us1.contains(x) == true ? 1 : 0;
                int f2 = us2.contains(x) == true ? 1 : 0;
                int f3 = us3.contains(x) == true ? 1 : 0;
                if (f1 + f2 + f3 >= 2)
                {
                    res.add(x);
                }
            }
            return res;
        }
    }
    

    [Leetcode]5895. 获取单值网格的最小操作数

    给你一个大小为 m x n 的二维整数网格 grid 和一个整数 x 。每一次操作,你可以对 grid 中的任一元素 加 x 或 减 x 。

    单值网格 是全部元素都相等的网格。

    返回使网格化为单值网格所需的 最小 操作数。如果不能,返回 -1 。

    贪心。要使任意两元素最终相等,这两元素的差必须是 x 的倍数,否则无法通过加减 x 来相等。我们可以以数组中的某一元素为基准,若所有元素与它的差均为 x 的倍数,则任意两元素之差为 x 的倍数。

    假设要让所有元素均为 y,设小于 y 的元素有 p 个,大于 y 的元素有 q 个,可以发现:

    若 p<q,y 每增加 x,操作数就可以减小 q-p;
    若 p>q,y 每减小 x,操作数就可以减小 p-q;
    因此 p=q 时可以让总操作数最小,此时 yy 为所有元素的中位数。

    class Solution {
        public int minOperations(int[][] grid, int x) {
            List<Integer> nums = new ArrayList<>();
            int n = grid.length, m=grid[0].length;
            for(int i=0;i<n;++i) {
                for(int j=0;j<m;++j) {
                    nums.add(grid[i][j]);
                }
            }
            //Collections.sort(nums);
            nums.sort(Comparator.naturalOrder());
            var ind = (m*n-1)/2;
            int val = nums.get(ind);
            int res = 0;
            for(var num:nums) {
                int result = Math.abs(num-val) / x;
                if((num-val)%x == 0) res += result;
                else return -1;
            }
            return res;
        }
    }
    

    [Leetcode]5896. 股票价格波动

    给你一支股票价格的数据流。数据流中每一条记录包含一个 时间戳 和该时间点股票对应的 价格 。

    不巧的是,由于股票市场内在的波动性,股票价格记录可能不是按时间顺序到来的。某些情况下,有的记录可能是错的。如果两个有相同时间戳的记录出现在数据流中,前一条记录视为错误记录,后出现的记录 更正 前一条错误的记录。

    请你设计一个算法,实现:

    更新 股票在某一时间戳的股票价格,如果有之前同一时间戳的价格,这一操作将 更正 之前的错误价格。
    找到当前记录里 最新股票价格 。最新股票价格 定义为时间戳最晚的股票价格。
    找到当前记录里股票的 最高价格 。
    找到当前记录里股票的 最低价格 。
    请你实现 StockPrice 类:

    StockPrice() 初始化对象,当前无股票价格记录。
    void update(int timestamp, int price) 在时间点 timestamp 更新股票价格为 price 。
    int current() 返回股票 最新价格 。
    int maximum() 返回股票 最高价格 。
    int minimum() 返回股票 最低价格 。

    int current() 返回股票 最新价格。我们只需要维护两个变量,最大的时间戳以及对应的价格即可
    而对于其他方法,我们需要读取的是股票的最低以及最高价格,但是update方法会更正某些时间戳的价格,因此股票的最高和最低价格是动态更新的。使用一个treemap,维护价格和时间戳的对应关系,对于某个价格,该股票可能有多个对应的时间戳,利用treemap的特性我们可以在o(1)的时间复杂度内获取当前最大和最小价格。我们可以使用map维护每个时间戳对应的价格。
    而update方法就需要维护上面的两个map。通过map,我们可以得到需要更新的时间戳原价是多少,再通过这个价格,定位到treemap里面,删除该时间戳。然后再将该时间戳和价格的对应关系插入到map和treemap里面。

    class StockPrice {
    
        //timeStamp ->price
        Map<Integer, Integer> map = new HashMap<>();
        //price -> timeStamps
        TreeMap<Integer, Set<Integer>> up = new TreeMap<>();
        int curTime=-1,curPrice=-1;
    
        public StockPrice() {
    
        }
    
        public void update(int timestamp, int price) {
            if (timestamp>=curTime)
            {
                curTime=timestamp;
                curPrice=price;
            }
    
    
            if(map.containsKey(timestamp)){
            Integer old = map.get(timestamp);
            up.get(old).remove(timestamp);
            if (up.get(old).isEmpty())
                up.remove(old);
            }
            map.put(timestamp, price);
            if (!up.containsKey(price))
                up.put(price,new HashSet<>());
            up.get(price).add(timestamp);
        }
    
        public int current() {
            return curPrice;
        }
    
        public int maximum() {
           return up.lastKey();
        }
    
        public int minimum() {
            return up.firstKey();
        }
    }
    
    /**
    * Your StockPrice object will be instantiated and called as such:
    * StockPrice obj = new StockPrice();
    * obj.update(timestamp,price);
    * int param_2 = obj.current();
    * int param_3 = obj.maximum();
    * int param_4 = obj.minimum();
    */
    

    [Leetcode]5897. 将数组分成两个数组并最小化数组和的差

    给你一个长度为 2 * n 的整数数组。你需要将 nums 分成 两个 长度为 n 的数组,分别求出两个数组的和,并 最小化 两个数组和之 差的绝对值 。nums 中每个元素都需要放入两个数组之一。

    请你返回 最小 的数组和之差。
    将 2n 个数组拆分成左右两个数组(前n个,后n个), 然后分别求出这两个数组的所有组合情况,最后遍历组合情况找到最佳结果
    不拆的话组合情况数太多,因此拆成两个数组分别求组合情况。

    class Solution {
    
        public int minimumDifference(int[] nums) {
            // 前 n 个元素元素组合情况存储在left 中, 后 n 个元素组合请情况存储在 right 中
            // Map<元素个数, Set<key个元素的总和>>
            Map<Integer, TreeSet<Integer>> left = new HashMap<>();
            Map<Integer, TreeSet<Integer>> right = new HashMap<>();
    
            int min = Integer.MAX_VALUE;
            int total = 0;
    
            int n = nums.length / 2;
            for(int i=0;i < 2 * n;i++){
                total += nums[i];
    
                if(i < n){
                    left.put(i+1, new TreeSet<>());
                }else{
                    right.put(i - n + 1, new TreeSet<>());
                }
            }
    
            dfs(nums, 0, 0, 0, n, left);
            dfs(nums, 0, 0, n, 2*n, right);
    
            // 情况一, 一部分元素在左侧,一部分元素在右侧
            for(int i=1;i<n;i++){
                TreeSet<Integer> set = left.get(i);
                for(int leftSum : set){
                    // 前 i 个元素在  left 中, 后  n - i 个元素在 right 中
                    // 最佳情况是分成两侧相等即  total / 2, 寻找最佳组合最近的组合
                    Integer rightSum = right.get(n-i).ceiling(total / 2 - leftSum);
                    if(null != rightSum){
                        int sum = leftSum + rightSum;
                        min = Math.min(min, Math.abs(sum - (total - sum)));
                    }
    
                    rightSum = right.get(n-i).floor(total / 2 - leftSum);
                    if(null != rightSum){
                        int sum = leftSum + rightSum;
                        min = Math.min(min, Math.abs(sum - (total - sum)));
                    }
    
                    if(min == 0){
                        return 0;
                    }
                }
            }
    
            // 情况二,  所有元素都来源与一侧
            TreeSet<Integer> set = left.get(n);
            for(int sum : set){
                min = Math.min(min, Math.abs(sum - (total - sum)));
            }
    
            return min;
        }
    
        /**
         * 递归枚举所有的元素组合,将元素组合情况存 Map<元素个数, Set<key个元素的总和>> 中
         *
         * @param nums
         * @param sum   已选数组和
         * @param count 已选数个数
         * @param idx   当前索引
         * @param limit   索引边界
         * @param visited
         */
        public void dfs(int[] nums, int sum, int count, int idx, int limit, Map<Integer, TreeSet<Integer>> visited){
            if(visited.containsKey(count)){
                visited.get(count).add(sum);
            }
    
            if(idx >= limit) return ;
    
            // 选择当前元素
            dfs(nums, sum + nums[idx], count+1, idx+1, limit, visited);
    
            // 不选当前元素
            dfs(nums, sum, count, idx+1, limit, visited);
        }
    }
    

    Leetcode

  • 相关阅读:
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    FM
    GBDT+LR
    推荐系统架构设计
    DSSM双塔模型
    git
  • 原文地址:https://www.cnblogs.com/hellojamest/p/15390384.html
Copyright © 2020-2023  润新知