数据结构与算法比赛:力扣周赛288

https://leetcode-cn.com/contest/weekly-contest-288/

文章目录

  • 2231. 按奇偶性交换后的最大数字
  • 2232. 向表达式添加括号后的最小结果
    • Java String indexOf() 方法
    • Java substring() 方法
  • 2233. K 次增加后的最大乘积
  • 2234. 花园的最大总美丽值

2231. 按奇偶性交换后的最大数字

  1. 每个数和后面数判断是否同为奇同为偶,可以直接两个数相加看是否为奇数,因为奇偶性相同的两个数相加一定是偶数,奇偶数不同的两个数相加一定是奇数!字符直接对应着ascii码,不必再减去’0’转成数字
  2. 每次往后遍历只需要找到最大的数,和最大的数做一次交换即可!
  3. num先转String再转char数组,随后输出char数组通过Integer.parseInt(new String(chs))转回num
	/*
	 * 1、每个数和后面数判断是否同为奇同为偶,可以直接两个数相加看是否为奇数,
	 * 		因为奇偶性相同的两个数相加一定是偶数,奇偶数不同的两个数相加一定是奇数!
	 * 		字符直接对应着ascii码,不必再减去'0'转成数字;
	 * 2、每次往后遍历只需要找到最大的数,和最大的数做一次交换即可!
	 * 
	 * 执行用时:1 ms, 在所有 Java 提交中击败了93.38%的用户
	 * 内存消耗:38.5 MB, 在所有 Java 提交中击败了46.16%的用户
	 */
	public int largestInteger(int num) {
		//首先吧num转换成String再转换成char型数组
		String s = String.valueOf(num);
        char[] chs = s.toCharArray();
        
        for(int i=0; i<s.length(); i++){
        	int maxIdx = i;//最大的数的index
        	for(int j=s.length()-1; j>=i; j--){
        		//奇偶性相同的两个数的差的取2模为0
        		if(((chs[i] - '0' + chs[j] - '0') % 2 == 0)){
        			if(chs[j] > chs[maxIdx]){
                        maxIdx = j;
                    }       			
        		}
        	}
        	
            if(maxIdx != i){
                char temp = chs[i];
                chs[i] = chs[maxIdx];
                chs[maxIdx] = temp;
            }
        }
        
        return Integer.parseInt(new String(chs));
	}

比赛时代码:

  1. 尝试把num先转换成num[]
  2. 设置了两组双指针,一组奇,一组偶数
	/*
	 * 两对双指针,一对排奇,一对排偶
	 */
	public int largestInteger1(int num) {
		int[] nums = change(num);
        
		int len = nums.length;
		int oddl = 0; 
		int oddr = len-1;
		int evenl = 0;
		int evenr = len-1;
		
		while(oddl < oddr){
			if(nums[oddl]%2 == 1 && nums[oddr]%2 == 1){//两个指针都找到了奇数
				
			}
		}
		
		
        return 1;
	}
	
	//将int转换为int[]
	public int[] change(int num){
		int temp = num;//输入的整数
		int wei = 0;//几位数
		ArrayList<Integer> list = new ArrayList<Integer>();
		//算出位数
        while(temp!=0){
               temp = temp/10;
               wei++;
        }
        //创建一个和整数位数相同大小的数组
        int[] element = new int[wei];
        int tmp = num;
        for(int i = wei;i>0;i--){
        	//从高位到低位依次取数字
            int m1 = (new Double(Math.pow(10,i-1))).intValue();
            tmp = (num/m1)%10;
            element[wei-i] = tmp;
        }
        return element;
	}

2232. 向表达式添加括号后的最小结果

参考计算器
https://leetcode-cn.com/problems/minimize-result-by-adding-parentheses-to-expression/

	int addIndex = expression.indexOf('+');
        int len = expression.length();
        int min = Integer.MAX_VALUE;
        int[] pair = new int[2];
        // 以addIndex为分界线两边进行分割
        for (int i = 0; i < addIndex; i++) {//加号前的num
            for (int j = addIndex + 2; j <= len; j++) {//加号后的num
                String s1 = expression.substring(0, i);
                int num1 = "".equals(s1) ? 1 : Integer.parseInt(s1);
                
                String s2 = expression.substring(i, addIndex);
                int num2 = Integer.parseInt(s2);
                
                String s3 = expression.substring(addIndex + 1, j);
                int num3 = Integer.parseInt(s3);
                
                String s4 = expression.substring(j, len);
                int num4 = "".equals(s4) ? 1 : Integer.parseInt(s4);
                
                int num = num1 * (num2 + num3) * num4;
                if (num < min) {
                    pair = new int[]{i, j};
                    min = num;
                }
            }
        }
        StringBuilder sb = new StringBuilder(expression);
        sb.insert(pair[0], '(');
        sb.insert(pair[1] + 1, ')');
        return sb.toString();

Java String indexOf() 方法

public class Main {
    public static void main(String args[]) {
        String string = "aaa456ac";  
        //查找指定字符是在字符串中的下标。在则返回所在字符串下标;不在则返回-1.  
        System.out.println(string.indexOf("b")); // indexOf(String str); 返回结果:-1,"b"不存在  
 
        // 从第四个字符位置开始往后继续查找,包含当前位置  
        System.out.println(string.indexOf("a",3));//indexOf(String str, int fromIndex); 返回结果:6  
 
        //(与之前的差别:上面的参数是 String 类型,下面的参数是 int 类型)参考数据:a-97,b-98,c-99  
 
        // 从头开始查找是否存在指定的字符  
        System.out.println(string.indexOf(99));//indexOf(int ch);返回结果:7  
        System.out.println(string.indexOf('c'));//indexOf(int ch);返回结果:7  
 
        //从fromIndex查找ch,这个是字符型变量,不是字符串。字符a对应的数字就是97。  
        System.out.println(string.indexOf(97,3));//indexOf(int ch, int fromIndex); 返回结果:6  
        System.out.println(string.indexOf('a',3));//indexOf(int ch, int fromIndex); 返回结果:6  
    }
}

Java substring() 方法

public class RunoobTest {
    public static void main(String args[]) {
        String Str = new String("This is text");
 
        System.out.print("返回值 :" );
        System.out.println(Str.substring(4) );
 
        System.out.print("返回值 :" );
        System.out.println(Str.substring(4, 10) );
    }
}

返回值 : is text
返回值 : is te

2233. K 次增加后的最大乘积

https://leetcode-cn.com/problems/maximum-product-after-k-increments/
贪心+优先队列

	/*
	 * 1.把所有起始数字放进一个最小堆优先队列。
	 * 2.进行k次操作,每次取出队列中最小值,并对其进行加一操作,再放回队列。
	 * 3.最后把队列中所有数字相乘就是答案了(注意步步取余防止溢出,证明(a+b)%c = (a%c+b%c)%c)。
	 * 
	 * 执行用时:196 ms, 在所有 Java 提交中击败了81.96%的用户
	 * 内存消耗:52.4 MB, 在所有 Java 提交中击败了32.28%的用户
	 */
	public int maximumProduct(int[] nums, int k) {
		PriorityQueue<Integer> pq = new PriorityQueue<>();
        for (int num : nums){
            pq.offer(num);
        }
        for (int i = 0; i < k; i++){
            int num = pq.poll();
            num += 1;
            pq.offer(num);
        }
        long ans = 1;
        long MOD = 1000000007;
        for (int num : pq){
            ans = (num * ans) % MOD;
        }
        return (int)ans;
	}

比赛时代码:

  1. 动态规划
  2. dp[i][j]:第j次加1时,加到第i个数上的乘积
  3. 每次计算完一行后,对比乘积最大的i,并记录
	/*
	 * 8 / 73 个通过测试用例
	 */
	public int maximumProduct1(int[] nums, int k) {
		int len = nums.length;
		long MOD = 1000000007;
		int[][] dp = new int[k][len];
		
		int addindex = 0;
		int tosum = 0;//当前行最大乘积
		
		for(int j=0; j<k; j++){
			addindex = 0;
			tosum = 0;//当前行最大乘积
			for(int i=0; i<nums.length; i++){
				nums[i] += 1;
				dp[j][i] = cheng(nums, MOD);
				
				if(dp[j][i] > tosum) {
					tosum = dp[j][i];
					addindex = i;
				}
				nums[i] -= 1;
			}	
			nums[addindex]++;
			show1(nums);
		}
	
		return (int) (tosum%MOD);
	}
	
	public int cheng(int[] nums, long MOD){
		int res = nums[0];		
		for(int i=1; i<nums.length; i++) {
			//System.out.print("当前res为:" + res + ",当前");
			res = (int) ((res*nums[i])%MOD);
		}
		return res;
	}

2234. 花园的最大总美丽值

https://leetcode-cn.com/problems/maximum-total-beauty-of-the-gardens/

//核心思路:
//1.如果要填充完善花园,一定是优先填种花数最多的花园,因此容易想到排序数组,然后逆序遍历进行填充
//2.如果不填充为完善花园,那就要使得所有不完善花园种花数的最小值最大
//3.But,填还是不填我们并不知道,需要根据full和partial的值确定,不过这个分类讨论就太细了没法做。因此!填和不填两种情况的美丽值我们都算出来,取最大值就行了!
//4.根据上述三点,我们可以逆序遍历数组,对于每个花园,我们分别计算不填充为完善花园(当前花园和之前花园都不填充)的美丽值,以及当前花园填充为完善花园,然后继续循环,在下一个花园上走相同逻辑!

//详细步骤见代码注释
//注意,newFlowers表示最大可种新花数目,即种的新花数目也可以小于newFlowers,甚至可以不种新花
class Solution {
    public long maximumBeauty(int[] flowers, long newFlowers, int target, int full, int partial) {
        //升序
        Arrays.sort(flowers);
        int n = flowers.length;
        //种花最少的花园已经达到了target,可直接返回结果
        if (flowers[0] >= target) return (long)n * full;

        //前缀和,sum[i]表示前i个花园累积已经种花的数量,这个仅仅用于后续的一步计算,不是重点
        long[] sum = new long[n];
        sum[0] = flowers[0];
        for (int i = 1; i < n; i++){
            sum[i] = sum[i - 1] + flowers[i];
        }

        //保存最终结果
        long ans = 0;
        
        //逆序遍历,优先把种花数多的花园,填满至target
        for (int i = n - 1; i >= 0; i--) {
            //当前花园种花数已经>=target,不处理
            if (flowers[i] >= target) continue;

            //当前花园种花数 < target时,此时有两种选择:
            //1.当前花园以及前面花园都不填充为完善花园,使得当前花园以及前面花园种花数的最小值最大!(例如partial远大于full的情况,此时把新种花指标用在增大不完善花园的最小值上对结果增益更大,但要牢牢记住这些花园都不能填充为完善花园)
            //2.当前花园填充成完善花园,再继续循环处理前面花园的情况(例如full比较大的情况,此时把新种花指标用在凑完善花园上对结果增益更大)

            //针对1,要使得当前花园以及前面花园都不能填充为完善花园,则这些花园的种花数范围必定在[flowers[0], target - 1]内,flowers[0]是种花数最小的花园,题目也说了已经种了的花不能移走,因此左边界是flowers[0]
            //那么新花种完以后,这些花园的种花数最小值必定在这个范围内,如此转化为:在一个递增区间内,找最后一个满足xxx条件的数minVal,典型二分查找问题。(因为要尽可能使这个最小值最大嘛,所以要找最后一个满足条件的!!)
            //而这个xxx条件就是指,能否用newFlowers把当前花园以及前面花园种花数小于minVal的全都填满到minVal
            long l = flowers[0], r = target - 1;
            while (l < r) {
                long mid = (r - l + 1) / 2 + l;
                if (check(flowers, sum, newFlowers, mid, i)) {
                    l = mid;
                } else {
                    r = mid - 1;
                }
            }
            //这里计算了选择1情况下的美丽值,并更新全局最大美丽值
            ans = Math.max(ans, (n - i - 1) * (long)full + l * partial);

            //继续走选择2,继续循环
            newFlowers -= target - flowers[i];

            //注意,如果newFlowers不足以把当前花园填充为美丽花园,那说明只能走选择1了,而且后续的花园都不能填充了
            //直接结束,返回ans!
            if (newFlowers < 0) return ans;
        }
        //循环能走出来,说明全部花园都可以填充为完善花园
        //处理边界情况,也就是全部花园都填成完善花园的情况,上面循环中最后这次少计算了
        if (newFlowers >= 0) return Math.max(ans, (long)full * n);
        return ans;
    }

    //能否用newFlowers把flowers[0, idx]中小于num的花园都填满到minVal
    public boolean check(int[] flowers, long[] sum, long newFlowers, long minVal, int idx) {
        int l = 0, r = idx;
        //既然要填满所有小于minVal的元素,那就要找最后一个小于minVal的元素,继续二分!
        while (l < r) {
            int mid = l + r + 1 >> 1;
            if (flowers[mid] < minVal) {
                l = mid;
            } else {
                r = mid - 1;
            }
        }
        //此时flowers[0,l]都是小于minVal的,计算一下填满它们需要的花数量
        long diff = minVal * (l + 1) - sum[l];
        //如果newFlowers够填,返回true;不够,返回false
        return newFlowers >= diff;
    }
}

你可能感兴趣的:(数据结构与算法比赛,#,力扣周赛,数据结构,算法)