1. 程式人生 > 其它 >LeetCode Weekly Contest 288

LeetCode Weekly Contest 288

題目1 按奇偶性交換後的最大數字

題目正文

給你一個正整數 num 。你可以交換 num 中 奇偶性 相同的任意兩位數字(即,都是奇數或者偶數)。

返回交換 任意 次之後 num 的 最大 可能值。

示例 1:

輸入:num = 1234
輸出:3412
解釋:交換數字 3 和數字 1 ,結果得到 3214 。
交換數字 2 和數字 4 ,結果得到 3412 。
注意,可能存在其他交換序列,但是可以證明 3412 是最大可能值。
注意,不能交換數字 4 和數字 1 ,因為它們奇偶性不同。

示例 2:

輸入:num = 65875
輸出:87655
解釋:交換數字 8 和數字 6 ,結果得到 85675 。
交換數字 5 和數字 7 ,結果得到 87655 。
注意,可能存在其他交換序列,但是可以證明 87655 是最大可能值。

提示:

1 <= num <= 10^9

思路

求最大的數,很顯然就是要將滿足條件的數按倒序排列出來。利用桶的思想將所有數字剝離下來,遍歷陣列的時候從大到小取對應的奇數或者偶數就好。

AC程式碼

點選檢視程式碼
class Solution {
    public int largestInteger(int num) {
        int[] nums = new int[10];
        char[] chars = String.valueOf(num).toCharArray();
        int len = chars.length;
        for(char ch: chars) {
            int a = Integer.parseInt(ch+"");
            nums[a] ++;
        }
        int res = 0;
        for(char ch: chars) {
            int a = Integer.parseInt(ch+"");
            if( a%2==0 ) {
                for(int i=8; i>=0; i-=2 ) {
                    if( nums[i]>0 ) {
                        res = res*10 + i;
                        nums[i] --;
                        break;
                    }
                }
            } else {
                for(int i=9; i>=1; i-=2 ) {
                    if( nums[i]>0 ) {
                        res = res*10 + i;
                        nums[i] --;
                        break;
                    }
                }
            }
        }
        return res;
    }
}

題目2 向表示式新增括號後的最小結果

題目正文

給你一個下標從 0 開始的字串 expression ,格式為 "+" ,其中 表示正整數。

請你向 expression 中新增一對括號,使得在新增之後, expression 仍然是一個有效的數學表示式,並且計算後可以得到 最小 可能值。左括號 必須 新增在 '+' 的左側,而右括號必須新增在 '+' 的右側。

返回新增一對括號後形成的表示式 expression ,且滿足 expression 計算得到 最小 可能值。如果存在多個答案都能產生相同結果,返回任意一個答案。

生成的輸入滿足:expression 的原始值和新增滿足要求的任一對括號之後 expression 的值,都符合 32-bit 帶符號整數範圍。

示例 1:

輸入:expression = "247+38"
輸出:"2(47+38)"
解釋:表示式計算得到 2 * (47 + 38) = 2 * 85 = 170 。
注意 "2(4)7+38" 不是有效的結果,因為右括號必須新增在 '+' 的右側。
可以證明 170 是最小可能值。

示例 2:

輸入:expression = "12+34"
輸出:"1(2+3)4"
解釋:表示式計算得到 1 * (2 + 3) * 4 = 1 * 5 * 4 = 20 。

示例 3:

輸入:expression = "999+999"
輸出:"(999+999)"
解釋:表示式計算得到 999 + 999 = 1998 。

提示:

3 <= expression.length <= 10
expression 僅由數字 '1' 到 '9' 和 '+' 組成
expression 由數字開始和結束
expression 恰好僅含有一個 '+'.
expression 的原始值和新增滿足要求的任一對括號之後 expression 的值,都符合 32-bit 帶符號整數範圍

解題思路

題目意思很明確,就是要將一個加號表示式調整為帶括號的表示式,也就是下面這種形式的表示式
a1(a2+b1)b2 [a1、b2可不存在 a2、b1必須有值]
調整後的算術表示式的結果要最小。可以看到資料不算大,可以直接模擬。將表示式分成兩個部分後,用兩個for迴圈對括號所有可能出現的位置進行模擬,最後就可以得到最小的結果。在競賽過程我是將其轉成數字之和再進行操作,實際上是不需要轉的,可以直接用字串去取值,轉化成數字之和,處理更加麻煩了。

AC程式碼

點選檢視程式碼
class Solution {
    private String turnString(long a1, long a2, long b1, long b2) {
        StringBuffer res = new StringBuffer();
        if( a1 == 0) {
            res.append("(");
        } else {
            res.append(a1).append("(");
        }
        res.append(a2).append("+").append(b1);
        if( b2==0 ) {
            res.append(")");
        } else {
            res.append(")").append(b2);
        }
        return res.toString();
    }
    
    private long calc(long a1, long a2, long b1, long b2) {
        if( a2==0 || b1==0 ) {
            // 非法位置
            return Long.MAX_VALUE;
        }
        long sum = a2+b1;
        if( a1!=0 ) {
            sum *= a1;
        }
        if( b2!=0 ) {
            sum *= b2;
        }
        return sum;
    }
    
    private long resve(long num) {
        long res = 0;
        while(num!=0) {
            res = res*10 + num%10;
            num /= 10;
        }
        return res;
    }
    
    public String minimizeResult(String expression) {
        String[] strs = expression.split("\\+");
        long a = Long.parseLong(strs[0]);
        long b = Long.parseLong(strs[1]);
        long res = a + b;
        long a1 = 0;
        long a2 = 0;
        long a22 = 0;
        long resA1 = 0;
        long resA2 = a;
        long resB2 = 0;
        long resB1 = b;
        while(a!=0) {
            a1 = a/10;
            a22 = a22*10+a%10;
            a2 = resve(a22);
            a = a/10;
            long b1 = b;
            long b22 = 0;
            while(b1!=0 ) {
                long b2 = resve(b22);
                long tempRes = calc(a1, a2, b1, b2);
                if( tempRes < res ) {
                    res = tempRes;
                    resA1 = a1;
                    resA2 = a2;
                    resB2 = b2;
                    resB1 = b1;
                }
                b22 = b22*10 + b1%10;
                b1 /= 10;
            }
        }
        return turnString(resA1, resA2, resB1, resB2);
    }
}

題目3 K次增加後的最大乘積

題目正文

解題思路

給你一個非負整數陣列 nums 和一個整數 k 。每次操作,你可以選擇 nums 中 任一 元素並將它 增加 1 。

請你返回 至多 k 次操作後,能得到的 nums的 最大乘積 。由於答案可能很大,請你將答案對 10^9 + 7 取餘後返回。

示例 1:

輸入:nums = [0,4], k = 5
輸出:20
解釋:將第一個數增加 5 次。
得到 nums = [5, 4] ,乘積為 5 * 4 = 20 。
可以證明 20 是能得到的最大乘積,所以我們返回 20 。
存在其他增加 nums 的方法,也能得到最大乘積。

示例 2:

輸入:nums = [6,3,3,2], k = 2
輸出:216
解釋:將第二個數增加 1 次,將第四個數增加 1 次。
得到 nums = [6, 4, 3, 3] ,乘積為 6 * 4 * 3 * 3 = 216 。
可以證明 216 是能得到的最大乘積,所以我們返回 216 。
存在其他增加 nums 的方法,也能得到最大乘積。

提示:

1 <= nums.length, k <= 10^5
0 <= nums[i] <= 10^6

解題思路

很簡單的貪心思想,對於所有數字的乘積,每次對位置i的數字加一操作,該次操作對新陣列的乘積帶來的新增貢獻為:除了i位置以外其他所有數之積,所以每次加1的操作必然是對最小的數進行的。
競賽中我是利用桶的思想,將所有數字都存下來,然後從小到大去模擬加1的操作,由於桶是天然排好序的,所以每次加1的操作都是滿足貪心思想,但是桶的話要注意桶的範圍。因為有向上加的操作,所以會出現邊界的問題。
另外這個題目是可以直接用優先佇列去做的,優先佇列的隊頭永遠是最小的,每次對隊頭進行操作即可,這樣程式碼應該是最少的。

AC程式碼

點選檢視程式碼
class Solution {
    public int maximumProduct(int[] nums, int k) {
        int maxLen = 2000005;
        int mod = 1000000000+7;
        int[] arr = new int[maxLen];
        for(int num: nums) {
            arr[num] ++;
        }
        for(int i=0; i<maxLen; i++) {
            if( k == 0 ) {
                break;
            }
            while(arr[i]>0 && k>0) {
                arr[i+1] ++;
                arr[i] --;
                k --;
            }
        }
        long res = 1;
        for(int i=0; i<maxLen; i++) {
            while( arr[i]>0 ) {
                arr[i] --;
                res = ((long)(res%mod)*(i%mod))%mod;
            }
        }
        return (int) res;
    }
}