华为笔试算法题解
第1题 字符串处理
思路:先过滤掉数字,然后按GBK编码扫描汉字的长度,若为偶则子串长度length-cnt/2,若为奇则子串长度length-(cnt/2+1)(GBK编码汉字为2字节,数值小于0)
import java.io.UnsupportedEncodingException;
import java.util.Scanner;
/**
*
* 在GBK编码下,请编写一个截取字符串的函数, 输入为一个字符串和字节数,输出为按字节截取的字符串。 但是要保证汉字不被截半个,
* 同时忽略字符串中的数字后输出最终结果。
*
* 输入描述:
*
* 一行字符串和待截取的字节数
*
* 输出描述:
*
* 单独的一行截取后的字符串
*
* 示例1
*
* 输入
*
* 华HUA
* 4
*
* 输出
*
* 华HU
*
* 备注:
*
* 要保证汉字不被截半个,同时忽略字符串中的数字后输出最终结果。
*/
public class Str {
static String splitString(String str,int length){
try {
byte[] bytes = str.getBytes("GBK");
int cnt=0;
for(byte x:bytes){
if(x<0) cnt++;
}
if(cnt%2==0) return str.substring(0,length-cnt/2);
else return str.substring(0,length-cnt/2-1);
}catch (UnsupportedEncodingException e){
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
while(scanner.hasNext()){
String str=scanner.nextLine();
int length=scanner.nextInt();
String str1=str.replaceAll("\d","");
String ans=splitString(str1,length);
System.out.println(ans);
}
scanner.close();
}
}
第2题 日期
利用Calendar类处理,注意月份从0开始,星期从周日开始
import java.util.Calendar;
import java.util.Scanner;
/**
*
* 13号又恰好是星期五真的很特殊吗?也就是说,13号出现在星期五的几率比出现在其它周日的几率大吗?要回答这个问题,
*
* 写一个程序计算13日出现在某个星期的次数(在给定的N年时间中)。这个时间段为1900年1月1日到1900+N-1年12月31日。
*
* N为非负整数,不超过400。(1900年1月1日是星期一)
*
* 输入描述:
*
* 1 0
* 第一个参数为years,表示距离1900年1月1日的年数
* 第二个参数为weeks,表示星期数(分别用0——6代表星期日到星期六)
*
* 输出描述:
*
* 13日出现在星期数为weeks的次数,若异常失败输出-1
*
* 示例1
*
* 输入
*
* 1 0
*
* 输出
* 1
*/
public class Cal {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
while(scanner.hasNext()){
int years=scanner.nextInt();
int weeks=scanner.nextInt();
if(years<=0 || weeks>6 || weeks <0){
System.out.println("-1");
continue;
}
Calendar calendar=Calendar.getInstance();
int cnt=0;
for(int i=1900;i<1900+years;i++)
for(int j=0;j<12;j++){
calendar.set(i,j,13);
int week=calendar.get(Calendar.DAY_OF_WEEK)-1;
if(week==weeks)
cnt++;
}
System.out.println(cnt);
}
scanner.close();
}
}
第3题 DP
(dice[i][j])表示i个骰子出现和为j的可能数,即为i-1个骰子扔出的和分别为j-1,j-2...j-6加上第i个骰子扔出1,2...6的情况和,可以写出如下的表达式
[dice[i][j]=dice[i-1][j-1]+dice[i-1][j-2]+dice[i-1][j-3]+dice[i-1][j-4]+dice[i-1][j-5]+dice[i-1][j-6]
]
注意过滤一下和为负的情况
import java.util.ArrayList;
import java.util.Scanner;
/**
*
* 有N个骰子,同时投掷出去,向上面的数字之和为 A。
*
* 那么输入为N个筛子,请计算出A,和他出现的概率。
*
* 概率值,小数点保留5位。
*
* 输入描述:
*
* N,骰子数目
*
* 输出描述:
*
* [[1, 0.16667], [2, 0.16667], [3, 0.16667], [4, 0.16667], [5, 0.16667], [6, 0.16667]]
* 输出为二维数组。每一个值,第一个表示数字, 第二个表示概率。
*
* 示例1
*
* 输入
*
* 1
*
* 输出
*
* [[1, 0.16667], [2, 0.16667], [3, 0.16667], [4, 0.16667], [5, 0.16667], [6, 0.16667]]
*/
public class Dice {
public static void main(String[] args) {
Scanner scanner=new Scanner(System.in);
while(scanner.hasNext()){
int N=scanner.nextInt();
int[][] dice=new int[N+1][6*N+1];
for(int i=1;i<=6;i++)
dice[1][i]=1;
for(int i=2;i<=N;i++)
for(int j=N;j<=6*N;j++)
for(int k=1;j-k>0 && k<=6;k++) {
dice[i][j] += dice[i][j - k];
}
double total=Math.pow(6,N);
ArrayList<ArrayList<String>> list=new ArrayList<>();
for(int i=N;i<=6*N;i++){
ArrayList<String> item=new ArrayList<>();
item.add(Integer.toString(i));
item.add(String.format("%.5f",dice[N][i]/total));
list.add(item);
}
System.out.println(list.toString());
}
scanner.close();
}
}