文章目录
- [1. 重排字符串](#1. 重排字符串)
- [2. 分组](#2. 分组)
- [3. DNA序列](#3. DNA序列)
1. 重排字符串
题目描述

解题思路
贪心+构造
每次处理相同的字符,优先处理出现次数最多的字符
- 先统计所有字母的出现次数,并记录最大次数,最大次数决定了这个字符串能否重排
- 让次数最多之外的字符间隔一个空排列,当把偶数格子排列完,剩余奇数格子天然就是不相邻的。

- 能否重排:
maxcnt>(n+1)/2时,不可以重排.
代码实现
java
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
in.nextLine();
String str = in.nextLine();
char[] ss = str.toCharArray();
int[] arr = new int[26];
int max = 0;
char maxchar = '0';
for (int i = 0; i < n; i++) {
arr[ss[i] - 'a']++;
if (arr[ss[i] - 'a'] > max) {
max = arr[ss[i] - 'a'];
maxchar = ss[i];
}
}
if (max > (n + 1) / 2) {
System.out.println("no");
return;
} else {
System.out.println("yes");
char[] ans = new char[n];
//先处理次数最多的字符
int i = 0;
while(max-- >0){
ans[i]=maxchar;
i+=2;
}
for (int j = 0; j < 26; j++) {
if(arr[j]>0 && (char)(j+'a')!=maxchar){
while(arr[j]-- >0){
if(i>=n)
i=1;
ans[i] = (char)(j+'a');
i+=2;
}
}
}
for(int j = 0;j<n;j++)
System.out.print(ans[j]);
}
}
}
2. 分组
题目描述

解题思路
暴力枚举 -> 二分查找
- 利用哈希表统计每一声部的人数
- 枚举最终的分配结果中,小组中最多的人数。
- x表示小组最多的人数。计算对于每个声部按x分组会有多少组,统计m1+m2+...总和是否小于等于m。
- 找到哈希表中最大的value,枚举的范围就是[1,hmax],从1开始枚举,直到找到一个数可以满足check条件。
优化:二分查找
可以把对[1,hmax]的枚举优化为二分查找:[1,ret-1] check(x)>m [ret,right] check(x)<=m
- 如果
check(mid)为假,则证明当前的x太小,应该把left更新为mid+1 - 如果
check(mid)为真,证明当前的x符合条件,但不一定是最小的,right更新为mid
代码实现
- 暴力枚举
java
import java.util.*;
public class Main{
static HashMap<Integer,Integer> hash = new HashMap<>();
static int m,n;
public static void main(String[] args){
Scanner in = new Scanner(System.in);
n = in.nextInt();
m = in.nextInt();
int[] a = new int[n];
int hmax = 0;
for(int i = 0;i<n;i++){
a[i] = in.nextInt();
if(!hash.containsKey(a[i]))
hash.put(a[i],0);
hash.put(a[i],hash.get(a[i])+1);
hmax = Math.max(hmax,hash.get(a[i]));
}
for(int i = 1;i<=hmax;i++){
if(check(i)){
System.out.println(i);
return;
}
}
System.out.println(-1);
}
//判断最多人数为x时能否被分成x组
static boolean check(int x){
int g = 0;//统计能分成多少组
for(int a:hash.values()){
g += a/x + ((a%x==0)?0:1);
}
return g<=m;
}
}
- 二分查找
java
import java.util.*;
public class Main{
static HashMap<Integer,Integer> hash = new HashMap<>();
static int m,n;
public static void main(String[] args){
Scanner in = new Scanner(System.in);
n = in.nextInt();
m = in.nextInt();
int[] a = new int[n];
int hmax = 0;
for(int i = 0;i<n;i++){
a[i] = in.nextInt();
if(!hash.containsKey(a[i]))
hash.put(a[i],0);
hash.put(a[i],hash.get(a[i])+1);
hmax = Math.max(hmax,hash.get(a[i]));
}
int left = 1;
int right = hmax;
while(left<right){
int mid = (right-left)/2+left;
if(check(mid))
right = mid;
else
left = mid+1;
}
if(check(left))
System.out.println(left);
else
System.out.println(-1);
}
//判断最多人数为x时能否被分成x组
static boolean check(int x){
int g = 0;//统计能分成多少组
for(int a:hash.values()){
g += a/x + ((a%x==0)?0:1);
}
return g<=m;
}
}
3. DNA序列
题目描述

解题思路
滑动窗口
字串长度固定为5,所以两个指针同时向右运动,可以用滑动窗口。
代码实现
java
import java.util.Scanner;
// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String str = in.nextLine();
int len = in.nextInt();
char[] ss = str.toCharArray();
int n = ss.length;
String ans = " ";
int l = 0;
int r = 0;
int count = 0;
int max = 0;
while(r<n){
if(ss[r]=='C' || ss[r]=='G')
count++;
while(r-l+1>len){
if(ss[l]=='C' || ss[l] == 'G')
count--;
l++;
}
if(r-l+1==len && count>max){
max = count;
ans = str.substring(l,r+1);
}
r++;
}
System.out.println(ans);
}
}