leetcode周賽 - 406

艾尔夏尔-Layton發表於2024-07-14

100352. 交換後字典序最小的字串

  給你一個僅由數字組成的字串 s,在最多交換一次 相鄰 且具有相同 奇偶性 的數字後,返回可以得到的字典序最小的字串。

  如果兩個數字都是奇數或都是偶數,則它們具有相同的奇偶性。例如,5 和 9、2 和 4 奇偶性相同,而 6 和 9 奇偶性不同。

思路

  從左到右掃一遍就行,交換的越早越好,因為字典序是從左往右看的

import java.util.Arrays;

class Solution {
    public String getSmallestString(String s) {
        char[] charArray = s.toCharArray();
        for (int i = 0; i < charArray.length - 1; i++) {
            int now = charArray[i] - '0', nxt = charArray[i + 1] - '0';
            if (now % 2 == nxt % 2 && now > nxt) {
                char tmp = charArray[i];
                charArray[i] = charArray[i + 1];
                charArray[i + 1] = tmp;
                break;
            }
        }
        return new String(charArray);
    }
}

100368. 從連結串列中移除在陣列中存在的節點

  給你一個整數陣列 nums 和一個連結串列的頭節點 head。從連結串列中移除所有存在於 nums 中的節點後,返回修改後的連結串列的頭節點。

思路

  將nums轉成一個set,就能在O(1)的時間內判斷當前節點值在不在nums裡,然後掃一遍維護指標就行

  當然還有一種方法是記錄那些沒在nums裡的節點值,重新做一個連結串列出來返回

import java.util.HashSet;
import java.util.Set;
class Solution {
    public ListNode modifiedList(int[] nums, ListNode head) {
        if (head == null) return null;
        Set<Integer> set = new HashSet<>();
        for (int num : nums) {
            set.add(num);
        }
        ListNode newHead = head;
        while (newHead != null && set.contains(newHead.val)) newHead = newHead.next;
        if (newHead == null) return null;
        ListNode pre = newHead;
        while (pre.next != null) {
            ListNode now = pre.next;
            if (set.contains(now.val)) {
                pre.next = findNewNextNode(set, now);
                if (pre.next != null) pre = pre.next;
                continue;
            }
            pre = now;
        }
        return newHead;
    }

    private ListNode findNewNextNode(Set<Integer> set, ListNode now) {
        ListNode ans = now;
        while (set.contains(ans.val)) {
            ans = ans.next;
            if (ans == null) break;
        }
        return ans;
    }
}

100361. 切蛋糕的最小總開銷 I

有一個 m x n 大小的矩形蛋糕,需要切成 1 x 1 的小塊。

給你整數 mn 和兩個陣列:

  • horizontalCut 的大小為 m - 1 ,其中 horizontalCut[i] 表示沿著水平線 i 切蛋糕的開銷。
  • verticalCut 的大小為 n - 1 ,其中 verticalCut[j] 表示沿著垂直線 j 切蛋糕的開銷。

一次操作中,你可以選擇任意不是 1 x 1 大小的矩形蛋糕並執行以下操作之一:

  1. 沿著水平線 i 切開蛋糕,開銷為 horizontalCut[i]
  2. 沿著垂直線 j 切開蛋糕,開銷為 verticalCut[j]

每次操作後,這塊蛋糕都被切成兩個獨立的小蛋糕。

每次操作的開銷都為最開始對應切割線的開銷,並且不會改變。

請你返回將蛋糕全部切成 1 x 1 的蛋糕塊的 最小 總開銷。

思路

  當你橫著切一刀時,豎著切時都要加一刀,豎著切同理,所以我們想每次切大的花費的邊,這樣就不會重複切多次。把橫邊和豎邊降序排序,維護兩個多切係數,每次選擇橫邊和豎邊較大的那邊來切,同時維護多切係數,橫的切一刀,豎邊的多切係數就要+1,反之同理

import java.util.Arrays;

class Solution {
    public static int minimumCost(int m, int n, int[] horizontalCut, int[] verticalCut) {
        int cos = 0;
        int horizonNum = 1, verticalNum = 1;
        reverseOrderQuickSort(horizontalCut, 0, horizontalCut.length - 1);
        reverseOrderQuickSort(verticalCut, 0, verticalCut.length - 1);
        int i = 0, j = 0;
        while (i < horizontalCut.length || j < verticalCut.length) {
            if (i == horizontalCut.length) {
                cos += verticalCut[j] * verticalNum;
                j++;
                continue;
            }
            if (j == verticalCut.length) {
                cos += horizontalCut[i] * horizonNum;
                i++;
                continue;
            }
            if (horizontalCut[i] > verticalCut[j]) {
                cos += horizontalCut[i] * horizonNum;
                verticalNum++;
                i++;
            } else {
                cos += verticalCut[j] * verticalNum;
                horizonNum++;
                j++;
            }
        }
        return cos;
    }

    private static void reverseOrderQuickSort(int[] num, int left, int right) {
        if (left < right) {
            int i = left, j = right, n = num[left];
            while (i < j) {
                while (i < j && num[j] <= n) j--;
                if (i < j) num[i++] = num[j];
                while (i < j && num[i] > n) i++;
                if (i < j) num[j--] = num[i];
            }
            num[i] = n;
            reverseOrderQuickSort(num, left, i - 1);
            reverseOrderQuickSort(num, i + 1, right);
        }
    }
}

100367. 切蛋糕的最小總開銷 II

  題意和剛剛一樣,在剛剛的基礎上增大n和m的資料量

思路

  和第三題是一樣的,我的解法tle了,時間複雜度應該是一樣的,問題應該是手寫的快排沒有jdk的速度快,用jdk的api就能AC

import java.util.Arrays;

class Solution {
    public long minimumCost(int m, int n, int[] horizontalCut, int[] verticalCut) {
        long cos = 0;
        int horizonNum = 1, verticalNum = 1;
        Arrays.sort(horizontalCut);
        Arrays.sort(verticalCut);
        int i = horizontalCut.length - 1, j = verticalCut.length - 1;
        while (i >= 0 || j >= 0) {
            if (j < 0 || i >= 0 && horizontalCut[i] > verticalCut[j]) {
                cos += (long) horizontalCut[i] * horizonNum;
                verticalNum++;
                i--;
            } else {
                cos += (long) verticalCut[j] * verticalNum;
                horizonNum++;
                j--;
            }
        }
        return cos;
    }
}

相關文章