BAT、网易、蘑菇街面试题整理-7

数据结构与算法

1. 链表与数组。

2. 队列和栈,出栈与入栈。

3. 链表的删除、插入、反向。

4. 字符串操作。

http://blog.csdn.net/WINCOL/article/details/4795369


5. Hash表的hash函数,冲突解决方法有哪些。

6. 各种排序:冒泡、选择、插入、希尔、归并、快排、堆排、桶排、基数的原理、平均时间复杂度、最坏时间复杂度、空间复杂度、是否稳定。

BAT、网易、蘑菇街面试题整理-7_第1张图片BAT、网易、蘑菇街面试题整理-7_第2张图片BAT、网易、蘑菇街面试题整理-7_第3张图片BAT、网易、蘑菇街面试题整理-7_第4张图片

      package com.algorithmz.sort.imple;


import com.algorithmz.sort.Sort;




/**
 * 冒泡排序
 * @author jianina
 *
 */
public class BubbleSort extends Sort{


    /**
     * 简单冒泡排序
     */
@Override
public void sort(int[] array) {
for (int i = 0; i < array.length-1; i++) {
for (int j = i+1; j < array.length; j++) {
if(array[j]int temp =array[i];
array[i]=array[j];
array[j]=temp;
}
}

}

}



/**
* 优化算法2
* 优化不明显 ,反而比算法1还要慢
* @param array
*/
public void sort2(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j =array.length-2; j >=i; j--) {
if(array[j]>array[j+1]){
int temp =array[j];
array[j]=array[j+1];
array[j+1]=temp;
}
}

}

}



/**
* 优化算法3
* 只有当每个内循环排序完之后,便可以得出正确的排序结果,则后面的循环不再进行,
* 否则和算法1、算法2在时间上没有多大差别
* @param array
*/
public void sort3(int[] array) {
boolean flag=true;
for (int i = 0; i < array.length&&flag; i++) {
flag=false;
for (int j =array.length-2; j >=i; j--) {
if(array[j]>array[j+1]){
int temp =array[j];
array[j]=array[j+1];
array[j+1]=temp; 
flag=true;
}
}

}

}






package com.algorithmz.sort.imple;


import com.algorithmz.sort.Sort;


public class SimpleSelectionSort  extends  Sort{
    

/**
* 选择排序算法
* 每个位置看准了最小的才进行转换位置,减少了多余的交换位置
* 20万条数据量,冒泡50秒,选择15秒
*/
@Override
public void sort(int[] array) {
// TODO Auto-generated method stub
int min;
for (int i = 0; i < array.length-1; i++) {
 
min=i;
for (int j = i+1; j < array.length; j++) {

if(array[j]min=j;
}
}

 
if(i!=min){
  int temp=array[i];
  array[i]=array[min];
  array[min]=temp;


}
}


}




   package com.algorithmz.sort.imple;


import com.algorithmz.sort.Sort;


/**
 * 插入排序
 * @author jianina
 *
 */
public class InsertSort extends Sort{


@Override
public void sort(int[] array) {
// TODO Auto-generated method stub
for (int i = 1; i < array.length; i++) {
for (int j = i; j>0&&compare(array[j], array[j-1]); j--) {
changePostion(j,j-1, array);
}
}
}


public  void  sort2(int[] array){
int j;
for (int i = 2; i < array.length; i++) {

if(array[i]array[0]=array[i];
for (j = i-1;array[j]>array[0]; j--) {
array[j+1]=array[j];
}

array[j+1]=array[0];


}

}
}


public void sort3(int[] array){

for (int i =1; i < array.length; i++) {
int key=array[i];
int j=i-1;
while(j>=0&&array[j]>key){
array[j+1]=array[j];
j-=1;

}

array[j+1]=key;
}
}



/**
* 递归实现
* @param array
*/
public void sort4(int[] array,int n){
if(n>1){
sort4(array,n-1);
}

if(array[n]changePostion(n, n-1,array);
sort4(array, n-1);
}

}

}


package com.algorithmz.sort.imple;


import com.algorithmz.sort.Sort;




/**
 * 希尔排序
 * @author jianina
 *
 */
public class ShellSort extends Sort{


@Override
public void sort(int[] array) {
int length=array.length;

   int i, j, gap;  
 
   for (gap = length / 2; gap > 0; gap /= 2)  
       for (i = gap; i            for (j = i - gap; j >= 0 && array[j] > array[j + gap]; j -= gap)  
              changePostion(j, j + gap, array);


}


public void sort2(int[] array){
int length=array.length;
int i,j,gap;

for (gap= length/2;gap>0; gap/=2) {
for (i = gap; ifor (j= i-gap; j>=0&&array[j]>array[j+gap]; j-=gap) {
changePostion(j, j+gap, array);
}
}

}

}


}


package com.algorithmz.sort.imple;


import com.algorithmz.sort.Sort;


/**
 * 归并排序
 * @author jianina
 *
 */
public class MergeSort extends Sort{
   public static void main(String[] args) {
int[] array=new int[]{1,3,4,5,2,4,6,8};
merge(array, 0, 3, 7);
for (int i : array) {
System.out.println(i);
}
}
@Override
public void sort(int[] array) {
// TODO Auto-generated method stub
     sort(array,0,array.length-1);
}


public void sort(int[] array,int p,int r) {
// TODO Auto-generated method stub
     if(p     int q=(p+r)/2;
     sort(array,p,q);
     sort(array,q+1,r);
     merge2(array, p, q, r);
     }
}

public static void merge(int[] array,int p,int q,int r){
int n1=(q-p)+1;
int n2=r-q;

int[] d1=new int[n1+1];
int[] d2=new int[n2+1];

for(int i=0;id1[i]=array[p+i];

}

for(int i=0;id2[i]=array[q+i+1];

}

d1[n1]=Integer.MAX_VALUE;
d2[n2]=Integer.MAX_VALUE;

int i=0;
int j=0;
for(int k=p;k<=r;k++){
if(d1[i]<=d2[j]){
array[k]=d1[i];
i++;
}else{
array[k]=d2[j];
j++;
}
}


}


public static void merge2(int[] array,int p,int q,int r){
int n1=(q-p)+1;
int n2=r-q;

int[] d1=new int[n1];
int[] d2=new int[n2];

for(int i=0;id1[i]=array[p+i];

}

for(int i=0;id2[i]=array[q+i+1];

}



int i=0;
int j=0;
for(int k=p;k<=r;k++){

if(i>=n1){
array[k]=d2[j++];
continue;
}else if(j>=n2){
array[k]=d1[i++];
continue;
}

if(d1[i]<=d2[j]){
array[k]=d1[i];
i++;
continue;
}

if(d1[i]>d2[j]){
array[k]=d2[j];
j++;
continue;
}




}


}
       
}


 package com.algorithmz.sort.imple;


 

package com.algorithmz.sort.imple;


import com.algorithmz.sort.Sort;


/**
 * 快速排序
 * @author jianina
 *
 */
public class QuickSortM  extends Sort{
   public int changeCount;
@Override
public void sort(int[] array) {
// TODO Auto-generated method stub
sort(array, 0, array.length-1);
}



public void sort(int[] array,int low,int high) {
// TODO Auto-generated method stub
if(low int mid=partition(array, low, high);
sort(array,low,mid-1);
sort(array,mid+1,high);


}
}


/**while循环判断条件加不加等号情况分析:
* 不加双等 交换次数:378次,但是不加等号的速度最快
* 加一个双等 交换次数:174, 
* 条件加双等 交换次数149, 


*/


public int partition(int[] array,int low,int high){
int pivotkey=array[low];

while(low
while(lowpivotkey){
high--;
}

if(low array[low]=array[high];
changeCount++;
low++;
}

while(lowarray[low]){
low++;
}
if(low array[high]=array[low];
changeCount++;
high--;
}



}

array[low]=pivotkey;
return low;
}


}



7. 快排的partition函数与归并的Merge函数。

归并Merge

public static void merge2(int[] array,int p,int q,int r){
int n1=(q-p)+1;
int n2=r-q;

int[] d1=new int[n1];
int[] d2=new int[n2];

for(int i=0;id1[i]=array[p+i];

}

for(int i=0;id2[i]=array[q+i+1];

}



int i=0;
int j=0;
for(int k=p;k<=r;k++){

if(i>=n1){
array[k]=d2[j++];
continue;
}else if(j>=n2){
array[k]=d1[i++];
continue;
}

if(d1[i]<=d2[j]){
array[k]=d1[i];
i++;
continue;
}

if(d1[i]>d2[j]){
array[k]=d2[j];
j++;
continue;
}




}


}


快拍parttition

public int partition(int[] array,int low,int high){
int pivotkey=array[low];

while(low
while(lowpivotkey){
high--;
}

if(lowarray[low]=array[high];
changeCount++;
low++;
}

while(lowarray[low]){
low++;
}
if(lowarray[high]=array[low];
changeCount++;
high--;
}



}

array[low]=pivotkey;
return low;
}


8. 对冒泡与快排的改进。

冒泡优化:冒泡优化加上flag标识

package com.algorithmz.sort.imple;


import com.algorithmz.sort.Sort;


/**
 * 快速排序
 * @author jianina
 *
 */
public class QuickSortM  extends Sort{
   public int max_length_insert_sort=7;
   public InsertSort insertSort=new InsertSort();
@Override
public void sort(int[] array) {
// TODO Auto-generated method stub
sort(array, 0, array.length-1);
}



public void sort(int[] array,int low,int high) {
// TODO Auto-generated method stub







if(lowint pivoykey=partition(array, low, high);
sort(array,low,pivoykey-1);
sort(array,pivoykey+1,high);

}



}

/**
* 优化1加上阈值,当数组长度低于阈值是采用插入排序
* @param array
* @param low
* @param high
*/


public void sort2(int[] array) {
// TODO Auto-generated method stub
sort(array, 0, array.length-1);


}

public void sort2(int[] array,int low,int high) {
// TODO Auto-generated method stub
int pivoykey;
if((high-low)>max_length_insert_sort){
pivoykey=partition(array, low, high);
sort2(array,low,pivoykey-1);
sort2(array,pivoykey+1,high);
}
else{
InsertSort.sort4(array);
}


}




public void sort3(int[] array) {
// TODO Auto-generated method stub
sort3(array, 0, array.length-1);


}

/**
* 优化2再加上阈值的同时,采用尾递归,减少递归深度
* @param array
* @param low
* @param high
*/
public void sort3(int[] array,int low,int high) {
// TODO Auto-generated method stub
int pivoykey;
if((high-low)>max_length_insert_sort){


while (lowpivoykey=partition(array, low, high);
sort3(array,low,pivoykey-1);
low=pivoykey+1;
}
}
else{
InsertSort.sort4(array);
}


}


/**while循环判断条件加不加等号情况分析:
* 不加双等 交换次数:378次,但是不加等号的速度最快
* 加一个双等 交换次数:174, 
* 条件加双等 交换次数149, 


*/


public int partition(int[] array,int low,int high){
int pivotkey=array[low];

while(low
while(lowpivotkey){
high--;
}

if(lowarray[low]=array[high];

low++;
}

while(lowarray[low]){
low++;
}
if(lowarray[high]=array[low];

high--;
}



}

array[low]=pivotkey;
return low;
}


}



9. 二分查找,与变种二分查找。

package com.algorithmz.binarysearch;


public class BinarySearch {
public static void main(String[] args) {
int[] array=new int[]{1,2,53,6,4,8};
System.out.println(binarySearch(array,-1));
}

public static int binarySearch(int[] a,int key) {
        int low = 0;
        int high = a.length - 1;
        int mid = 0;
        while(low <= high){
            mid = (low + high) / 2;
            if(a[mid] == key) return mid;
            if(a[mid] > key) high = mid - 1;
            if(a[mid] < key) low = mid + 1;
        }
        return -1;
    }


10. 二叉树、B+树、AVL树、红黑树、哈夫曼树。

http://blog.sina.com.cn/s/blog_9cbb6a210102v5dc.html

http://blog.csdn.net/dongdong_java/article/details/9128983

http://blog.csdn.net/quitepig/article/details/8041308




11. 二叉树的前中后续遍历:递归与非递归写法,层序遍历算法。

package com.algorithmz.binarytree;


import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Stack;


public class BinaryTree {

 public static void main(String[] args) {
BinaryTree binaryTree=new BinaryTree();
binaryTree.createBinaryTree();
binaryTree.levelTravel(binaryTree.root);
}

     private TreeNode root=null;
     
     public BinaryTree(){
    root=new TreeNode(1,"rootNode(A)");
     }
     
     public BinaryTree(TreeNode root){
    this.root=root;
     
     }
     
     
     public void createBinaryTree(){
    TreeNode b=new TreeNode(2,"B");
    TreeNode c=new TreeNode(3,"C");
    TreeNode d=new TreeNode(4,"D");
    TreeNode e=new TreeNode(5,"E");
    TreeNode f=new TreeNode(6,"F");
     
    root.leftNode=b;
    root.rightNode=c;
    root.leftNode.leftNode=d;
    root.leftNode.rightNode=e;
    root.rightNode.rightNode=f;
     
   
     
     }
     
     public boolean isEmpty(){
    return root==null;
     }
     
     
     public int height(){
    return height(root);
     }
     
     
     public int height(TreeNode  treeNode){
    if(treeNode==null){
    return 0;
    }
    int i=height(treeNode.leftNode);
    int j=height(treeNode.rightNode);
     
     
    return i      
     }
     
     
     public int size(){
     
    return size(root);
     }
    
     
     public int size(TreeNode treeNode){
     
    if(treeNode==null){
    return 0;
    }
     
    return 1+size(treeNode.leftNode)+size(treeNode.rightNode);
     
     }
     
    
     public void visted(TreeNode subTree){
    subTree.isVisted=true;
    System.out.println("key:"+subTree.key+"  name:"+subTree.data);
     }
     
     
     
 
     /**
      * 前序遍历
      * @param subTree
      */
     public void preOrder(TreeNode subTree){
    if(subTree!=null){
    visted(subTree);
    preOrder(subTree.leftNode);
    preOrder(subTree.rightNode);
    }
     
     }
     
     
     
     /**
      * 前序遍历
      * @param subTree
      */
     public void inOrder(TreeNode subTree){
    if(subTree!=null){
   
    inOrder(subTree.leftNode);
    visted(subTree);
    inOrder(subTree.rightNode);
    }
     
     }
     
     
     public void postOrder(TreeNode subTree){
    if(subTree!=null){
    postOrder(subTree.leftNode);
    postOrder(subTree.rightNode);
    visted(subTree);
    }
     }
     
     
     /**
      * 二叉树非递归遍历实现
      * @param subTree
      */
     public void nonRecPreOrder(TreeNode subTree){
    Stack  stack=new Stack();
    TreeNode node=subTree;
    while(node!=null||stack.size()>0){
    while(node!=null){
    visted(node);
    stack.push(node);
    node=node.leftNode;
     
    }
     
    node=stack.pop();
    node=node.rightNode;
     
    }
     
     
     }
     
     
     
     /**
      * 二叉树中序非递归遍历
      * @param subTree
      */
     public void nonRecInOrder(TreeNode subTree){
    Stack stack =new Stack();  
         TreeNode node =subTree;  
         while(node!=null||stack.size()>0){  
             //存在左子树  
             while(node!=null){  
                 stack.push(node);  
                 node=node.leftNode;  
             }  
             //栈非空  
             if(stack.size()>0){  
                 node=stack.pop();  
                 visted(node);  
                 node=node.rightNode;  
             }  
         }  
     
     }
     
     public  void nonRecPostOrder(TreeNode p){
     Stack stack=new Stack();  
          TreeNode node =p;  
          while(p!=null){  
              //左子树入栈  
              for(;p.leftNode!=null;p=p.leftNode){  
                  stack.push(p);  
              }  
              //当前结点无右子树或右子树已经输出  
              while(p!=null&&(p.rightNode==null||p.rightNode==node)){  
                  visted(p);  
                  //纪录上一个已输出结点  
                  node =p;  
                  if(stack.empty())  
                      return;  
                  p=stack.pop();  
              }  
              //处理右子树  
              stack.push(p);  
              p=p.rightNode;  
          }
     
     
     }
       
       
       
     /** 
      *  
      * @param root 树根节点 
      * 层序遍历二叉树,用队列实现,先将根节点入队列,只要队列不为空,然后出队列,并访问,接着讲访问节点的左右子树依次入队列 
      */  
     public static void levelTravel(TreeNode root){  
         if(root==null)return;  
         Queue q=new LinkedList();  
         q.add(root);  
         while(!q.isEmpty()){  
        TreeNode temp =  q.poll();  
             System.out.println(temp.data);  
             if(temp.leftNode!=null)
            q.add(temp.leftNode);  
             if(temp.rightNode!=null)
            q.add(temp.rightNode);  
         }  
     }  
     
     
     /** 
      *  
      * @param root 树根节点 
      * 利用栈实现循环先序遍历二叉树 
      * 这种实现类似于图的深度优先遍历(DFS) 
      * 维护一个栈,将根节点入栈,然后只要栈不为空,出栈并访问,接着依次将访问节点的右节点、左节点入栈。 
      * 这种方式应该是对先序遍历的一种特殊实现(看上去简单明了),但是不具备很好的扩展性,在中序和后序方式中不适用 
      */  
     public static void preOrderStack_1(TreeNode root){  
         if(root==null)return;  
         Stack s=new Stack();  
         s.push(root);  
         while(!s.isEmpty()){  
        TreeNode temp=s.pop();  
             System.out.println(temp.data);  
             if(temp.rightNode!=null) s.push(temp.rightNode);  
             if(temp.leftNode!=null) s.push(temp.leftNode);  
         }  
     }  
     /** 
      *  
      * @param root 树的根节点 
      * 利用栈模拟递归过程实现循环先序遍历二叉树 
      * 这种方式具备扩展性,它模拟递归的过程,将左子树点不断的压入栈,直到null,然后处理栈顶节点的右子树 
      */  
     public static void preOrderStack_2(TreeNode root){  
         if(root==null)return;  
         Stack s=new Stack();  
         while(root!=null||!s.isEmpty()){  
             while(root!=null){  
                 System.out.println(root.data);  
                 s.push(root);//先访问再入栈  
                 root=root.leftNode;  
             }  
             root=s.pop();  
             root=root.leftNode;//如果是null,出栈并处理右子树  
         }  
     }  
     /** 
      *  
      * @param root 树根节点 
      * 利用栈模拟递归过程实现循环中序遍历二叉树 
      * 思想和上面的preOrderStack_2相同,只是访问的时间是在左子树都处理完直到null的时候出栈并访问。 
      */  
     public static void inOrderStack(TreeNode root){  
         if(root==null)return;  
         Stack s=new Stack();  
         while(root!=null||!s.isEmpty()){  
             while(root!=null){  
                 s.push(root);//先访问再入栈  
                 root=root.leftNode;  
             }  
             root=s.pop();  
             System.out.println(root.data);  
             root=root.rightNode;//如果是null,出栈并处理右子树  
         }  
     }  
     /** 
      *  
      * @param root 树根节点 
      * 后序遍历不同于先序和中序,它是要先处理完左右子树,然后再处理根(回溯),所以需要一个记录哪些节点已经被访问的结构(可以在树结构里面加一个标记),这里可以用map实现 
      */  
     public static void postOrderStack(TreeNode root){  
         if(root==null)return;  
         Stack s=new Stack();  
         Map map=new HashMap();   
         s.push(root);  
         while(!s.isEmpty()){  
        TreeNode temp=s.peek();  
             if(temp.leftNode!=null&&!map.containsKey(temp.leftNode)){  
                 temp=temp.leftNode;  
                 while(temp!=null){  
                     if(map.containsKey(temp))break;  
                     else s.push(temp);  
                     temp=temp.leftNode;  
                 }  
                 continue;  
             }  
             if(temp.rightNode!=null&&!map.containsKey(temp.rightNode)){  
                 s.push(temp.rightNode);  
                 continue;  
             }  
             TreeNode t=s.pop();  
             map.put(t,true);  
             System.out.println(t.data);  
         }  
     }  
 
       
       
       
       
       
       private static class TreeNode{
      
      private int key;
      private String data;
      private boolean isVisted;
      private TreeNode leftNode;
      private TreeNode rightNode;
      
      public  TreeNode(){
      
      }
      
            public  TreeNode(int key,String data){
      this.key=key;
      this.data=data;
      
      }
            
            
            public  TreeNode(int key,String data,TreeNode leftNode,TreeNode rightNode){
        this.key=key;
        this.data=data;
        this.leftNode=leftNode;
        this.rightNode=rightNode;
        
        
        }
      
       }
}

12. 图的BFSDFS算法,最小生成树prim算法与最短路径Dijkstra算法。

13. KMP算法。

http://blog.csdn.net/yutianzuijin/article/details/11954939

14. 排列组合问题。

15. 动态规划、贪心算法、分治算法。(一般不会问到)

16. 大数据处理:类似10亿条数据找出最大的1000个数.........等等

算法的话其实是个重点,因为最后都是要你写代码,所以算法还是需要花不少时间准备,这里有太多算法题,写不全,我的建议是没事多在OJ上刷刷题(牛客网、leetcode等),剑指offer上的算法要能理解并自己写出来,编程之美也推荐看一看。

推荐书籍:《大话数据结构》《剑指offer》《编程之美》

你可能感兴趣的:(BAT、网易、蘑菇街面试题整理-7)