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;
}
}