尝试挑战了下网易2017校招的笔试编程题,共三题,AC第一题,第二题思考了很久勉强用一种low逼的方式完成,第三题没有完成,希望路过的ACM大神点醒。下面附上原题和我的解法,不喜勿喷。
第一题:rev翻转
实现一个rev操作,使得一个整数反转,如输入"123",输出"321",并去掉前导0,如输入“100”,输出"1"。然后输入两个数a,b,输出rev(rev(a)+rev(b))的结果。
输入输出示例:
输入:
100 322
输出:
422
解题思路:这题较为简单,只要能写出rev函数就可以解决问题。我采用的方法是从个位开始逐个提取数字拼接字符串的方式实现,设置首0标志,凡遇到0则剔除,当遇到非0数字时,取消首0检验。不多说,附上代码:
import java.util.Scanner;
public class Main {
public static int rev(int a){
StringBuffer string =new StringBuffer();
int b = 0 ;
boolean flag=true;
while(a>0){
b = a%10;
a = (a-b)/10;
if(flag){
if(b!=0){
flag = false;
string.append(Integer.toString(b));
}
}else{
string.append(Integer.toString(b));
}
}
return Integer.parseInt(string.toString());
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while (in.hasNextInt()) {//注意while处理多个case
int a = in.nextInt();
int b = in.nextInt();
System.out.println(rev(rev(a)+rev(b)));
}
}
}
第二题:暗黑的字符串
使用“A”,“B”,“C” 三个字符构建字符串,对于一个构建好的字符串,如果存在连续三个字符,“A”,“B”,“C” 三个字符刚好各出现一次,如“ABCA”,那么称这样的字符串是“纯净”的。如果找不到这样的连续三个字符满足条件,那么称这样的字符串是“暗黑”的,如“ABAA”。
现在给定一个整数n,试输出能构成的n位暗黑字符串的个数。
输入输出示例:
输入:
3
输出:
21
分析:这题笔一开始笔者采用的是暴力穷举的方法,就是列出所3^n种可能,然后逐一判断是否暗黑来进行统计。在构建出所有的字符串时采用了递归的方法,即通过一位一位地增加位数的方式得到,算法复杂度较高。代码如下:
import java.util.Scanner;
public class Main {
public static boolean isWhite(String testString){
boolean flag = false;
String[] abc = new String[]{"ABC","ACB","BAC","BCA","CBA","CAB"};
for (int i = 0; i < abc.length; i++) {
if(testString.contains(abc[i])){
flag = true;
break;
}
}
return flag;
}
public static String[] generateABC(int n){
String[] init = new String[]{"A","B","C"};
if(n==1){
return init;
}else{
String[] abc = generateABC(n-1);
String[] ABC = new String[abc.length*init.length];
for (int i = 0; i < abc.length; i++) {
for (int j = 0; j < init.length; j++) {
ABC[j*abc.length+i] =abc[i]+init[j];
}
}
return ABC;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
StringBuffer testString = new StringBuffer();
if(n<3){
System.out.println((int)(Math.pow(3,n)));
}else{
int count = 0;
String[] result = generateABC(n);
for (int i = 0; i <result.length; i++) {
if(isWhite(result[i])){
count++;
}
}
System.out.println(result.length-count);
}
}
}
然后很快发现,这种写法在n=14时就坚持不住内存溢出了。
于是请教了ACM高手,在高手的指点下,使用了数位DP算法,完成了此题的求解。代码如下:
import java.util.Scanner;
/**
* 数位DP求解
* @author shenwc
*
*/
public class DpResovle {
private static int[][] blacks ;
private static boolean flag = true;//标记用以判断是否是首次调用
public static int[][] BlackCount (int length){
if(flag){
blacks = new int[length+1][4];
flag =false;
}
if(length==3){
//用二维数组blacks 存储暗黑字符串的个数
//第一个维度代表字符串长度
// 第二个维度的代表末尾状况
// 0 代表末尾以AAA,BBB,或CCC结尾
// 1 代表末尾以AAB,AAC,BBC,BBA,CCA,CCB结尾
// 2 代表末尾以ABA,CBC,ACA,BCB,BAB,CAC结尾
// 3 代表末尾以ABB,ACC,BCC,BAA,CAA,BAA结尾
blacks[3][0] =3;
blacks[3][1] =6;
blacks[3][2] =6;
blacks[3][3] =6;
}else {
BlackCount (length-1);
blacks[length][0] = blacks[length-1][0]+blacks[length-1][3];
blacks[length][1] = 2*(blacks[length-1][0]+blacks[length-1][3]);
blacks[length][2] = blacks[length-1][1]+blacks[length-1][2];
blacks[length][3] = blacks[length-1][1]+blacks[length-1][2];
}
return blacks;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
StringBuffer testString = new StringBuffer();
if(n<3){
System.out.println((int)(Math.pow(3,n)));
}else{
long time1 = System.currentTimeMillis();
int[][] result = BlackCount(n);
int count = 0;
for (int i = 0; i < 4; i++) {
count+=result[n][i];
}
System.out.println(count);
long time2 = System.currentTimeMillis();
System.out.println("用时:"+(time2-time1)+"ms");
}
}
}
第三题:回文序列
对于{1,2,1},{345},{2,3,3,2}这样对称的序列我们称之为回文序列。
现在对于任意一个输入的序列,如{1,2,3,4},我们有一种操作,将相邻两个数相加并放回到这两个数原来的位置。对于{5,2,3,4},可以通过一次操作变为{7,3,4},两次操作变为{7,7}。
现在试求出对于任意一个输入的序列,将其变为回文序列的最小步数。
输入输出示例:
输入:
4(代表序列个数)
5 2 3 4
输出:
2
分析:本题笔者没有写出代码。不知道这题是否可以用动态规划的方法求解,如果可以,还请大神指教。