HJ24 合唱队
描述
计算最少出列多少位同学,使得剩下的同学排成合唱队形
说明:
N 位同学站成一排,音乐老师要请其中的 (N - K) 位同学出列,使得剩下的 K 位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为 1,2…,K ,他们的身高分别为 T1,T2,…,TK , 则他们的身高满足存在 i (1<=i<=K) 使得 T1<T2<......<Ti-1<Ti>Ti+1>......>TK 。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
注意:不允许改变队列元素的先后顺序 且 不要求最高同学左右人数必须相等
数据范围: 1 \le n \le 3000 \1≤n≤3000
输入描述:
用例两行数据,第一行是同学的总数 N ,第二行是 N 位同学的身高,以空格隔开
输出描述:
最少需要几位同学出列
示例1
输入:
8
186 186 150 200 160 130 197 200
复制
输出:
4
复制
说明:
由于不允许改变队列元素的先后顺序,所以最终剩下的队列应该为186 200 160 130或150 200 160 130
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = null;
while ((str = br.readLine()) != null) {
if (str.equals("")) continue;
int n = Integer.parseInt(str);
int[] heights = new int[n];
String[] str_heights = br.readLine().split(" ");
// 当仅有一个人时,其自己组成一个合唱队,出列0人
if (n <= 1) System.out.println(0);
else {
for (int i = 0; i < n; i++) heights[i] = Integer.parseInt(str_heights[i]);
// 记录从左向右的最长递增子序列和从右向左的最长递增子序列
int[] seq = new int[n], rev_seq = new int[n];
int[] k = new int[n]; // 用于记录以i为终点的从左向右和从右向走的子序列元素个数
seq[0] = heights[0]; // 初始化从左向右子序列首元素为第一个元素
int index = 1; // 记录当前子序列的长度
for (int i = 1; i < n; i++) {
if (heights[i] > seq[index-1]) { // 当当前元素大于递增序列最后一个元素时
k[i] = index; // 其左边元素个数
seq[index++] = heights[i]; // 更新递增序列
} else { // 当当前元素位于目前维护递增序列之间时
// 使用二分搜索找到其所属位置
int l = 0, r = index - 1;
while (l < r) {
int mid = l + (r - l) / 2;
if (seq[mid] < heights[i]) l = mid + 1;
else r = mid;
}
seq[l] = heights[i]; // 将所属位置值进行替换
k[i] = l; // 其左边元素个数
}
}
// 随后,再从右向左进行上述操作
rev_seq[0] = heights[n-1];
index = 1;
for (int i = n - 2; i >= 0; i--) {
if (heights[i] > rev_seq[index-1]) {
k[i] += index;
rev_seq[index++] = heights[i];
} else {
int l = 0, r = index - 1;
while (l < r) {
int mid = l + (r - l) / 2;
if (rev_seq[mid] < heights[i]) l = mid + 1;
else r = mid;
}
rev_seq[l] = heights[i];
k[i] += l;
}
}
int max = 1;
for (int num: k)
if (max < num) max = num;
// max+1为最大的k
System.out.println(n - max - 1);
}
}
}
}
HJ26 字符串排序
描述
编写一个程序,将输入字符串中的字符按如下规则排序。
规则 1 :英文字母从 A 到 Z 排列,不区分大小写。
如,输入: Type 输出: epTy
规则 2 :同一个英文字母的大小写同时存在时,按照输入顺序排列。
如,输入: BabA 输出: aABb
规则 3 :非英文字母的其它字符保持原来的位置。
如,输入: By?e 输出: Be?y
数据范围:输入的字符串长度满足 1 \le n \le 1000 \1≤n≤1000
输入描述:
输入字符串
输出描述:
输出字符串
示例1
输入:
A Famous Saying: Much Ado About Nothing (2012/8).
复制
输出:
A aaAAbc dFgghh: iimM nNn oooos Sttuuuy (2012/8).
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main{
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s;
while((s = br.readLine()) != null){
char[] ch = s.toCharArray();
char[] chars = new char[ch.length];
int flag = 65, j=0;
while(flag<=90){
for(int i=0; i<ch.length; i++){
if((ch[i]>=65&&ch[i]<=90) || (ch[i]>=97&&ch[i]<=122)){
if(ch[i]==flag || ch[i]== flag+32){
chars[j] = ch[i];
j++;
}
}
}
flag++;
}
j=0;
for(int i=0; i<ch.length; i++){
if((ch[i]>=65&&ch[i]<=90) || (ch[i]>=97&&ch[i]<=122)){
ch[i] = chars[j];
j++;
}
}
System.out.println(String.valueOf(ch));
}
}
}
HJ27 查找兄弟单词
描述
定义一个单词的“兄弟单词”为:交换该单词字母顺序(注:可以交换任意次),而不添加、删除、修改原有的字母就能生成的单词。
兄弟单词要求和原来的单词不同。例如: ab 和 ba 是兄弟单词。 ab 和 ab 则不是兄弟单词。
现在给定你 n 个单词,另外再给你一个单词 str ,让你寻找 str 的兄弟单词里,按字典序排列后的第 k 个单词是什么?
注意:字典中可能有重复单词。
数据范围:1 \le n \le 1000 \1≤n≤1000 ,输入的字符串长度满足 1 \le len(str) \le 10 \1≤len(str)≤10 , 1 \le k < n \1≤k<n
输入描述:
先输入单词的个数n,再输入n个单词。 再输入一个单词,为待查找的单词x 最后输入数字k
输出描述:
输出查找到x的兄弟单词的个数m 然后输出查找到的按照字典顺序排序后的第k个兄弟单词,没有符合第k个的话则不用输出。
示例1
输入:
3 abc bca cab abc 1
复制
输出:
2
bca
复制
示例2
输入:
6 cab ad abcd cba abc bca abc 1
复制
输出:
3
bca
复制
说明:
abc的兄弟单词有cab cba bca,所以输出3
经字典序排列后,变为bca cab cba,所以第1个字典序兄弟单词为bca
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
String s=null;
while((s=bf.readLine())!=null){
// 将输入的字符串分割成字符串数组
String[] words=s.split(" ");
// 待查找单词
String str=words[words.length-2];
// 兄弟单词表里的第k个兄弟单词
int k=Integer.parseInt(words[words.length-1]);
// 存放兄弟单词表
ArrayList<String> broWords=new ArrayList<>();
// 遍历输入的单词
for (int i = 1; i < words.length-2; i++) {
// 不相等且长度相同
if((!words[i].equals(str)) && words[i].length()==str.length()) {
char[] chStr=str.toCharArray();
char[] word=words[i].toCharArray();
int temp=0;
for (int j = 0; j < chStr.length; j++) {
for (int j2 = 0; j2 < word.length; j2++) {
if (word[j]==chStr[j2]) {
chStr[j2]='0';
temp++;
break;
}
}
}
if (temp==chStr.length) {
broWords.add(words[i]);
}
}
}
System.out.println(broWords.size());
if(k>0 && k<=broWords.size()) {
Collections.sort(broWords);
System.out.println(broWords.get(k-1));
}
}
}
}
HJ29 字符串加解密
描述
1、对输入的字符串进行加解密,并输出。
2、加密方法为:
当内容是英文字母时则用该英文字母的后一个字母替换,同时字母变换大小写,如字母a时则替换为B;字母Z时则替换为a;
当内容是数字时则把该数字加1,如0替换1,1替换2,9替换0;
其他字符不做变化。
3、解密方法为加密的逆过程。
数据范围:输入的两个字符串长度满足 1 \le n \le 1000 \1≤n≤1000 ,保证输入的字符串都是大小写字母或者数字
输入描述:
输入说明
输入一串要加密的密码
输入一串加过密的密码
输出描述:
输出说明
输出加密后的字符
输出解密后的字符
示例1
输入:
abcdefg
BCDEFGH
复制
输出:
BCDEFGH
abcdefg
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Scanner;
public class Main{
public static void main(String []args) throws Exception{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
String str="";
while((str=br.readLine())!=null) {
String word=br.readLine();
System.out.println(jiami(str));
System.out.println(jiemi(word));
}
}
public static String jiami(String str) {
char ch[]=str.toCharArray();
StringBuilder sb=new StringBuilder();
for(int i=0;i<ch.length;i++) {
if(ch[i]>='a'&&ch[i]<='z') {
if(ch[i]=='z')
sb.append('A');
else
sb.append((char)(ch[i]-32+1));
}
else if(ch[i]>='A'&&ch[i]<='Z') {
if(ch[i]=='Z')
sb.append('a');
else
sb.append((char)(ch[i]+32+1));
}
else if(ch[i]>='0'&&ch[i]<='9') {
if(ch[i]=='9')
sb.append('0');
else
sb.append(ch[i]-'0'+1);
}
}
return sb.toString();
}
public static String jiemi(String str) {
char ch[]=str.toCharArray();
StringBuilder sb=new StringBuilder();
for(int i=0;i<ch.length;i++) {
if(ch[i]>='a'&&ch[i]<='z') {
if(ch[i]=='a')
sb.append('Z');
else
sb.append((char)(ch[i]-32-1));
}
else if(ch[i]>='A'&&ch[i]<='Z') {
if(ch[i]=='A')
sb.append('z');
else
sb.append((char)(ch[i]+32-1));
}
else if(ch[i]>='0'&&ch[i]<='9') {
if(ch[i]=='0')
sb.append('9');
else
sb.append(ch[i]-'0'-1);
}
}
return sb.toString();
}
}
HJ32 密码截取
描述
Catcher是MCA国的情报员,他工作时发现敌国会用一些对称的密码进行通信,比如像这些ABBA,ABA,A,123321,但是他们有时会在开始或结束时加入一些无关的字符以防止别国破解。比如进行下列变化 ABBA->12ABBA,ABA->ABAKK,123321->51233214 。因为截获的串太长了,而且存在多种可能的情况(abaaab可看作是aba,或baaab的加密形式),Cathcer的工作量实在是太大了,他只能向电脑高手求助,你能帮Catcher找出最长的有效密码串吗?
数据范围:字符串长度满足 1 \le n \le 2500 \1≤n≤2500
输入描述:
输入一个字符串(字符串的长度不超过2500)
输出描述:
返回有效密码串的最大长度
示例1
输入:
ABBA
复制
输出:
4
复制
示例2
输入:
ABBBA
复制
输出:
5
复制
示例3
输入:
12HHHHA
复制
输出:
4
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader bf=new BufferedReader(new InputStreamReader(System.in));
String str;
//中心扩散法
while((str=bf.readLine())!=null){
int max=0;
for(int i=0;i<str.length()-1;i++){
//ABA型
int len1=longest(str,i,i);
//ABBA型
int len2=longest(str,i,i+1);
max=Math.max(max,len1>len2?len1:len2);
}
System.out.println(max);
}
}
private static int longest(String str,int i,int j){
while(j<str.length()&&i>=0&&str.charAt(i)==str.charAt(j)){
i--;
j++;
}
return j-i-1;
}
}
HJ33 整数与IP地址间的转换
描述
原理:ip地址的每段可以看成是一个0-255的整数,把每段拆分成一个二进制形式组合起来,然后把这个二进制数转变成
一个长整数。
举例:一个ip地址为10.0.3.193
每段数字 相对应的二进制数
10 00001010
0 00000000
3 00000011
193 11000001
组合起来即为:00001010 00000000 00000011 11000001,转换为10进制数就是:167773121,即该IP地址转换后的数字就是它了。
数据范围:保证输入的是合法的 IP 序列
输入描述:
输入
1 输入IP地址
2 输入10进制型的IP地址
输出描述:
输出
1 输出转换成10进制的IP地址
2 输出转换后的IP地址
示例1
输入:
10.0.3.193
167969729
复制
输出:
167773121
10.3.3.193
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main{
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = null;
while ((str = br.readLine()) != null) {
String[] ip = str.split("\\.");
long num = Long.parseLong(br.readLine());
//转10进制
System.out.println(Long.parseLong(ip[0]) << 24 | Long.parseLong(ip[1]) << 16 |
Long.parseLong(ip[2]) << 8 | Long.parseLong(ip[3]));
//转ip地址
StringBuilder sb = new StringBuilder();
sb.append(String.valueOf((num >> 24) & 255)).append(".").append(String.valueOf((num >> 16) & 255))
.append(".").append(String.valueOf((num >> 8) & 255)).append(".").append(String.valueOf(num & 255));
System.out.println(sb.toString());
}
}
}
HJ36 字符串加密
描述
有一种技巧可以对数据进行加密,它使用一个单词作为它的密匙。下面是它的工作原理:首先,选择一个单词作为密匙,如TRAILBLAZERS。如果单词中包含有重复的字母,只保留第1个,将所得结果作为新字母表开头,并将新建立的字母表中未出现的字母按照正常字母表顺序加入新字母表。如下所示:
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
T R A I L B Z E S C D F G H J K M N O P Q U V W X Y (实际需建立小写字母的字母表,此字母表仅为方便演示)
上面其他用字母表中剩余的字母填充完整。在对信息进行加密时,信息中的每个字母被固定于顶上那行,并用下面那行的对应字母一一取代原文的字母(字母字符的大小写状态应该保留)。因此,使用这个密匙, Attack AT DAWN (黎明时攻击)就会被加密为Tpptad TP ITVH。
请实现下述接口,通过指定的密匙和明文得到密文。
本题有多组输入数据。
数据范围:1 \le n \le 100 \1≤n≤100 ,保证输入的字符串中仅包含小写字母
输入描述:
先输入key和要加密的字符串
输出描述:
返回加密后的字符串
示例1
输入:
nihao
ni
复制
输出:
le
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String key;
while ((key = br.readLine()) != null) {
char[] chars = key.toLowerCase().toCharArray();
char[] dict = new char[26];
int index = 0;
tag1:
for (char ch : chars) {
for (int i = 0; i < index; i++) {
if (ch == dict[i]) {
continue tag1;
}
}
dict[index] = ch;
index++;
}
char ch = 'a';
tag2:
for (int i = 0; i < 26; i++) {
for (int j = 0; j < index; j++) {
if (dict[j] == ch) {
ch++;
continue tag2;
}
}
dict[index] = ch;
ch++;
index++;
}
String str = br.readLine();
char[] res = str.toCharArray();
for (int i = 0; i < res.length; i++) {
if(res[i] - 'a'>=0){
res[i] = dict[res[i] - 'a'];
}else{
res[i] = dict[res[i] - 'A'];
}
}
System.out.println(String.valueOf(res));
}
}
}
HJ38 求小球落地5次后所经历的路程和第5次反弹的高度
描述
假设一个球从任意高度自由落下,每次落地后反跳回原高度的一半; 再落下, 求它在第5次落地时,共经历多少米?第5次反弹多高?
最后的误差判断是小数点6位
数据范围:输入的小球初始高度满足 1 \le n \le 1000 \1≤n≤1000 ,且保证是一个整数
输入描述:
输入起始高度,int型
输出描述:
分别输出第5次落地时,共经过多少米第5次反弹多高
示例1
输入:
1
复制
输出:
2.875
0.03125
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str;
while ((str = br.readLine()) != null) {
double height = Integer.parseInt(str);
System.out.println(get(height));
System.out.println(height(height));
}
}
public static double height(double h) {
for (int i = 0; i < 5; i++) {
h = h / 2;
}
return h;
}
public static double get(double h) {
return h + h + h / 2 + h / 4 + h / 8;
}
}
HJ41 称砝码
描述
现有一组砝码,重量互不相等,分别为 m1,m2,m3…mn ;
每种砝码对应的数量为 x1,x2,x3...xn 。现在要用这些砝码去称物体的重量(放在同一侧),问能称出多少种不同的重量。
注:
称重重量包括 0
本题有多组输入
数据范围:每组输入数据满足 1 \le n \le 10 \1≤n≤10 , 1 \le m_i \le 2000 \1≤mi≤2000 , 1 \le x_i \le 10 \1≤xi≤10
输入描述:
输入包含多组测试数据。
对于每组测试数据:
第一行:n --- 砝码的种数(范围[1,10])
第二行:m1 m2 m3 ... mn --- 每种砝码的重量(范围[1,2000])
第三行:x1 x2 x3 .... xn --- 每种砝码对应的数量(范围[1,6])
输出描述:
利用给定的砝码可以称出的不同的重量数
示例1
输入:
2
1 2
2 1
10
4 185 35 191 26 148 149 3 172 147
3 5 2 1 5 5 3 1 4 2
复制
输出:
5
3375
import java.io.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String line;
while((line = reader.readLine()) != null) {
String[] m = reader.readLine().split(" ");
String[] x = reader.readLine().split(" ");
int[] weight = new int[m.length];
int[] nums = new int[x.length];
int sum = 0;
for (int i = 0; i < m.length; i++) {
weight[i] = Integer.parseInt(m[i]);
nums[i] = Integer.parseInt(x[i]);
sum += weight[i] * nums[i];
}
System.out.println(fama(m.length, weight, nums, sum));
}
}
public static int fama(int n, int[] weight, int[] nums, int sum){
boolean[] weg = new boolean[sum+1];
weg[0] =true;
weg[sum] = true;
int top = 0;
// 三重循环,分别表示 n个砝码分类,每个种类有 nums[i]个数量
for(int i =0; i < n; i++){
for (int j = 0; j < nums[i]; j++) {
for(int k=top + weight[i]; k>= weight[i];k--){
// weg[k-weight[i]]== true, 画数轴可以了解,k-weight[i]如果在数轴中存在,则k-weight[i] + weight[i] = k,即k重量也将在数轴范围内
if(weg[k -weight[i]]){
weg[k] = true;
}
}
top += weight[i];
}
}
int count = 0;
for (boolean b : weg) {
if (b) count++;
}
return count;
}
}
HJ43 迷宫问题
描述
定义一个二维数组 N*M ,如 5 × 5 数组下所示:
int maze[5][5] = {
0, 1, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 0, 0,
0, 1, 1, 1, 0,
0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的路线。入口点为[0,0],既第一格是可以走的路。
本题含有多组数据。
数据范围: 2 \le n,m \le 10 \2≤n,m≤10 , 输入的内容只包含 0 \le val \le 1 \0≤val≤1
输入描述:
输入两个整数,分别表示二维数组的行数,列数。再输入相应的数组,其中的1表示墙壁,0表示可以走的路。数据保证有唯一解,不考虑有多解的情况,即迷宫只有一条通道。
输出描述:
左上角到右下角的最短路径,格式如样例所示。
示例1
输入:
5 5
0 1 0 0 0
0 1 1 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
复制
输出:
(0,0)
(1,0)
(2,0)
(2,1)
(2,2)
(2,3)
(2,4)
(3,4)
(4,4)
复制
示例2
输入:
5 5
0 1 0 0 0
0 1 0 1 0
0 0 0 0 1
0 1 1 1 0
0 0 0 0 0
复制
输出:
(0,0)
(1,0)
(2,0)
(3,0)
(4,0)
(4,1)
(4,2)
(4,3)
(4,4)
复制
说明:
注意:不能斜着走!!
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Stack;
public class Main {
public int[][] directions = {
{0, 1},
{1, 0},
{-1, 0},
{0, -1}
};
private Stack<int[]> path;
private ArrayList<int[]> minPath;
private int[][] matrix;
private boolean[][] visited;
public static void main(String[] args) throws Exception {
Main main= new Main();
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str1 = null;
while ((str1 = br.readLine()) != null) {
String[] arr = str1.split(" ");
int rows = Integer.parseInt(arr[0]);
int cols = Integer.parseInt(arr[1]);
main.path = new Stack<>();
main.minPath = null;
main.matrix = new int[rows][cols];
main.visited = new boolean[rows][cols];
for (int i = 0; i < rows; i++) {
String[] str2 = br.readLine().split(" ");
for (int j = 0; j < cols; j++) {
main.matrix[i][j] = Integer.parseInt(str2[j]);
}
}
main.dfs(0, 0);
StringBuilder sb = new StringBuilder();
for (int[] res : main.minPath) {
sb.append('(').append(res[0]).append(',').append(res[1]).append(")\n");
}
System.out.print(sb);
}
}
private void dfs(int i, int j) {
if (i > matrix.length - 1 || i < 0 || j > matrix[0].length - 1 || j < 0 ||
visited[i][j] || matrix[i][j] == 1 ||
(minPath != null && path.size() >= minPath.size())) {
return;
}
if (i == matrix.length - 1 && j == matrix[0].length - 1) {
path.add(new int[]{i, j});
minPath = new ArrayList<>(path);
path.pop();
return;
}
path.add(new int[]{i, j});
visited[i][j] = true;
for (int[] direction : directions) {
dfs(i + direction[0], j + direction[1]);
}
visited[i][j] = false;
path.pop();
}
}