LeetCode刷了500+了总结了算法必背模板直接拿到字节实习offer

目前已经有了两场大厂复习了,分别是滴滴和字节,现在还在字节实习,回想自己找实习的注意的点,那就是算法超级重要,我把能力排一个序,算法>项目经历>八股,所以在互联网这样如此内卷的行业,LeetCode是一定要刷的,下面是我刷题记录,研一的时候刷的得多,今年四五月份找实习,大部分时间都在搞好项目和八股去了,算法这一块很忽视。我这一年实习面试大大小小的面了几十家,有些直接被挂简历,有些被kpi,还有些被捞起来的,总之面试那段时间很累很累。实习就和去年相比,真的是一个天上,一个地下,上一届的学长,人均好几个大厂实习offer,到了我们这,不仅门槛高了,实习的福利也少了(他们实习的时候600-700/day)

 

LeetCode刷了500+了总结了算法必背模板直接拿到字节实习offer_第1张图片

 算法这一块,刷起来真的很迷糊,之前自己是按照剑指offer,hot一百刷的,后面发现每日一题好多不会,在面试的过程中还有好多题目不会写,于是我开始总结,自己总结算法的小技巧,感觉还是不全,于是子朋友的推荐下面,看了labuladong算法小抄,按照书中的算法思路,在重新去刷题目,总结算法的核心点,面对同样的问题,核心点会了,那这道题目也就会了。地址:labuladong 的算法小抄 :: labuladong的算法小抄,还有另外一个算法书籍,代码随想录,代码随想录,一定要分类去刷题,这样提高效率,多总结,变成自己的东西。下面是我总结几种常用的算法框架和模板,基本上是常考的类型,面试前背一背,基本不慌。在很多时候,面试完你经常会抱怨,那道算法题我之前都会,为什么手撕的时候写不出来,是因为写的少,没有完全背下来,所以你需要去回顾,默写。

快速排序

快速排序是字节超级喜欢考的题目,不仅要快速写出来,parttion的方法要熟记于心,快速排序还可以解决求第k大的数问题,因为快排parttion找出点是最终点。

public class Main {
    public static void main(String[] args) {
        int []nums = new int[]{1,3,5,7,9,10,2,4,6,8};
        quickSort(nums,0,nums.length-1);
        System.out.println(Arrays.toString(nums));
    }
    public static void quickSort(int []nums , int left , int right){
        if (left >= right)return;
        int mid = partition(nums , left , right);
        quickSort(nums,left,mid-1);
        quickSort(nums,mid+1,right);
    }
    public static int partition(int []nums , int left , int right) {
       int flag = left;
       int index = left+1;
       for (int i = index ; i <= right ; i++){
           if(nums[flag] > nums[i]){
               swap(nums,index,i);
               index ++;
           }
       }
       swap(nums,flag , index - 1);
       return index - 1;
    }
    private static void swap(int[] nums, int i, int j) {
        int tep = nums[i];
        nums[i] = nums[j];
        nums[j] = tep;
    }
}

堆排序

实习面试的时候,字节和腾讯都出过这道题目,背这道算法可以了解优先队列的原理。

public class Main {
    public static void main(String[] args) {
        int []nums = new int[]{1,3,5,7,9,10,2,4,6,8};
        heapSort(nums);
        System.out.println(Arrays.toString(nums));
    }
    public static void heapSort(int []nums){
       int len = nums.length;
       initHeap(nums,len);
       int index = len -1;
       for (int i = 0 ; i < len ; i++){
           swap(nums, 0 ,index);
           heapfying(nums , 0 , index);
           index --;
       }
    }

    private static void initHeap(int[] nums, int len) {
        for (int i = len / 2 -1 ; i >= 0 ; i--){
            heapfying(nums, i , len);
        }
    }

    private static void heapfying(int[] nums, int i, int len) {
        int left = 2 * i + 1;
        int right = 2 * i + 2;
        int max_index = i;
        if(left < len && nums[max_index] < nums[left]){
            max_index = left;
        }
        if(right < len && nums[max_index] < nums[right]){
            max_index = right;
        }
        if(max_index != i){
            swap(nums,max_index,i);
            heapfying(nums,max_index,len);
        }
    }

    private static void swap(int[] nums, int i, int j) {
        int tep = nums[i];
        nums[i] = nums[j];
        nums[j] = tep;
    }
}

归并排序

字节面试出现过,难度不难,要经常背一背。

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int []nums = new int[]{1,3,5,7,9,10,2,4,6,8};
        mergeSort(nums , 0 , nums.length-1);
        System.out.println(Arrays.toString(nums));

//        sort(new int []{1,3,2,4}, 0 , 1 , 3);
    }

    public static void mergeSort(int []nums , int left , int right){
       if (left >= right)return;
       int mid = left + (right - left) / 2;
       mergeSort(nums , left , mid);
       mergeSort(nums , mid+1 , right);
       sort(nums , left , mid , right);
    }

    public static void sort(int[] nums, int left , int mid , int right) {
        int tep [] = new int[right - left + 1];
        int i = left ;
        int j = mid + 1;
        int index = 0;
        while(i <= mid && j <= right){
            if(nums[i] > nums[j]){
                tep [index] = nums[j];
                j ++;
                index ++;
            }else{
                tep [index] = nums[i];
                i ++;
                index ++;
            }
        }
        while(i <= mid ){
            tep [index] = nums[i];
            i ++;
            index ++;
        }
        while(j <= right){
            tep [index] = nums[j];
            j ++;
            index ++;
        }
        index = 0;
        for (i = left ; i <= right; i++){
            nums[i] = tep[index++];
        }

    }
}

快速幂

快速幂和大数相乘是一种思想,将另外一个数转换为二进制的形式去处理,在用十进制和二进制处理的过程中可以考虑取模。

    public static int quickPow(int a , int b){
        final int INF = 1000000+1; // 超过范围对res取余
        int res = 1;
        a = a % INF;
        while (b != 0){
            if ((b & 1) == 1){
                res = res * a;
                res %= INF;
            }
            b = b >> 1;
            a = a * a;
            a = a %INF;
        }
        return res;
    }

大数相乘

public static int bigNumberMultiply(int a , int b){
        final int INF = 1000000+1; // 超过范围对res取余
        int res = 0;
        int tep = a;
        while (b != 0){
            if ((b & 1) == 1){
                res += tep;
                res %= INF;
            }
            b = b >> 1;
            tep = tep * a;
        }
        return res;
    }

质数分布规律

质数分布规律可以快速判断一个数是否为质数,大于等于5的质数分布在6的倍数左右,但是六的倍数左右不一定是质数。

 public static boolean isPrime(int n){
        if (n == 2 || n == 3 || n == 5)return true;
        if (n == 4 || n == 1)return false;
        if (n % 6 != 5 && n % 6 != 1)return false;
        for (int i = 5 ; i <= Math.sqrt(n) ; i += 6){
            if (n % i == 0 || n % n + 2 == 0){
                return false;
            }
        }
        return true;
    }

牛顿迭代法开平方

记住迭代公式:x1 = (x0 + n / x0) / 2;

    public static double newDun(int n , double x ){
        double x0 = n / 2 ;
        if (n == 1) x0 = 1;
        double x1 = (x0 + n / x0) / 2;
        while(Math.abs(x1 - x0)>x){
            x0 = x1;
            x1 = (x0 + n / x0) / 2;
        }
        return x1;
    }

水塘抽样法

水塘抽样可以面对变化的范围进行取随机。

 public static int selectPond(int n){
        int res = 0;
        Random r = new Random();
        for (int i = 1 ; i <= n ;i++){
            if (r.nextInt(i) == 0){ 
                res = i;
            }
        }
        return res;
    }

已知rand7求rand10

腾讯考过的一道题目,转换思想。

 public static int rand10(){
        Random r = new Random();
        int res = 7 * (r.nextInt(7)) +  (r.nextInt(7) + 1);
        while(res >41){
            res = 7 * (r.nextInt(7)) +  (r.nextInt(7) + 1);
        }
        return res % 10 == 0?10:res % 10;
    }

binarySearch

二分搜索可以灵活使用在答案成线性分布的情况,可以用来逼近答案,类似于求数的平方根,逐渐逼近答案。

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

leftBound

注意写法,在特殊二分场景下需要使用。

 public static int leftBound(int []nums , int target){
        int left = 0;
        int right = nums.length -1;
        while (left <= right){
            int mid = left + (right - left) / 2;
            if(target == nums[mid]){
                 right = mid - 1;
            }else if (target > nums[mid]){
                left = mid + 1;
            }else if (target < nums[mid]){
                right = mid - 1;
            }
        }
        if (left >= nums.length || nums[left] != target){
            return -1;
        }
        return left;
    }

rightBound

与leftBound相对应的。

 public static int rightBound(int []nums , int target){
        int left = 0;
        int right = nums.length -1;
        while (left <= right){
            int mid = left + (right - left) / 2;
            if(target == nums[mid]){
                 left = mid + 1;
            }else if (target > nums[mid]){
                left = mid + 1;
            }else if (target < nums[mid]){
                right = mid - 1;
            }
        }
        if (right < 0  || nums[right] != target){
            return -1;
        }
        return right;
    }

深度遍历 

public void dfs(){
        
    }

深度遍历是一个特别重要的算法思想,大部分涉及到全排列或者组合的问题,都能解决,类似于全排列,树的遍历,岛屿问题呀等等。在涉及到组合问题的时候可以采用数组有序,和选择项if(i > 0 &&dp[i] != dp[i-1])的方式实现组合去重复(例题:数组划分为k个相等的子数组)。

广度遍历

 public static void bfs(){
        LinkedList<> que = new LinkedList();
        que.add(root)
        while (!que.isEmpty()){
            int size = que.size();
            for (int i = 0 ; i < size ; i++){
                int cv = que.getFirst();
                que.removeFirst();
                // 将cv的子节点加入que
            }
        }
    }

查并集

import java.util.Random;
class unionFind{
    int count; // 连通分量的个数
    int parent[]; //指向父节点
    int []size; // 节点重量
    public unionFind (int n){
        size = new int[n];
        parent = new int[n];
        for (int i = 0 ; i < n ; i++){
            size[i] = 1;
            parent[i] = i;
        }
        count = n;
    }
    public void union(int p , int q){
        int r1 = findRoot(p);
        int r2 = findRoot(q);
        if (r1 == r2)return;
        if (size[r1] > size[r2]){
            parent[r2] = r1;   
            size[r1] += size[r2];
        }else{
            parent[r1] = r2;
            size[r2] += size[r1];
        }
        count --;
    }
    public boolean isConnect(int p , int q){
        return findRoot(p) == findRoot(q);
    }
    public int findRoot(int p){
        int res = parent[p];
        while (res!=parent[res]){
            res = parent[res];
        }
        return res;
    }
    public int getCount(){
        return count;
    }
}

dijkstra算法

dijkstra算法不适用于边值为负的情况。

public class Main {
    public static void main(String[] args) {
        int [][] distance = new int[][]{{1,2,3},{2,3,1},{0,4,3},{2,4,4},{1,4,6}};
        System.out.println(dijkstra(distance, 5, 1, 4));
    }
    /*
    * 单源最短距离-dijkstra算法
    * int[][] distance距离
    *  int n总结点数
    *  int src源点
    *  int dest目标点
    *
    * */
    public static int dijkstra(int[][] distance, int n, int src, int dest) {
        int []costs = new int[n];
        boolean []visited = new boolean[n];
        final int INF = 1000*1000+1;
        Arrays.fill(costs,INF);
        costs[src] = 0;
        for (int []cv : distance){
            int i = cv[0];
            int j = cv[1];
            int cost = cv[2];
            if (i == src){
                costs[j] = cost;
            }
        }
        visited[src] = true;
        for (int t = 1 ; t <= n - 1; t++){
            int post = 0;
            int min = Integer.MAX_VALUE;
            for (int k = 0 ; k < n; k++){
               if(!visited [k] && min > costs[k]){
                   min = costs[k];
                   post = k;
               }
            }
            visited[post] = true;
            for (int []cv : distance){
                int i = cv[0];
                int j = cv[1];
                int cost = cv[2];
                if (post == i && !visited[j] &&  costs[j] > costs[i] + cost){
                    costs[j] = costs[i] + cost;
                }
            }
        }
        return costs[dest] == INF ? -1 : costs[dest];
    }
}

bellman ford算法

bellman ford算法可以适用于限定步数的最短路径,采用dp[distance][n]来保证。

public class Main {
    public static void main(String[] args) {
        int [][] distance = new int[][]{{1,2,3},{2,3,1},{0,4,3},{2,4,2},{1,4,6}};
        System.out.println(bellmanFord(distance, 5, 1, 4));
    }

    /*
    * 单源最短距离-bellman ford算法
    * int[][] distance距离
    *  int n总结点数
    *  int src源点
    *  int dest目标点
    *
    * */
    public static int bellmanFord(int[][] distance, int n, int src, int dest) {
        int []costs = new int[n];
        final int INF = 1000*1000+1;
        Arrays.fill(costs,INF);
        costs[src] = 0;
        for (int t = 1 ; t <= n - 1; t++){
            boolean flag = true;
            for (int []cv : distance){
                int i = cv[0];
                int j = cv[1];
                int cost = cv[2];
                if (costs[j] > costs[i] + cost){
                    costs[j] = costs[i] + cost;
                    flag = false;
                }
            }
            if (flag){
                return costs[dest] == INF ? -1 : costs[dest];
            }
        }
        for (int []cv : distance){
            int i = cv[0];
            int j = cv[1];
            int cost = cv[2];
            if (costs[j] > costs[i] + cost){
                return -1;
            }
        }
        return costs[dest] == INF ? -1 : costs[dest];
    }
}

LRU

package alian;


import java.util.HashMap;

class Main{
    public static void main(String[] args) {
        LRU lru = new LRU(3);
        lru.set("1",new Integer(1));
        lru.set("2",new Integer(2));
        System.out.println(lru.get("1") != null);
        lru.set("3",new Integer(3));
        System.out.println(lru.get("3") != null);
        lru.set("4",new Integer(4));
        System.out.println(lru.get("1") == null);
    }
}
class LRU{
    HashMap map ;
    Node head,tail;
    int n ;
    int size ;
    public LRU(int n) {
        map = new HashMap<>();
        head = new Node();
        tail = new Node();
        head.next = tail;
        tail.pre = head;
        size = 0;
        this.n = n;
    }
    class Node{
        String key;
        Object val;
        Node pre;
        Node next;
    }
    public Node get(String key){
        if (!map.containsKey(key)){
            return null;
        }
        Node cv = map.get(key);
        // cv从双链表中断开
        Node pre1 = cv.pre;
        Node next1 = cv.next;
        pre1.next = next1;
        next1.pre = pre1;
        //插入到head之后
        head.next.pre = cv;
        cv.next = head.next;
        head.next = cv;
        cv.pre = head;
        return cv;
    }
    public void set(String key , Object val){
        if (!map.containsKey(key)){
            Node cv = new Node();
            cv.key = key;
            cv.val = val;
            size++;
            head.next.pre = cv;
            cv.next = head.next;
            head.next = cv;
            cv.pre = head;
            map.put(key , cv);
            if (size > n){
                size --;
                Node tep = tail.pre.pre;
                map.remove(tail.pre.key);
                tep.next = tail;
                tail.pre = tep;
            }
        }else {
            Node cv = map.get(key);
            cv.val = val;
            Node pre1 = cv.pre;
            Node next1 = cv.next;
            pre1.next = next1;
            next1.pre = pre1;
            head.next.pre = cv;
            cv.next = head.next;
            head.next = cv;
            cv.pre = head;
        }
    }
}

大厂面试喜欢常考的,注意点是考虑到双链表操作。

你可能感兴趣的:(#,算法面试,#,学习笔记,#,labuladong刷题,算法,实习,字节,刷题)