[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

posted @ 2021-10-10 19:46  Jamest  阅读(37)  评论(0编辑  收藏  举报