上岸算法 I LeetCode Weekly Contest 217解題報告

No.1 最富有客戶的資產總量數組

解題思路this

求子數組和的最大值. 可使用 Java 8 以後的 stream 一句話搞定.code

代碼展現排序

classSolution{

    publicintmaximumWealth(int[][] accounts){

        return Arrays.stream(accounts).

                map(i -> Arrays.stream(i).sum()).

                max(Integer::compareTo).get();

    }

}

No.2 找出最具競爭力都子序列隊列

解題思路ci

即找到長度爲 k 的字典序最小的子序列. 貪心地每次取最小的數便可.rem

可是咱們不能取全局範圍的最小數, 好比說第一次取, 咱們只能在 [0, n - k] 的下標範圍內取最小的, 假設取到的最小值的下標爲 x, 那麼第二次取就應該在 [x, n - k + 1] 的下標範圍內取最小的.get

可使用優先隊列完成.it

代碼展現io

class Number {

    int num;

    int idx;

    public Number(int num, int idx) {

        this.num = num;

        this.idx = idx;

    }

}

public int[] mostCompetitive(int[] nums, int k) {

    // 優先按照數值大小排序, 大小相同則按照下標排序

    PriorityQueue<Number> heap = new PriorityQueue<>((a, b) -> a.num == b.num ? a.idx - b.idx : a.num - b.num);

    // idx 表示區間的右端點

    int idx;

    for (idx = 0; idx <= nums.length - k; idx++) {

        heap.add(new Number(nums[idx], idx));

    }

    int[] res = new int[k];

    int latestIdx = -1;

    for (int i = 0; i < k; i++) {

        Number num = heap.poll();

        // 利用 latestIdx 移動區間左端點

        while (num.idx < latestIdx) {

            num = heap.poll();

        }

        // 取到了當前區間 [x, n - k + i] 中的最小值

        res[i] = num.num;

        latestIdx = num.idx;

        // 右端點更新, 繼續向優先隊列里加數

        for (; idx <= nums.length - k + i + 1 && idx < nums.length; idx++) {

            heap.add(new Number(nums[idx], idx));

        }

    }

    return res;

}

}

No.3 使數組互補的最少操做數

解題思路

核心仍然是枚舉: 枚舉最終的和是多少. 經過預處理的數據快速計算要使每組數達到這個和, 須要改動多少個數字.

代碼展現

class Solution {

    public int minMoves(int[] nums, int limit) {

        int halfLen = nums.length / 2;

        // 提取每組數, 便於後續處理

        int[] smallPart = new int[halfLen];

        int[] bigPart = new int[halfLen];

        for (int i = 0, j = nums.length - 1; i < j; i++, j--) {

            smallPart[i] = Math.min(nums[i], nums[j]);

            bigPart[i] = Math.max(nums[i], nums[j]);

        }

        // 數值數量的前綴和

        int[] smallCntPreSum = new int[limit + 1];

        int[] bigCntPreSum = new int[limit + 1];

        for (int i = 0; i < halfLen; i++) {

            smallCntPreSum[smallPart[i]]++;

            bigCntPreSum[bigPart[i]]++;

        }

        for (int i = 1; i <= limit; i++) {

            smallCntPreSum[i] += smallCntPreSum[i - 1];

            bigCntPreSum[i] += bigCntPreSum[i - 1];

        }

        // 原有的加和數值計數

        int[] sumCnt = new int[limit * 2 + 1];

        for (int i = 0; i < halfLen; i++) {

            sumCnt[smallPart[i] + bigPart[i]]++;

        }

        int res = nums.length;

        for (int sum = 2; sum <= limit + limit; ++sum) {

            // 最終的和爲 sum 時, 須要改動 tot 個數

            int tot = halfLen - sumCnt[sum];

            if (sum <= limit)

                tot += halfLen - smallCntPreSum[sum - 1];

            else

                tot += bigCntPreSum[sum - limit - 1];

            res = Math.min(res, tot);

        }

        return res;

    }

}

No.4 數組的最小偏移量

解題思路

每一個數都有必定的變化範圍, 好比 5 只能變成 5 或 10, 而 8 能夠變成 1, 2, 4, 8

雙向變化很差處理, 咱們能夠先將每一個數都變成它的最大值的形式: 偶數不變, 奇數能夠乘以 2.

而後咱們須要作的就是把一些數縮小, 以使得最大值和最小值的差最小.

咱們須要縮小的就是最大值——由於只有縮小最大值才能影響結果. 因此, 不斷縮小最大值便可.

代碼展現

class Solution {

    public int minimumDeviation(int[] nums) {

        TreeSet<Integer> set = new TreeSet<>();

        for (int num : nums) {

            set.add(num % 2 == 0 ? num : num * 2);

        }

        int res = set.last() - set.first();

        while (res > 0 && set.last() % 2 == 0) {

            int max = set.last();

            set.remove(max);

            set.add(max / 2);

            res = Math.min(res, set.last() - set.first());

        }

        return res;

    }

}
相關文章
相關標籤/搜索