笔试复盘(3.6)
题目一
题目描述
小团最近在玩手机上的四川麻将。四川麻将的一种玩法是玩家摸完牌之后选择三张花色一样的牌按某种顺序换给其他人。为了尽可能破坏对手的游戏体验,小团每次都会选择不连续的三张牌换出去。比如小团手上有14568这5张条子,则他可能会选择158这三张条子换出去。爱思考的小团马上对这个问题进行了推广。
小团把这个问题进行了简化,现在他给了你一个可重集合,并希望你从中选出一个尽可能大的子集使得其中没有两个数是“连续”的(连续是指即这两个数之差的绝对值不超过1)。
输入描述
第一行有一个整数n(1<=n<=100000),代表小团给你的可重集大小。
第二行有n个空格隔开的整数(范围在1到200000之间),代表小团给你的可重集。
输出描述
输出满足条件的最大子集的大小。
样例输入
6
1 2 3 5 6 7
样例输出
4
思路:
简单理解题意,从给出的数字序列中得到一串不连续的数字序列,使序列中含元素尽可能多,如样例1 3 5 7便是最大的不连续数字序列。
由于给出的序列至少有一位数字,则第一个元素可以直接拿取,可以设置一个整型变量 pre 代表上一个拿取的元素,初始化为给出序列的第一个元素。
后续的序列贪心拿取即可,贪心拿取需要保证序列为有序。所以遍历前需要进行一次排序。
从第二个元素开始遍历所给序列,若与pre差值大于1,则更换pre值,继续选取下一个可选数字即可。
class Solution1{
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n;
n= sc.nextInt();
int[] arr=new int[n];
Arrays.sort(arr);
for(int i=0;i<n;i++) arr[i]=sc.nextInt();
int ans=1;
int pre=arr[0];
for(int i=1;i<arr.length;i++){
int dex=arr[i]-pre;
if(dex>1){
ans++;
pre=arr[i];
}
}
System.out.println(ans);
}
}
题目二
题目描述
最大子段和是一个经典问题,即对于一个数组找出其和最大的子数组。
现在允许你在求解该问题之前翻转这个数组的连续一段(如翻转{1,2,3,4,5,6}的第三个到第五个元素组成的子数组得到的是{1,2,5,4,3,6}),则翻转后该数组的最大子段和最大能达到多少?
输入描述
第一行有一个正整数n(1<=n<=100000),代表数组长度。
第二行有n个空格隔开的整数(-1000<=ai<=1000),代表给出数组。
输出描述
输出一个整数,代表若允许你翻转一个子数组 ,则翻转后所得数组的最大子段和最大能到多少。
样例输入
6
-1 3 -5 2 -1 3
样例输出
7
思路:
解决一下如何求一个序列的最大子段和,力扣有最大子段和求解方式,可以利用动态规划解决。
状态表示为dp[i],表示以下标为i的元素结尾的序列的最大字段的和。
这样的话,最后只需要求出dp[0]~dp[n]中最大的值就是最大子段和了。
状态转移方程:
令给出的序列为a[0]~a[i],a[i]只有两种情况,与以a[i-1]结尾的最大子段结合;只保留自己,单独构成字段
若dp[i-1]<0,则a[i]自身构成字段显然字段和更大,dp[i]=a[i];反之dp[i]=dp[i-1]+a[i]
但是翻转位置的选择呢,我们枚举翻转位置即可,时间复杂度O(N*N)
源码如下:
class Solution22{
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt();
int[] nums=new int[n];
for(int i=0;i<n