这阵子同学投实习,面试了百度,由于我还没有投实习所以仅仅能事后问他都有哪些面试题。他记得的大概几个,字符串翻转、字符替代、一亿数据中找出100个最大数(似乎有内存限制)、八皇后问题和二叉树查找类似的问题。具体记不大清了,这些算法题都还是算是比較经典的,网上也有非常多具体解释,我也试着想想这些问题怎么解,针对这几个题解法罗列于此,希望对童鞋们有所帮助。如有不正确的地方,欢迎指正。
1、字符串翻转。
解法:七种java实现方法:
import java.util.Stack; public class StringReverse { //折半递归 public static String reverse1(String s) { int length = s.length(); if (length <= 1) return s; String left = s.substring(0, length / 2); String right = s.substring(length / 2, length); return reverse1(right) + reverse1(left); } //依次取字符放最前拼接 public static String reverse2(String s) { int length = s.length(); String reverse = ""; for (int i = 0; i < length; i++) reverse = s.charAt(i) + reverse; return reverse; } //字符数组 public static String reverse3(String s) { char[] array = s.toCharArray(); String reverse = ""; for (int i = array.length - 1; i >= 0; i--) reverse += array[i]; return reverse; } //用StringBuffer的reverse方法 public static String reverse4(String s) { return new StringBuffer(s).reverse().toString(); } //对称交换 public static String reverse5(String orig) { char[] s = orig.toCharArray(); int n = s.length - 1; int halfLength = n / 2; for (int i = 0; i <= halfLength; i++) { char temp = s[i]; s[i] = s[n - i]; s[n - i] = temp; } return new String(s); } // public static String reverse6(String s) { char[] str = s.toCharArray(); int begin = 0; int end = s.length() - 1; while (begin < end) { str[begin] = (char) (str[begin] ^ str[end]); str[end] = (char) (str[begin] ^ str[end]); str[begin] = (char) (str[end] ^ str[begin]); begin++; end--; } return new String(str); } //利用栈的先进后出特点 public static String reverse7(String s) { char[] str = s.toCharArray(); Stack<Character> stack = new Stack<Character>(); for (int i = 0; i < str.length; i++) stack.push(str[i]); String reversed = ""; for (int i = 0; i < str.length; i++) reversed += stack.pop(); return reversed; } }
2、字符串替代方法:例非常长的字符串中若干个空格,替换为逗号“,”。
解法:(1)word等文本编辑工具CTRL+F进行查找替换:【比較笨,适合没有编程环境的电脑】
步骤一:在替换中“查找内容”填两个连续空格“ ”,在“替换为”填上一个空格“ ”。狂点“所有替换”直到“0处替换”。这时所有的抖个空格都变成了一个空格。
步骤二:在“查找内容”填上一个空格“ ”,在“替换为”填上须要终于替换的字符如题中的逗号“,”。完毕。
(2)在linux操作系统中可採用shell脚本处理:【方便快捷的好方法啊!!!】
语句:sed '/ +/s//,/g' file1.txt>file2.txt
解释:用sed语句将文件file1.txt中的若干个空格替换为逗号“,”,存储在文件file2.txt中。
(3)java编程实现:
package com.melina; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Preprocess { /** * @param args */ public static void main(String[] args) { String regEx = "[' ']+"; // 一个或多个空格 Pattern p = Pattern.compile(regEx); try { String encoding = "gbk"; // 字符编码(可解决中文乱码问题 ) File file = new File("E:/hadoop/bill.txt"); if (file.isFile() && file.exists()) { InputStreamReader read = new InputStreamReader(new FileInputStream(file), encoding); BufferedReader bufferedReader = new BufferedReader(read); FileOutputStream out = null; out = new FileOutputStream(new File("E:/hadoop/bill1.txt")); String lineTXT = null; lineTXT = bufferedReader.readLine();//去掉第一行 的字段名 int count = 0; while ((lineTXT = bufferedReader.readLine()) != null) { //count += 1; Matcher m = p.matcher(lineTXT); //String str = count + "," + m.replaceAll(",").trim();//输出行号 String str = m.replaceAll(",").trim(); //将若干个空格替换为逗号“,” System.out.println(str.substring(0, str.length()-1)); //out.write((str.substring(0, str.length()-1)+" ").getBytes()); if(count == 0) { out.write((str.substring(0, str.length()-1)).getBytes()); } else { out.write(13); out.write((str.substring(0, str.length()-1)).getBytes()); } count += 1; } read.close(); out.close(); } else { System.out.println("找不到指定的文件!"); } } catch (Exception e) { System.out.println("读取文件内容操作出错"); e.printStackTrace(); } } }
3、从一亿数据中找出最大的100个数。
解法:(1)将一亿个数装在数组里面直接用java的各种排序插入算法实现:
注意内存溢出的问题,能够设置JVM
先生成包括一亿个随机数的数组:
int[] test =new int[100000000];//1亿个数字 Random r = new Random(); for(int i=0;i<test.length;i++){ test[i] = r.nextInt(test. length * 2); }
然后对每个数组里面的数採用插入算法:
for(int i=0;i<test.length;i++){ insert(test[i]); }
几个不同的插入算法:
public void insert(int a){ //维持数组从大到小排序 for(int i=0;i<data.length;i++){ if(a>data [i]){//a放到data[i].同一时候i開始到100,后移 for(int j=data .length -1 ;j>i;j--){ data[j] = data[j-1]; } data[i] = a; break; } } //printResult(); } public void insert1(int a){ //由于数组已经是从大到小排序,因此从尾部到头部開始,大的插入,小的话则继续 if(a < data [data .length - 1]) return;//比最小的还小则退出 for(int i =0;i<data.length; i++){ if(a > data [i]){ for(int j=data .length -1 ;j>i;j--){ data[j] = data[j-1]; } data[i] = a; break; } } } public void insert2(int a){ //linkNode插入 LinkNode t = sdata; LinkNode pre = null; int idx = 0; while(t!= null ){ idx++; if(idx >= 100){ t.setNext( null); break; } if(a > t.getData()){ LinkNode temp = new LinkNode(a); temp.setNext(t); if(sdata == t)sdata = temp; if(pre != null )pre.setNext(temp); //printLinkResult(); break; } pre = t; t = t.getNext(); //printLinkResult(); } }
当中链表的定义:
public class LinkNode { private int data ; private LinkNode next ; public LinkNode(int data) { this.data = data; this.next = null; } public LinkNode getNext() { return next ; } public void setNext(LinkNode next) { this.next = next; } public int getData() { return data ; } public void setData(int data) { this.data = data; } }
(2)假设内存有限,一亿的数据无法直接所有放在内存中处理,这时就须要採取另外的措施了,一部分一部分地加到内存处理。
(3)如果这一亿个数能够导入数据库中,使用sql语句:【还没有尝试,不知是否可行或者效率怎样】
select * from table order by 字段名 desc limit 100;
(4)如果这一亿数据在文件里,mapreduce程序处理:【待尝试】
4、八皇后问题
解法:【这个问题已经非常经典了,主要是有循环和递归方法。代码量大,主要摘抄自网络】
/** 问题描写叙述:在一个8×8国际象棋盘上,有8个皇后,每一个皇后占一格; 要求皇后间不会出现相互“攻击”的现象,即不能有两个皇后处在同一行、同一列或同一对角线上。 问共同拥有多少种不同的方法。 基本思路: 定义一个用来存放解的一维数组int[] cellpos = new int[9],为直观起见,约定下标从1開始。 数组的下标表示皇后所在的列,值表示皇后当前列所在的行。 定义一个列指示器pointer,用于指示当前程序已经求解到第几列。 先将pointer置为1,cellpos[1]置为1,即程序从第一列第一行開始求解。 当cellpos[1]>8时表示已经将解所有都求出来了. 为了降低部分时间复杂度,我们能够再给第二列赋一个初值,大家能够想想这个初值应该是多少. 给第二列赋完初值后,列指示器pointer应该等于3,即程序从第三列開始扫描, 此时i从第三列的第一行一直扫描到第8行.当皇后位于i行时,比方说如今第一列第一 行有一个皇后,第二列第三行有一个皇后,那么i肯定不能等于1,2,3,4. 然后如果cellpos[3] = 5,pointer++,列指示器跳到下一列,继续扫描,当pointer==8时, 说明已经扫描完了,当然扫描的时候i可能>8说明没有解,这时候就得加一个推断, 我们如果找到了最后一列的解, 就将这组解打印出来,然后pointer--,回到倒数第二列,并将cellpos[pointer]++, 由于倒数第二列的前面几行已经扫描过了.这时候别忘了清理最后一列,由于倒数第二列 的皇后位置已经变了,那么最后一列应该又一次从第一行開始扫描,想想为什么. 继续扫描解,当倒数第二列皇后位置也>8时,pointer--,回到倒数第三列,当然要 cellpos[pointer]++,而且将后面几列清理干净. 程序一直这样循环的执行, 直到cellpos[1]>8. */ public class Queen { //定义两个int型变量,用于下面循环程序。 private int i,k; //列指示器 private int pointer = 1; //解 int[] cellpos = new int[9]; public Queen() { cellpos[pointer] = 1; cellpos[2] = 3; pointer = 3; //给第二列之后的列赋一个初值1,由于默认是0,而我们约定的是从1開始. clean(2); while(cellpos[1] <= 8) { /** * 特殊点第一列,这里不写cellpos[pointer]++; * 是由于后面的程序中已经加过了. */ //if(pointer == 1) { //cellpos[pointer]++; //pointer++; //continue; //} /** * 特殊点第八行,这里为什么还要加一个推断呢 * 或许你会问后面不是有i>8推断吗?试想一下,当倒数第二列 * 正好等于8,求完解后,回到倒数第二列, * 而且后面的程序会使倒数第二列加1,如今还觉得它多余么. */ if(cellpos[pointer]>8) { pointer--; cellpos[pointer]++; //清理 clean(pointer); continue; } /** * 扫描 */ for(i=cellpos[pointer]; i<=8; i++) if(canStay(i)) break; if(i>8) { pointer--; cellpos[pointer]++; //清理 clean(pointer); continue; }else{ cellpos[pointer] = i; } if(pointer==8) { //将解打印出来 printQueen(); pointer--; cellpos[pointer]++; //清理 clean(pointer); }else{ pointer++; } } } private boolean canStay(int ci) { //行扫描,推断同一行是否有其他皇后. for(k=1; k<pointer; k++) if(cellpos[k]==ci) return false; //对角线扫描,推断对角线上是否有其他皇后.注意有两条对角线. for(k=1; k<pointer; k++) if((ci==cellpos[k]+(pointer-k)) || (ci==cellpos[k]-(pointer-k))) return false; return true; } private void clean(int pointer) { for(k=pointer+1; k<9; k++) cellpos[k] = 1; } private void printQueen() { for(k = 1; k<9; k++) { System.out.print(""+cellpos[k]); if(k!=8) System.out.print(","); } System.out.println(); } public static void main(String[] args) { new Queen(); } }
八皇后问题的另外两种实现:
循环方式:
package EightQueens; public class EightQueensNotRecursive { private static final boolean AVAILABLE = true; private int squares = 8, norm = squares - 1; private int positionInRow[] = new int[squares]; private int p=-1; private boolean[] rows = new boolean[squares]; private boolean[] column = new boolean[squares]; private boolean[] leftDiagonal = new boolean[2 * squares - 1]; private boolean[] rightDiagonal = new boolean[2 * squares - 1]; private static int howMany = 0; public EightQueensNotRecursive() { // To complete the initialization work for the // column,leftDiagonal,rigthDiagonal. for (int i = 0; i < squares; i++) { rows[i] = AVAILABLE; column[i] = AVAILABLE; positionInRow[i] = -1; } for (int i = 0; i < 2 * squares - 1; i++) { leftDiagonal[i] = AVAILABLE; rightDiagonal[i] = AVAILABLE; } } public void printResults(int[] columns) { int row, col; System.out.println(" 八皇后问题的第 " + howMany + " 种解法"); System.out.print(" 八皇后问题的结果为: "); for (int e : columns) { System.out.print(e); } System.out.println(" 详细的图演示样例如以下图所看到的: "); for (row = 0; row < squares; row++) { for (col = 0; col < squares; col++) { if (col == positionInRow[row]) { System.out.print("@"); } else { System.out.print("*"); } } System.out.println(); } System.out.println(); } public void putQueen() { int row=0, col; while (true) { for (col = p + 1; col < squares; col++) { if(rows[row]==AVAILABLE&&column[col]==AVAILABLE&&leftDiagonal[row+col]==AVAILABLE&&rightDiagonal[row-col+norm]==AVAILABLE) { break; } } //在当前的行里面找到了能够放置皇后的位置 if(col<squares) { rows[row]=!AVAILABLE; column[col]=!AVAILABLE; leftDiagonal[row+col]=!AVAILABLE; rightDiagonal[row-col+norm]=!AVAILABLE; positionInRow[row]=col; p=col; }else//假设当前行没办反放置皇后了,那么回溯 { if(row>0)//到前一行 { row--; p=positionInRow[row]; rows[row]=AVAILABLE; column[p]=AVAILABLE; leftDiagonal[row+p]=AVAILABLE; rightDiagonal[row-p+norm]=AVAILABLE; positionInRow[row]=-1; continue; }else { break; } } if(row==squares-1) { howMany+=1; printResults(positionInRow); p=positionInRow[row]; rows[row]=AVAILABLE; column[p]=AVAILABLE; leftDiagonal[row+p]=AVAILABLE; rightDiagonal[row-p+norm]=AVAILABLE; positionInRow[row]=-1; continue; } else { row++; p=-1; continue; } } } public static void main(String args[]) { EightQueensNotRecursive eightQueens=new EightQueensNotRecursive(); eightQueens.putQueen(); System.out.println(" 皇后问题一共同拥有 "+howMany+"种解法"); } }
递归方式:
package EightQueens; public class EightQueensRecursive { private static final boolean AVAILABLE=true; private int squares=8,norm=squares-1; private int positionInRow[]=new int[squares]; private boolean[] column=new boolean[squares]; private boolean[] leftDiagonal=new boolean[2*squares-1]; private boolean[] rightDiagonal=new boolean[2*squares-1]; private static int howMany=0; public EightQueensRecursive(){ //To complete the initialization work for the column,leftDiagonal,rigthDiagonal. for(int i=0;i<squares;i++){ column[i]=AVAILABLE; positionInRow[i]=-1; } for(int i=0;i<2*squares-1;i++){ leftDiagonal[i]=AVAILABLE; rightDiagonal[i]=AVAILABLE; } } public void printResults(int[] columns){ int row,col; System.out.println(" 八皇后问题的第 "+howMany+" 种解法"); System.out.print(" 八皇后问题的结果为: "); for(int e:columns){ System.out.print(e); } System.out.println(" 详细的图演示样例如以下图所看到的: "); for(row=0;row<squares;row++){ for(col=0;col<squares;col++){ if(col==positionInRow[row]){ System.out.print("@"); }else{ System.out.print("*"); } } System.out.println(); } System.out.println(); } public void putQueen(int row){ //假设前面已经得到了一个可行解 for(int i=0;i<squares;i++) { if(row>squares-1) break; if(column[i]==AVAILABLE&&leftDiagonal[row+i]==AVAILABLE&&rightDiagonal[row-i+norm]==AVAILABLE) { positionInRow[row]=i; column[i]=!AVAILABLE; leftDiagonal[row+i]=!AVAILABLE; rightDiagonal[row-i+norm]=!AVAILABLE; if(row<squares-1){ putQueen(row+1); }else { howMany+=1; printResults(positionInRow); } column[i]=AVAILABLE; leftDiagonal[row+i]=AVAILABLE; rightDiagonal[row-i+norm]=AVAILABLE; } } } public static void main(String args[]){ EightQueensRecursive eightQueens=new EightQueensRecursive(); eightQueens.putQueen(0); System.out.println(" 皇后问题一共找到了 "+howMany+"组解。"); } }
5、二叉树路径查找,并打印路径。
解法:直接上代码,两个java文件:
createBTree.java:
package cn.melian.binaryTree; import java.util.Stack; import java.util.StringTokenizer; public class createBTree { //创建一棵二叉树 public static BinaryTree createBTree(BinaryTree tree, StringTokenizer tokenizer){ if (tokenizer.hasMoreTokens()){ String str_data = tokenizer.nextToken(); tree = new BinaryTree(); if (str_data.equals("#" )){ return null; } tree. data = Integer. parseInt(str_data); //将值赋给节点 tree. leftnode = createBTree(tree. leftnode, tokenizer); tree. rightnode = createBTree(tree. rightnode , tokenizer); return tree; } return null; } //搜索和为指定值得全部路径并打印出来 public static void searchPrintTree( int value, int sum, BinaryTree tree, Stack<Integer> stack){ if (null != tree){ sum += tree. data; stack.push(tree. data); if (sum == value && tree.leftnode == null && tree. rightnode == null ){ for (int i:stack){ System. out .print(i+" " ); } System. out .println(); } searchPrintTree(value, sum, tree. leftnode, stack); searchPrintTree(value, sum, tree. rightnode, stack); stack.pop(); } } //main函数 public static void main(String[] args){ int value = 22; int sum = 0; String str_in = "10 5 4 # # 7 # # 12 # #" ; //String[] str_arr = str_in.split(" "); StringTokenizer tokenizer = new StringTokenizer(str_in, " " ); BinaryTree tree = new BinaryTree(); Stack<Integer> stack = new Stack<Integer>(); tree = createBTree(tree, tokenizer); searchPrintTree(value, sum, tree, stack); } }
二叉树的定义:
BinaryTree.java:
package cn.melian.binaryTree; public class BinaryTree { public int data ; public BinaryTree leftnode ; public BinaryTree rightnode ; }
如上面main函数的打印结果是:
10 5 7
10 12
OK!GOOD LUCK!小伙伴们加油!