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;
    }
}
posted @ 2022-04-10 13:36  Asimple  阅读(28)  评论(0编辑  收藏  举报