【Zilliz專場】力扣第 271 場周賽覆盤

語言: CN / TW / HK

你好,我是小黃,一名獨角獸企業的Java開發工程師。 感謝茫茫人海中我們能夠相遇, 俗話說:當你的才華和能力,不足以支撐你的夢想的時候,請靜下心來學習 希望優秀的你可以和我一起學習,一起努力,實現屬於自己的夢想。

這周沒起來,遲到了一會~

一、5952. 環和杆

1、題目簡介

在這裡插入圖片描述

2、題目解析

  • 簽到題,我們使用 Map<Character, Set<Character>> 來進行儲存
  • 遍歷 map,判斷 valuesize 是否為 3 就可

3、題目程式碼

```java class Solution { public int countPoints(String rings) { Map> map = new HashMap<>(); for (int i = 0; i < rings.length(); i = i + 2) { char ch = rings.charAt(i); char index = rings.charAt(i + 1); if (map.containsKey(index)) { map.get(index).add(ch); } else { Set set = new HashSet<>(); set.add(ch); map.put(index, set); } }

    int num = 0;
    for (Set<Character> set : map.values()) {
        if (set.size() == 3) {
            num++;
        }
    }
    return num;
}

} ```

在這裡插入圖片描述

二、5953. 子陣列範圍和

1、題目簡介

在這裡插入圖片描述

2、題目解析

  • 這個題,W了三次才過,原因在於:我一開始使用 List<List<Integer>> 來進行儲存,導致記憶體直接爆了,時間也超時了
  • 後續想了想優化空間:使用兩個最優佇列來儲存當前的最大值和最小值,這樣我們就可以用 O(1) 的時間複雜度獲取當前 max - min 的值
  • 最後第4次才過,嗚嗚嗚
  • 第二種做法:我們暴力的同時使用 maxmin 維護當前的最大值和最小值,見 程式碼二

3、題目程式碼

程式碼一 時間複雜度相對 程式碼二 來說,主要增加了 最優佇列選舉最大或最小 的時間

3.1 程式碼一

```java class Solution { public long subArrayRanges(int[] nums) { long sum = 0; for (int i = 0; i < nums.length; i++) { sum = sum + f(nums, i, 0); }

    return sum;
}



public long f(int[] nums, int index, long sum) {
    PriorityQueue<Integer> priorityQueue = new PriorityQueue<>(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;
        }
    });
    PriorityQueue<Integer> priorityQueue2 = new PriorityQueue<>(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1 - o2;
        }
    });
    List<Long> path = new ArrayList<>();
    for (int i = index; i < nums.length; i++) {
        priorityQueue.add(nums[i]);
        priorityQueue2.add(nums[i]);
        sum = sum + (priorityQueue.peek() - priorityQueue2.peek());
    }
    return sum;
}

} ``` 在這裡插入圖片描述

3.2 程式碼二

java class Solution { public long subArrayRanges(int[] nums) { long sum = 0; for (int i = 0; i < nums.length; i++) { int max = nums[i]; int min = nums[i]; for(int j = i + 1; j < nums.length; j++){ max = Math.max(max, nums[j]); min = Math.min(min, nums[j]); sum += max - min; } } return sum; } } 在這裡插入圖片描述

三、5954. 給植物澆水 II

1、題目簡介

在這裡插入圖片描述

2、題目解析

  • 模擬題,模擬每次倒水的流程
  • 題主這裡W一次是因為忘記 當前的水 = 可澆水 ,忘記相等也可以直接澆水了,筆誤。。。。

3、題目程式碼

```java class Solution { public int minimumRefill(int[] plants, int capacityA, int capacityB) { int sum = 0; int capacityAMAX = capacityA; int capacityBMAX = capacityB;

    // A從開頭澆水
    // B從結尾澆水

    int indexA = 0;
    int indexB = plants.length - 1;

    while (indexA < indexB) {
        // A 澆水
        if (plants[indexA] <= capacityA) {
            capacityA = capacityA - plants[indexA];
        } else {
            sum++;
            capacityA = capacityAMAX;
            capacityA = capacityA - plants[indexA];
        }

        // B澆水
        if (plants[indexB] <= capacityB) {
            capacityB = capacityB - plants[indexB];
        } else {
            sum++;
            capacityB = capacityBMAX;
            capacityB = capacityB - plants[indexB];
        }

        indexA++;
        indexB--;
    }
    if (indexA == indexB) {
        if (capacityA >= capacityB) {
            if (plants[indexA] <= capacityA) {
                capacityA = capacityA - plants[indexA];
            } else {
                sum++;
                capacityA = capacityAMAX;
                capacityA = capacityA - plants[indexA];
            }
        } else {
            // B澆水
            if (plants[indexB] <= capacityB) {
                capacityB = capacityB - plants[indexB];
            } else {
                sum++;
                capacityB = capacityBMAX;
                capacityB = capacityB - plants[indexB];
            }
        }
    }
    return sum;
}

} ``` 在這裡插入圖片描述

四、5955. 摘水果

1、題目簡介

在這裡插入圖片描述

2、題目解析

  • 題主一開始直接寫了一個 dfs 交上去了,不出所料,就這資料量,卡的死死的
  • 我們將題目簡化為:在一段區間中,找到最大的水果總數[L,R]
  • 這個區間的範圍:我們的總步數為 k
    • 我們可以先往右走 i 步,再往左走 k - i,那麼我們的區間為:[startPos + i - k + i ,startPos + i]
    • 我們也可以先往左走 i 步,再往左走 k - i,那麼我們的區間為:[startPos - i, startPos - i + k - i]
  • 我們可以用字首和求出整個表上的水果數目,然後暴力求每個區間的獲得水果的最大值

3、題目程式碼

3.1 DFS

```java public int maxTotalFruits(int[][] fruits, int startPos, int k) { Map map = new HashMap<>(); int max = Integer.MIN_VALUE; for (int i = 0; i < fruits.length; i++) { int index = fruits[i][0]; if (max <= index) { max = index; } int value = fruits[i][1]; map.put(index, value); } return dfs(map, startPos, k, max, 0); }

public int dfs(Map<Integer, Integer> map, int startPos, int k, int len, int sum) {
    // 判斷越界
    if (startPos < 0 || startPos >= len || k == 0) {
        return sum;
    }
    int value = map.getOrDefault(startPos, 0);
    // 判斷一下有沒有吃到水果
    if (map.containsKey(startPos)) {
        sum = sum + map.get(startPos);
        // 需要將此後設定為0
        map.put(startPos, 0);
    }
    // 然後去下一個狀態
    int num1 = dfs(map, startPos - 1, k - 1, len, sum);
    int num2 = dfs(map, startPos + 1, k - 1, len, sum);

    // 最後別忘記了回溯
    map.put(startPos, value);

    return Math.max(num1, num2);
}

```

3.2 貪心

```java class Solution { public int maxTotalFruits(int[][] fruits, int startPos, int k) { int MAX = 200001; int[] arr = new int[MAX]; int index = 0; int currSum = 0; for(int i = 0; i < MAX; i++){ if(index < fruits.length && fruits[index][0] == i){ currSum = currSum + fruits[index][1]; index++; } arr[i] = currSum; }

    // 計算K步最多能走的步數
    int res = 0;

    //先往左走i步, 再往右走 k - i 步
    for(int i = 0; i <= k; i++){
        // 防止越界
        int left = Math.max(0, startPos - i);
        int right = Math.min(MAX - 1, left + k - i);
        int curr = arr[right] - (left == 0 ? 0 : arr[left - 1]);
        res = Math.max(res, curr);
    }

    // 先往右走i步,再往左走k - i步
    for(int i = 0; i <= k; i++){
        int right = Math.min(startPos + i, MAX - 1);
        int left = Math.max(0, right - k + i);
        int curr = arr[right] - (left == 0 ? 0 : arr[left - 1]);
        res = Math.max(res, curr);
    }

    return res;

}

} ``` 在這裡插入圖片描述

五、總結

本週又是三題,由於一些細心問題,導致罰時過多,過三題排名 626 ~ 2250

可以看出,程式設計師的演算法能力逐漸開始上升

下週爭取不遲到,爭取AK!