算法训练#18:简单题再训练(贪心和分类讨论)

21 阅读2分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 21 天,点击查看活动详情

第一题

Cherry

题目理解

给出一个含有nn个整数的数组,要求在该数组找出一个区间(也就是数组中一个连续的子数组),该区间中的最小值与最大值的乘积大于其他区间的该乘积

输入

输入整数tt,代表案例个数,1t1031\le t\le 10^{3}
每个案例第1行输入1个整数nn2n1052\le n\le 10^{5}
每个案例的第二行输入nn个整数

输出

每个案例输出一个整数——代表找出的最大的乘积

思路

如果是单纯的划分区间,找区间中的最大值最小值然后相乘,时间成本太高,那么我们可以换个思路想:区间的小或者大,对乘积有什么影响?我们先称数组中两个相邻的数为iijj,那么ii乘以jj必然就是该区间的答案。若此时区间增大,从右边加入一个数字kk,此时就会有以下情况:

  1. i<j<ki\lt j\lt k,则该区间乘积比原区间乘积大,且区间可以缩短为(j,k)
  2. k<i<jk\lt i\lt j,则该区间乘积比原区间乘积小,不能成为答案对应区间
  3. i<k<ji\lt k\lt j,则该区间乘积与原区间乘积相同,可以缩短为原区间

通过以上情况,我们可以推导出:区间长度增加且乘积变大的情况下也可以缩短为与原区间长度相同的新区间,所以我们可以干脆直接判断数组中所有两两相邻的数字的乘积的最大值来得到题目答案。

代码

import java.util.Scanner;

public class Cherry {
    public static void main(String args[]) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        for (int i = 0; i < t; i++) {
            int n=sc.nextInt();
            Long[] a= new Long[n];
            for(int j=0;j<n;j++) {
                a[j]=sc.nextLong();
            }
            Long ans=a[0]*a[1];
            for(int j=2;j<n;j++)
                ans=Math.max(ans,a[j]*a[j-1]);
            System.out.println(ans);
        }
    }
}

第二题

Mocha and Red and Blue

题目理解

给出一个长度为nn的数组,其中有三种值:?,B,R。其中我们需要把?置换成B或者R,以达到一个目的:尽量少的相邻字符相等。

输入

输入整数tt,代表案例个数,1t1021\le t\le 10^{2}
每个案例第1行输入1个整数nn1n1021\le n\le 10^{2}
每个案例的第二行输入一个字符串

输出

每个案例输出一个字符串——达到目的的字符串

思路代码


import java.util.Scanner;

public class mocha_and_red_and_blue {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        for (int i = 0; i < t; i++) {
            int n=sc.nextInt();
            String s=sc.next();
            char[] c=s.toCharArray();
            int mark=0;
            boolean f=false;
            //该题主要是靠分类讨论解决问题,所以用注释的方式讲解思路
            //先找到最后一个非问号字符所在的位置
            for(int i1=0;i1<n;i1++){
                if(c[i1]!='?'){
                    mark=i1;
                    f=true;
                    break;
                }
            }
            //判断是否全是问号
            if(f) {
            //分两段轮流赋值
                for (int i1 = mark + 1; i1 < n; i1++) {
                    if (c[i1] == '?') {
                        switch (c[i1 - 1]) {
                            case 'B':
                                c[i1] = 'R';
                                break;
                            case 'R':
                                c[i1] = 'B';
                                break;
                        }
                    }
                }
                for (int i1 = mark - 1; i1 >= 0; i1--) {
                    if (c[i1] == '?') {
                        switch (c[i1 + 1]) {
                            case 'B':
                                c[i1] = 'R';
                                break;
                            case 'R':
                                c[i1] = 'B';
                                break;
                        }
                    }
                }
            }
            else{
            //全是问号就轮流填入B、R就行
                c[0]='B';
                for (int i1 = mark + 1; i1 < n; i1++) {
                    if (c[i1] == '?') {
                        switch (c[i1 - 1]) {
                            case 'B':
                                c[i1] = 'R';
                                break;
                            case 'R':
                                c[i1] = 'B';
                                break;
                        }
                    }
                }
            }
            for(int i1=0;i1<n;i1++){
                System.out.print(c[i1]);
            }
            System.out.println();
        }
    }
}