1. 程式人生 > 其它 >[Leetcode Weekly Contest]262

[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