Java 笔试面试 算法编程篇 一
1 /* ********************************************************************************** 1、编写一个程序,将a.txt文件中的单词与b.txt文件中的单词交替合并到c.txt文件中, a.txt文件中的单词用回车符分隔,b.txt文件中用回车或空格进行分隔。 *************************************************************************************/ 答: package com.example; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.net.URLDecoder; public class example1 { public static void main(String[] args) throws Exception { FileManager m1 = new FileManager("a.txt", new char[]{'\n'}); FileManager m2 = new FileManager("b.txt", new char[]{'\n', ' '}); FileWriter c = new FileWriter("c.txt"); String aWord = null; String bWord = null; while((aWord = m1.nextWord()) != null){ c.write(aWord + "\n"); bWord = m2.nextWord(); if(bWord != null){ c.write(bWord + "\n"); } } while((bWord = m2.nextWord()) != null){ c.write(bWord + "\n"); } c.close(); } } class FileManager{ String[] words = null; int pos = 0; public FileManager(String filename, char[] seperators) throws Exception{ // ClassLoader.getSystemResource("") //file:\D:\Coding_Project\eclipse2\Java面试问题集\Chapter2\bin\a.txt // this.getClass().getResource("").getPath() // /D:/Coding_Project/eclipse2/Java面试问题集/Chapter2/bin/com/example/ // System.out.println(URLDecoder.decode(this.getClass().getResource("/").getPath(),"UTF-8")); filename=this.getClass().getResource("/").getPath() + filename; filename=URLDecoder.decode(filename,"UTF-8"); //中文路径问题 File f = new File(filename); FileReader reader = new FileReader(f); char[] buf = new char[(int)f.length()]; int len = reader.read(buf); String results = new String(buf, 0, len); String regex = null; if(seperators.length > 1){ regex = "" + seperators[0] + "|" + seperators[1]; }else{ regex = "" + seperators[0]; } words = results.split(regex); reader.close(); // System.out.println(); } public String nextWord(){ if(pos == words.length){ return null; } return words[pos++]; } } FilenameFilter 一、FilenameFilter介绍 Java.io.FilenameFilter是文件名过滤器,用来过滤不符合规格的文件名,并返回合格的文件; 一般地: (1)String[] fs = f.list(); (2)File[] fs = f.listFiles(); 这两个方法返回f下的所有文件或目录; FilenameFilter用来把符合要求的文件或目录返回; 因此可以调用: (1)String []fs = f.list(FilenameFilter filter);; (2)File[]fs = f.listFiles(FilenameFilter filter); 二、文件名过滤器一般用法 1.实现FilenameFilter接口; 2.实现boolean accept(File dir,String name); //dir表示文件的当前目录,name表示文件名; class MyFilter implements FilenameFilter{ private String type; //type为需要过滤的条件,比如如果type=".jpg",则只能返回后缀为jpg的文件 public MyFilter(String type){ this.type = type; } public boolean accept(File dir,String name){ //返回true的文件则合格 } } 三、实例 要求:返回当前目录下所有以.java结尾的文件; package org.exam5a; import java.io.File; import java.io.FilenameFilter; public class T4 { public static void main(String[] args)throws Exception { File f = new File("."); MyFilter filter = new MyFilter(".java"); String[] files = f.list(filter); for(String a:files){ System.out.println(a); } } static class MyFilter implements FilenameFilter{ private String type; public MyFilter(String type){ this.type = type; } public boolean accept(File dir,String name){ return name.endsWith(type); } } } 2 /* ********************************************************************************** 2、编写一个程序,将d:\java 目录下的所有.java 文件复制到d:\temp 目录下,并 将原来文件的扩展名从.java 改为.temp *************************************************************************************/ package com.example; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class example2 { public static void main(String[] args) throws Exception { java2temp jt = new java2temp(); jt.transfer(); } } class java2temp { // String srcPath = URLDecoder.decode(this.getClass().getResource("/").getPath(),"UTF-8"); public void transfer() throws Exception{ // System.getProperty("user.dir") + "\\src"; // D:\Coding_Project\eclipse2\Java面试问题集\Chapter2\src // String srcPath = URLDecoder.decode(this.getClass().getResource("/").getPath(),"UTF-8"); // /D:/Coding_Project/eclipse2/Java面试问题集/Chapter2/bin/ String srcPath = System.getProperty("user.dir") + "\\src\\com\\example"; String desPath = srcPath + "\\temp"; System.out.println(srcPath+"\n"+desPath); File srcDir = new File(srcPath); if(!(srcDir.exists() && srcDir.isDirectory())){ throw new Exception("directory doesn't exist"); } File[] files = srcDir.listFiles( new FilenameFilter() { @Override public boolean accept(File dir, String name) { // TODO Auto-generated method stub return name.endsWith(".java"); } } ); System.out.println(files.length); File desDir = new File(desPath); if(!desDir.exists()){ desDir.mkdirs(); } for(File f : files){ FileInputStream fis = new FileInputStream(f); String destFilename = f.getName().replaceAll("\\.java$", ".temp"); FileOutputStream fos = new FileOutputStream(new File(desDir, destFilename)); copy(fis, fos); fis.close(); fos.close(); } } private void copy(InputStream ips, OutputStream ops) throws IOException{ int len = 0; byte[] buf = new byte[1024]; while((len = ips.read(buf)) != -1){ ops.write(buf, 0, len); } } } 不同编码英文字母和中文汉字所占字节。 GBK的编码是一个汉字两个字节,范围是第一个字节大于128开始,第二个字节从大于64开始。 第一个字节大于127就表示这是个汉字的开始。 byte这种类型只有java有,范围是-127到127.所以打印出来转换了就变成负数了。 import java.io.UnsupportedEncodingException; public class EncodeTest { /** * 打印字符串在指定编码下的字节数和编码名称到控制台 * * @param s * 字符串 * @param encodingName * 编码格式 */ public static void printByteLength(String s, String encodingName) { System.out.print("字节数:"); try { System.out.print(s.getBytes(encodingName).length); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } System.out.println(";编码:" + encodingName); } public static void main(String[] args) { String en = "A"; String ch = "人"; // 计算一个英文字母在各种编码下的字节数 System.out.println("英文字母:" + en); EncodeTest.printByteLength(en, "GB2312"); EncodeTest.printByteLength(en, "GBK"); EncodeTest.printByteLength(en, "GB18030"); EncodeTest.printByteLength(en, "ISO-8859-1"); EncodeTest.printByteLength(en, "UTF-8"); EncodeTest.printByteLength(en, "UTF-16"); EncodeTest.printByteLength(en, "UTF-16BE"); EncodeTest.printByteLength(en, "UTF-16LE"); System.out.println(); // 计算一个中文汉字在各种编码下的字节数 System.out.println("中文汉字:" + ch); EncodeTest.printByteLength(ch, "GB2312"); EncodeTest.printByteLength(ch, "GBK"); EncodeTest.printByteLength(ch, "GB18030"); EncodeTest.printByteLength(ch, "ISO-8859-1"); EncodeTest.printByteLength(ch, "UTF-8"); EncodeTest.printByteLength(ch, "UTF-16"); EncodeTest.printByteLength(ch, "UTF-16BE"); EncodeTest.printByteLength(ch, "UTF-16LE"); } } 运行结果如下: 英文字母:A 字节数:1;编码:GB2312 字节数:1;编码:GBK 字节数:1;编码:GB18030 字节数:1;编码:ISO-8859-1 字节数:1;编码:UTF-8 字节数:4;编码:UTF-16 字节数:2;编码:UTF-16BE 字节数:2;编码:UTF-16LE 中文汉字:人 字节数:2;编码:GB2312 字节数:2;编码:GBK 字节数:2;编码:GB18030 字节数:1;编码:ISO-8859-1 字节数:3;编码:UTF-8 字节数:4;编码:UTF-16 字节数:2;编码:UTF-16BE 字节数:2;编码:UTF-16LE 编码范围 // 1. GBK (GB2312/GB18030) // x00-xff GBK双字节编码范围 // x20-x7f ASCII // xa1-xff 中文 // x80-xff 中文 // // 2. UTF-8 (Unicode) // u4e00-u9fa5 (中文) // x3130-x318F (韩文) // xAC00-xD7A3 (韩文) // u0800-u4e00 (日文) 3 /* ********************************************************************************** 3、编写一个截取字符串的函数,输入为一个字符串和字节数,输出为按字节截取的字符串, 但要保证汉字不被截取半个,如“我ABC”,4,应该截取“我AB”, 输入“我ABC汉DEF”,6,应该输出“我ABC”,而不是“我ABC+汉的半个”。 *************************************************************************************/ package com.example; import java.io.UnsupportedEncodingException; public class example3 { public static void main(String[] args) throws Exception { String str = "你abc好"; trimGBK(str, 6); } public static void trimGBK(String str, int n) throws UnsupportedEncodingException{ byte[] buf = str.getBytes("GBK"); boolean bChineseFirstHalf = false; int num = 0; // GBK的编码是一个汉字两个字节,范围是第一个字节大于128开始,第二个字节从大于64开始。 // 第一个字节大于127就表示这是个汉字的开始。 // byte这种类型只有java有,范围是-127到127.所以打印出来转换了就变成负数了。 // 编码范围 // 1. GBK (GB2312/GB18030) // x00-xff GBK双字节编码范围 // x20-x7f ASCII -- 英文为正数 // xa1-xff 中文 -- 中文为负数 // x80-xff 中文 // // 2. UTF-8 (Unicode) // u4e00-u9fa5 (中文) // x3130-x318F (韩文) // xAC00-xD7A3 (韩文) // u0800-u4e00 (日文) for(int i = 0; i < n; i++){ if(buf[i] < 0 && !bChineseFirstHalf){ bChineseFirstHalf = true; }else{ num++; bChineseFirstHalf = false; } } System.out.println(str.substring(0, num)); } } 4 /* ********************************************************************************** 4、有一个字符串,其中包含中文字符、英文字符和数字字符,请统计和打印出各个字符的个数。 *************************************************************************************/ package com.example; import java.util.HashMap; import java.util.Map; public class example4 { public static void main(String[] args) throws Exception { String str = "中国aadf的111萨bbb菲的zz萨菲"; char[] strArr = str.toCharArray(); HashMap<Character, Integer> map = new HashMap<Character, Integer>(); Integer num = 0; for(char c : strArr){ num = map.get(c); if(num == null){ num = 1; } else{ num = num + 1; } map.put(c, num); } for(Map.Entry<Character, Integer> entry : map.entrySet()){ System.out.println(entry.getKey() + "\t: " + entry.getValue()); } } } //结果 f : 1 菲 : 2 1 : 3 d : 1 b : 3 的 : 2 a : 2 中 : 1 萨 : 2 国 : 1 z : 2 5 二叉树 /* ********************************************************************************** 5、说明生活中遇到的二叉树,用java 实现二叉树 答: 二叉查找树 *************************************************************************************/ package com.example; import java.util.Arrays; import java.util.HashMap; public class example5 { public static void main(String[] args) throws Exception { int[] data = new int[10]; HashMap<Integer, Boolean> map = new HashMap<>(); for(int i=0; i<data.length; i++){ int tmp = (int)(Math.random() * 100 + 1); while(map.get(tmp) != null){ tmp = (int)(Math.random() * 100 + 1); } data[i] = tmp; map.put(tmp, true); } System.out.println(Arrays.toString(data)); BinaryTree root = new BinaryTree(data[0]); for(int i : data){ if(i != data[0]){ // System.out.print(i + " "); root.add(i); } } System.out.println("先序:"); root.preOrderTraverse(); System.out.println(); System.out.println("中序:"); root.midOrderTraverse(); System.out.println(); System.out.println("非递归中序:"); root.midOrderTraverse2(); System.out.println(); System.out.println("后序:"); root.postOrderTraverse(); System.out.println(); } } class BinaryTree{ private int value; private BinaryTree lChild; private BinaryTree rChild; public BinaryTree(){ } public BinaryTree(int value){ this.value = value; } @Override public String toString() { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(); sb.append(value); return sb.toString(); } public void add(int value){ if(value < this.value){ if(this.lChild == null){ lChild = new BinaryTree(); lChild.value = value; }else{ lChild.add(value); } }else if(value > this.value){ if(this.rChild == null){ this.rChild = new BinaryTree(); rChild.value = value; }else{ rChild.add(value); } } } public boolean isExist(int value){ if(this.value == value){ return true; }else if(value < this.value){ if(this.lChild == null){ return false; }else{ return lChild.isExist(value); } }else{ if(null == this.rChild){ return false; }else{ return rChild.isExist(value); } } } public void preOrderTraverse(){ System.out.print(this.value + ","); if(null != lChild) lChild.preOrderTraverse(); if(null != rChild) rChild.preOrderTraverse(); } public void midOrderTraverse(){ if(null != lChild) lChild.midOrderTraverse(); System.out.print(this.value + ","); if(null != rChild) rChild.midOrderTraverse(); } //非递归中序 public void midOrderTraverse2(){ MyArrayStack<BinaryTree> s = new MyArrayStack<BinaryTree>(); BinaryTree tmp = this; while((null != tmp) || !s.isEmpty()){ if(null != tmp){ s.push(tmp); tmp = tmp.lChild; }else{ BinaryTree tmp2 = s.pop(); System.out.print(tmp2.value + ","); tmp = tmp2.rChild; } System.out.println(s.toString()); } } public void postOrderTraverse(){ if(null != lChild) lChild.postOrderTraverse(); if(null != rChild) rChild.postOrderTraverse(); System.out.print(this.value + ","); } } interface MyStack<T>{ boolean isEmpty(); void clear(); int length(); boolean push(T data); T pop(); } class MyArrayStack<T> implements MyStack<T>{ private Object[] objs = new Object[16]; private int size = 0; @Override public boolean isEmpty() { return size == 0; } @Override public void clear() { // TODO Auto-generated method stub for (int i = 0; i < objs.length; i++) { objs[i] = null; } size = 0; } @Override public int length() { return size; } @Override public boolean push(T data) { if(size >= objs.length){ resize(); } objs[size++] = data; return true; } @SuppressWarnings("unchecked") @Override public T pop() { if(size <= 0){ return null; } return (T)objs[--size]; } public void resize(){ Object[] tmp = new Object[objs.length * 3 / 2 + 1]; for (int i = 0; i < objs.length; i++) { tmp[i] = objs[i]; objs[i] = null; } objs=tmp; } @Override public String toString() { // TODO Auto-generated method stub StringBuilder sb = new StringBuilder(); sb.append("MyArrayStack: ["); for(int i=0; i<size; i++){ sb.append(objs[i].toString()); if(i != size - 1){ sb.append(", "); } } sb.append("]"); return sb.toString(); } } 6 /* ********************************************************************************** 6.从类似如下的文本文件中读取出所有的姓名,并打印出重复的姓名和重复的次数,并按重复次数排序: 1,张三,28 2,李四,35 3,张三,28 4,王五,35 5,张三,28 6,李四,35 7,赵六,28 8,田七,35 *************************************************************************************/ package com.example; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.TreeSet; import java.util.Iterator; public class example6 { public static void main(String[] args) throws Exception { HashMap<String, Integer> results = new HashMap<String, Integer>(); //文件在src路径下 InputStream ips = example6.class.getResourceAsStream("/UserInfo.txt"); //文件与类在相同的包下面,可以用相对路径 //InputStream ips = example6.class.getResourceAsStream("UserInfo.txt"); BufferedReader br = new BufferedReader(new InputStreamReader(ips)); String line = null; try { while((line = br.readLine()) != null){ // System.out.println(line + "aa"); dealLine(line, results); } sortResults(results); } catch (IOException e) { // TODO: handle exception e.printStackTrace(); } } static class User{ public String name; public Integer value; public User(String name, Integer value) { super(); this.name = name; this.value = value; } @Override public boolean equals(Object obj) { // TODO Auto-generated method stub //下面的代码没有执行,说明往treeset 中增加数据时,不会使用到equals 方法。 System.out.println(super.equals(obj)); return super.equals(obj); } } public static void sortResults(Map<String, Integer> results){ TreeSet<Object> sortedResults = new TreeSet<Object>(new Comparator<Object>() { public int compare(Object o1, Object o2) { User u1 = (User)o1; User u2 = (User)o2; /*如果compareTo 返回结果0,则认为两个对象相等,新的对象不会增加到集合中去 所以,不能直接用下面的代码,否则,那些个数相同的其他姓名就打印不出来。 * */ // return u1.value-u2.value; // return u1.value<u2.value?-1:u1.value==u2.value?0:1; if(u1.value > u2.value){ return 1; } if(u1.value < u2.value){ return -1; } return u1.name.compareTo(u2.name); }; }); @SuppressWarnings("rawtypes") Iterator iter = results.keySet().iterator(); while(iter.hasNext()){ String name = (String)iter.next(); Integer value = (Integer) results.get(name); if(value > 1){ sortedResults.add(new User(name, value)); } } printResults(sortedResults); } public static void dealLine(String line, Map<String, Integer> map){ if(!"".equals(line.trim())){ String[] results = line.split(","); if(results.length == 3){ String name = results[1]; Integer value = (Integer)map.get(name); if(null == value){ value = 0; } map.put(name, value + 1); } } } @SuppressWarnings({ "rawtypes" }) private static void printResults(TreeSet sortedResults){ Iterator iter = sortedResults.iterator(); while(iter.hasNext()){ User u = (User)iter.next(); System.out.println(u.name + ":" + u.value); } } } 7 /* ********************************************************************************** 递归算法题 一个整数,大于0,不用循环和本地变量,按照n,2n,4n,8n 的顺序递增,当值大于5000 时,把值按照指定顺序输出来。 例:n=1237 则输出为: 1237, 2474, 4948, 9896, 9896, 4948, 2474, 1237, 提示:写程序时,先致谢按递增方式的代码,写好递增的以后,再增加考虑递减部分。 *************************************************************************************/ package com.example; public class example7 { public static void main(String[] args) throws Exception { doubleNum(1237); } public static void doubleNum(int n){ System.out.println(n); if(n <= 5000){ doubleNum(n * 2); } System.out.println(n); } } 8 /* ********************************************************************************** 递归算法题 第1个人10,第2个比第1个人大2岁,依次递推,请用递归方式计算出第8个人多大? *************************************************************************************/ package cn.itcast; import java.util.Date; publicclass A1 { public static voidmain(String [] args) { System.out.println(computeAge(8)); } public static int computeAge(int n) { if(n==1)return 10; return computeAge(n-1) + 2; } } 9 将数组元素顺序颠倒 /* ********************************************************************************** 有数组a[n],用java 代码将数组元素顺序颠倒 *************************************************************************************/ package com.example; import java.util.Arrays; public class example11 { public static void main(String[] args) throws Exception { int[] arr = new int[10]; for(int i=1; i<arr.length; i++){ arr[i] = (int)(Math.random() * 100 + 1); } System.out.println(Arrays.toString(arr)); swap(arr); System.out.println(Arrays.toString(arr)); } //用下面的也可以 //for(inti=0,int j=a.length-1;i<j;i++,j--)是否等效于for(int i=0;i<a.length/2;i++)呢? public static void swap(int[] arr){ int len = arr.length; for(int i=0; i<len/2; i++){ int tmp = arr[i]; arr[i] = arr[len - 1 - i]; arr[len - 1 - i] = tmp; } } } 10金额转换 /* ********************************************************************************** 金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。 *************************************************************************************/ package com.example; public class example12 { private static final char[] data = new char[] { '零','壹','贰','叁','肆','伍','陆','柒','捌','玖'}; private static final char[] units = new char[] { '元','拾','佰','仟','万','拾','佰','仟','亿'}; public static void main(String[] args) throws Exception { System.out.println(convert(135009003)); } public static String convert(int money) { StringBuffer sbf = new StringBuffer(); int unit = 0; while(money!=0) { sbf.insert(0,units[unit++]); int number = money%10; sbf.insert(0,data[number]); money/= 10; } // return sbf.toString(); //去零,正则表达式 return sbf.toString().toString().replaceAll("零[拾佰仟]","零"). replaceAll("零+万","万").replaceAll("零+元","元").replaceAll("零+","零"); } } //135009003 //不去零 : 壹亿叁仟伍佰零拾零万玖仟零佰零拾叁元 //结果 : 壹亿叁仟伍佰万玖仟零叁元 11请设计一个一百亿的计算器 二分查找法 二分查找又称折半查找,它是一种效率较高的查找方法。 二分查找要求:1.必须采用顺序存储结构 2.必须按关键字大小有序排列。 二分查找算法是在有序数组中用到的较为频繁的一种算法,在未接触二分查找算法时,最通用的一种做法是,对数组进行遍历,跟每个元素进行比较,其时间为O(n).但二分查找算法则更优,因为其查找时间为O(lgn),譬如数组{1, 2, 3, 4, 5, 6, 7, 8, 9},查找元素6,用二分查找的算法执行的话,其顺序为: 1.第一步查找中间元素,即5,由于5<6,则6必然在5之后的数组元素中,那么就在{6, 7, 8, 9}中查找, 2.寻找{6, 7, 8, 9}的中位数,为7,7>6,则6应该在7左边的数组元素中,那么只剩下6,即找到了。 /** * 二分查找又称折半查找,它是一种效率较高的查找方法。 【二分查找要求】:1.必须采用顺序存储结构 2.必须按关键字大小有序排列。 * @author Administrator * */ public class BinarySearch { public static void main(String[] args) { int[] src = new int[] {1, 3, 5, 7, 8, 9}; System.out.println(binarySearch(src, 3)); System.out.println(binarySearch(src,3,0,src.length-1)); } /** * * 二分查找<a href="http://lib.csdn.net/base/datastructure" class='replace_word' title="算法与数据结构知识库" target='_blank' style='color:#df3434; font-weight:bold;'>算法</a> * * * * @param srcArray * 有序数组 * * @param des * 查找元素 * * @return des的数组下标,没找到返回-1 */ public static int binarySearch(int[] srcArray, int des){ int low = 0; int high = srcArray.length-1; while(low <= high) { int middle = (low + high)/2; if(des == srcArray[middle]) { return middle; }else if(des <srcArray[middle]) { high = middle - 1; }else { low = middle + 1; } } return -1; } /** *二分查找特定整数在整型数组中的位置(递归) *@paramdataset *@paramdata *@parambeginIndex *@paramendIndex *@returnindex */ public static int binarySearch(int[] dataset,int data,int beginIndex,int endIndex){ int midIndex = (beginIndex+endIndex)/2; if(data <dataset[beginIndex]||data>dataset[endIndex]||beginIndex>endIndex){ return -1; } if(data <dataset[midIndex]){ return binarySearch(dataset,data,beginIndex,midIndex-1); }else if(data>dataset[midIndex]){ return binarySearch(dataset,data,midIndex+1,endIndex); }else { return midIndex; } } } 快速排序 /* ********************************************************************************** 快速排序 3、实现思路。 1.以第一个关键字 K 1 为控制字,将 [K 1 ,K 2 ,…,K n ] 分成两个子区, 使左区所有关键字小于等于 K 1 ,右区所有关键字大于等于 K 1 , 最后控制字居两个子区中间的适当位置。在子区内数据尚处于无序状态。 2.递归处理左右子区 *************************************************************************************/ package com.example; import java.util.Arrays; public class example8 { public static void main(String[] args) throws Exception { int[] arr = new int[10]; for(int i = 0; i<arr.length; i++){ arr[i] = (int)(Math.random() * 100 + 1); } System.out.println(Arrays.toString(arr)); quickSort(arr, 0, arr.length - 1); System.out.println(Arrays.toString(arr)); //数组被改变 } public static void quickSort(int[] arr, int left, int right){ if(left < right){ int pivotloc = partition(arr, left, right); // System.out.print(left + ":" + right); //left , right 不变 // System.out.println(Arrays.toString(arr)); //数组被改变 quickSort(arr, left, pivotloc - 1); quickSort(arr, pivotloc + 1, right); } } public static int partition(int[] arr, int left, int right){ int pivotkey = arr[left]; while(left < right){ while(left < right && pivotkey <= arr[right]) right--; if(left < right) arr[left++] = arr[right]; while(left < right && pivotkey >= arr[left]) left++; if(left < right) arr[right--] = arr[left]; } arr[left] = pivotkey; return left; } }