2014百度实习生面试题(部分)详解

这阵子同学投实习,面试了百度,因为我还没有投实习所以只能事后问他都有哪些面试题。他记得的大概几个,字符串翻转、字符替代、一亿数据中找出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)+"\n").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("\n 具体的图示如下图所示: ");
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("\n 具体的图示如下图所示: ");
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!小伙伴们加油!




  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值