秋招手撕代码系列

0.秋招之路似苍茫,不思量,自难忘,千里奔忙,无处话凄凉。笔试面试俱神伤,心似铁,身如钢,雄关不惧,成败自含香。

良心总结:https://www.jianshu.com/p/3f0cd7af370d

 

Table of Contents

1.二分查找

2.归并排序

3. 快速排序

4. 冒泡排序(优化版)

5.拓扑排序

6. 堆排序

7.树的遍历

8.全排列

9. 反转链表

10. 寻找链表的第一个公共节点

11. 合并有序链表

12. 洗牌算法

13. 二叉树的宽度

14. 链表中找环的入口

15.合并两个二叉树

16. 希尔排序

18.求一个子树是否是另一棵树的子树?


1.二分查找

/***
 * 参考资料:https://blog.csdn.net/v_july_v/article/details/7093204
 */
public class Search{

    public static BinarySearch(int nums[],int target){
        int left = 0;
        int right = nums.length-1;
        while(left<=right){
            int middle = left + (right-left)>>1;
            if(nums[middle]target){
                right = middle-1;
            }
            else{
                return middle;
            }
        }
        return -1;
    }
}

2.归并排序

/***
 * 参考资料:https://blog.csdn.net/jianyuerensheng/article/details/51262984
 */
 public class Mergesort{
    public static Merge(int arr[],int low,int mid,int high){
      int [] tmp = new int[high-low+1];
      int i = low;//左边部分的游标
      int j = mid+1;//右边部分的游标
      int k = 0;
      //逻辑很简单,谁小谁先上
      while (i<=mid&&j<=high) {
          if(arr[i]<=arr[j]){
             tmp[k++] = arr[i++];
          }else{
              tmp[k++] = arr[j++];
          }
      }
      //处理尾巴
      while(i<=mid){
          tmp[k++] = arr[i++];
      }
      //处理尾巴
      while(j<= high){
          tmp[k++] = arr[j++];
      } 
      //覆盖原数组,使其局部有序 
      for(int k2=0;k2

3. 快速排序

/**
 * 参考资料:https://www.jianshu.com/p/3f0cd7af370d
 */
public static void quickSort(int[] arr) {
    qsort(arr, 0, arr.length - 1);
}

private static void qsort(int[] arr, int low, int high) {
    if (low < high) {
        int pivot = partition(arr, low, high);        // 将数组分为两部分
        qsort(arr, low, pivot - 1);                   // 递归排序左子数组
        qsort(arr, pivot + 1, high);                  // 递归排序右子数组
    }
}
//这种方法没有借助tmp,所以在最终落pivot之前,low处的元素有重复,相当于原数组中的pivot处的值被覆盖掉了
private static int partition(int[] arr, int low, int high) {
    int pivot = arr[low];               // 枢轴记录
    while (low < high) {
        while (low < high && arr[high] >= pivot) --high;
        arr[low] = arr[high];           // 交换比枢轴小的记录到左端
        while (low < high && arr[low] <= pivot) ++low;
        arr[high] = arr[low];           // 交换比枢轴大的记录到右端
    }
    // 扫描完成,枢轴到位
    arr[low] = pivot;
    // 返回的是枢轴的位置
    return low;
}

4. 冒泡排序(优化版)

/***
 * 参考资料:https://blog.csdn.net/yanxiaolx/article/details/51622286
 */
public static void BubbleSort(int Arr[]){
       for(int i=0;iArr[j+1]){//大的往右边走
                  int tmp = Arr[j];
                  Arr[j] = Arr[j+1];
                  Arr[j+1] = tmp;
                  flag = 1;
                  pos = j;//记住最后交换的位置
              }
           }
           k = pos;
           if(flag == 0)
              return;
       }
    }

5.拓扑排序

/**
 * 参考资料:https://www.cnblogs.com/hapjin/p/5432996.html
 * */
import java.util.*;

public class Vertex{
   int out;
   int in;
   Edge adjoinedges[];
}
public class Edge{
   Vertex start;
   Vertex end;
}
public class Graph{
    Vertex [] vertexs;
    Edge [] edges;
}
public class Solution{

    public static void topoSort(Graph graph){
       Queue q = new Queue<>();
       int count = 0;
       for(Vertex v:graph.vertexs){//将当前拓扑图中入度为0的节点找出来并入栈
           if(v.in==0)
              q.offer(v);
       }
       while(!q.isEmpty()){
          Vertex v = q.poll();
          count++;//统计出队列的节点个数
          for(Edge e : v.adjoinedges){
              if(e.end.in==0){
                  q.offer(e.end);
              }
          }
       }
       if(count!=graph.vertexs.length)//如果所有节点没有出栈则存在环
         System.out.println("circle");
    }
}

6. 堆排序

/**参考资料:https://zhuanlan.zhihu.com/p/52884590
*/
/***
  * 
  * @param arr: 用来存放堆的数组
  * @param n: 堆的最右下角的元素下标
  * @param i:堆的根节点的下标
  */
 public static void heapify(int arr[],int n,int i){
    int largest = i;// 将最大元素设置为堆顶元素
    int l = 2*i +1;// left = 2*i + 1 
    int r = 2*i+2;// right = 2*i + 2 
    if(larr[largest]){//n在这里起到边界判定的作用
        largest = l;
    }
    if(rarr[largest]){//n在这里起到边界判定的作用
        largest= r;
    }
    if(largest!=i){
        swap(arr,i,largest);//将左右子树大的一个和堆顶交换
        heapify(arr, n,largest);//递归构建堆
    }
 }
 public static void heapifySort(int arr[],int n){
     /** 初始建堆,i为啥从n/2-1开始呢?假设n=3,那么根节点是啥,
     是0吧,这个是为了和heapify()函数下标规律保持一致*/
     for(int i=n/2-1;i>=0;i--)
        heapify(arr,n,i);
    //一个个从堆顶取出元素
     for(int i=n-1;i>=0;i--){
        swap(arr,0,i);//堆顶元素的下标是0,交换即是把堆顶元素放到屁股后面
        heapify(arr, i, 0);//堆调整的过程
     }
 }
 /**注意交换不能按值传递*/
 public static void swap(int arr[],int a,int b){
     int tmp = arr[a];
     arr[a] = arr[b];
     arr[b] = tmp;
 }

7.树的遍历

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    /**define the tree node with the class */
    class TreeNode{
       int val;
       TreeNode left;
       TreeNode right;
       TreeNode(int x){val =x;}
    }
    public void visit(int x){
        System.out.println("%d ",x);
    }
    /***Traverse with recusion */
    public void preOrderTraverse(TreeNode root){
       if (root==null) {
           return;
       }
       visit(root.val);
       preOrderTraverse(root.left);
       preOrderTraverse(root.right);
    }
    public void inOrderTraverse(TreeNode root){
        if (root==null) {
            return;
        }
        inOrderTraverse(root.left);
        visit(root.val);
        inOrderTraverse(root.right);
     }
     public void postOrderTraverse(TreeNode root){
        if (root==null) {
            return;
        }
        postOrderTraverse(root.left);
        postOrderTraverse(root.right);
        visit(root.val);
     }
        /***Traverse without recusion */
        public void preOrderTraverseNoRes(TreeNode root){
               Stack stack = new Stack<>();
               while (!stack.isEmpty()||root!=null) {
                   if(root!=null){
                       visit(root.val);
                       stack.push(root);
                       root=root.left;
                   }else{
                       root = stack.pop();
                       root = root.right;
                   }
               }
         }
         public void inOrderTraverseNoRes(TreeNode root){
            Stack stack = new Stack<>();
            while (!stack.isEmpty()||root!=null) {
                if(root!=null){//将左子树压栈到底
                    stack.push(root);
                    root=root.left;
                }else{
                    root = stack.pop();//弹出即访问
                    visit(root.val);
                    root = root.right;//转右子树
                }
            }
      }

      public void postOrderTraverseNoRes(TreeNode root){
        Stack stack = new Stack<>();
        List ret = new ArrayList<>();
        while (!stack.isEmpty()||root!=null) {
            if(root!=null){
                visit(root.val);
                stack.push(root);
                root=root.left;
            }else{
                root = stack.pop();
                root = root.right;
            }
        }
        Collections.reverse(ret);
        return ret;
  }
  //层序遍历
  public void levelTraverse(TreeNode root){
      if(root == null){
          return;
      }
      linkedList queue = new linkedList<>();
      queue.offer(root);//将根节点入队列
      //
      while(!queue.isEmpty()){
          TreeNode node = queue.poll();//出队列
          visit(node.val);
          if(node.left!=null){
            queue.offer(node.left);
          }
          if(node.right!=null)
          {
            queue.offer(node.right);
          }
      }
  }
}

8.全排列

/**
参考资料:https://blog.csdn.net/u013309870/article/details/68941284
*/
public  void Permutation(char chs[],int start )
    {
        if(start==chs.length-1)
        {
            Arrays.toString(chs);
            //如果已经到了数组的最后一个元素,前面的元素已经排好,输出。
        }
        for(int i=start;i<=chs.length-1;i++)
        {
        //把第一个元素分别与后面的元素进行交换,递归的调用其子数组进行排序
           if(i==start||chs[i]!=chs[start])
          {
                Swap(chs,i,start);
                Permutation(chs,start+1);
                Swap(chs,i,start);
           }
        //子数组排序返回后要将第一个元素交换回来。  
        //如果不交换回来会出错,比如说第一次1、2交换,第一个位置为2,子数组排序返回后如果不将1、2
        //交换回来第二次交换的时候就会将2、3交换,因此必须将1、2交换使1还是在第一个位置 
        }
    }
    public  void Swap(char chs[],int i,int j)
    {
        char temp;
        temp=chs[i];
        chs[i]=chs[j];
        chs[j]=temp;
    }

 

9. 反转链表

/**参考资料:https://www.jianshu.com/p/3f0cd7af370d*/    
    public ListNode ReverseList(ListNode head) {
        ListNode pre = null;
        while(head!=null){
            ListNode tmp = head;//暂存当前头节点
            head = head.next;//head后移
            tmp.next = pre;//当前头节点指向前一个节点
            pre = tmp;//前一个节点后移
        }
        return pre;
    }

10. 寻找链表的第一个公共节点

    public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        ListNode p1 = pHead1;
        ListNode p2 = pHead2;
        //可以理解为操场上跑步,由于两个人速度不一样,总可能相遇。
        while(p1!=p2){
            p1=(p1==null?pHead1:p1.next);//循环遍历链表
            p2=(p2==null?pHead2:p2.next);//循环遍历链表
        }
        return p1;
    }

11. 合并有序链表

public ListNode Merge(ListNode list1,ListNode list2) {
        ListNode head = new ListNode(0);//用来记录头节点
        ListNode cur = head;//游标,谁小指向谁
        //list1和list2也分别用来进行移动
        while(list1!=null&&list2!=null){
           if(list1.val<=list2.val){
               cur.next = list1;//更新游标链接新节点
               cur = cur.next;//更新游标
               list1 = list1.next;//更新列表
           }else{
               cur.next = list2;
               cur = cur.next;
               list2 = list2.next;
           }   
        }
        if(list1!=null)
            cur.next = list1;
        if(list2!=null)
            cur.next = list2;
        return head.next;
    }

12. 洗牌算法

/**
参考资料:https://www.jianshu.com/p/0071c8c4014e
*/    
public static void Shuffle(int [] arr){
        Random random = new Random();
        int length = arr.length;
        for(int i = length;i >1;i--){
           Swap(arr, i-1, random.nextInt(i));//保证已经交换的不影响,可以出现不交换的情况
        }
    }
    public static void Swap(int [] arr,int i,int j){
       int tmp = arr[i];
       arr[i] = arr[j];
       arr[j] = tmp;
  }

13. 二叉树的宽度

/**
参考资料:https://blog.csdn.net/not_in_mountain/article/details/78198478
*/   
public static int getMaxWidth(TreeNode root){
        Queue q = new LinkedList<>();
        if(root!=null) q.offer(root);
        int max = 0;
        while(!q.isEmpty()||root!=null){
            int len = q.size();//获取当前层节点个数
            max = len>max?len:max;//遍历完一层节点
            while(len>0){
                TreeNode node = q.poll();
                len--;
                if(node.left!=null) q.offer(node.left);
                if(node.right!=null) q.offer(node.right);
            }
        }
        return max;
    }

14. 链表中找环的入口

public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        if(pHead==null||pHead.next==null)
            return null;
        ListNode fastP = pHead;
        ListNode slowP = pHead;
        while(slowP!=null&&fastP!=null){
            slowP=slowP.next;//慢指针
            fastP=fastP.next.next;//快指针
            if(slowP==fastP){
                fastP=pHead;
                while(fastP!=slowP){
                fastP=fastP.next;
                slowP=slowP.next;
            }
            if(slowP==fastP)
            return slowP;
            }
        }
        return null;
    }
}

15.合并两个二叉树

    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        if (t1 == null && t2 == null) return null;
        int val = (t1 == null ? 0 : t1.val) + (t2 == null ? 0 : t2.val);
        TreeNode newNode = new TreeNode(val);
        newNode.left = mergeTrees(t1 == null ? null : t1.left, t2 == null ? null : t2.left);
        newNode.right = mergeTrees(t1 == null ? null : t1.right, t2 == null ? null : t2.right);
        return newNode;
    }

16. 希尔排序

/**
参考资料:https://mp.weixin.qq.com/s/vn3KiV-ez79FmbZ36SX9lg
*/
public static void ShellSort(int arr[]){
       int n = arr.length;
       int gap = n/2;
       while(gap>0){
        for(int i=1;i0&&tmp

18.求一个子树是否是另一棵树的子树?

这道题本质上是一个回溯问题,题解采用了递归里面套递归的手法**/
public class Solution {
    public boolean HasSubtree(TreeNode root1,TreeNode root2){
        boolean result = false;
        if(root1==null||root2==null)
            return false;
        if(root1.val==root2.val){//相等则继续往下探寻
            result = IsContain(root1,root2);
        }
        if(!result){//往左探寻
            result = HasSubtree(root1.left,root2);
        }
        if(!result){//往右探寻
            result = HasSubtree(root1.right,root2);
        }          
        return result;
    }
    public boolean IsContain(TreeNode root1,TreeNode root2){//递归探寻
        if(root2==null) return true;
        if(root1==null) return false;
        if(root1.val!=root2.val) return false;
        return IsContain(root1.left,root2.left) && IsContain(root1.right,root2.right);
    }
}

 

你可能感兴趣的:(算法与数据结构,Java)