大厂代码面手撕基础题


不要纠结,干就完事了,熟练度很重要!!!多练习,多总结!!!

快速排序

代码实现

class Solution {
    public int[] sortArray(int[] nums) {
        sort(nums, 0, nums.length-1);
        return nums;
    }

    public void sort(int[] nums, int lo, int hi){
        if(lo > hi){
            return ;
        }

        int j = partition(nums, lo, hi);
        sort(nums, lo, j-1);
        sort(nums, j+1, hi);
    }

    public int partition(int[] nums, int lo, int hi){
        int pivot = nums[lo];
        int i = lo+1, j = hi;
        while(i <= j){
            while(i < hi && nums[i] < pivot){
                i++;
            }

            while(j > lo && nums[j] > pivot){
                j--;
            }
            if(i >= j){
                break;
            }
            swap(nums, i, j);
        }
        swap(nums, lo, j);
        return j;
    }

    public void swap(int[] nums, int i, int j){
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

归并排序

代码实现

class Solution {
    int[] temp;
    public int[] sortArray(int[] nums) {
        temp = new int[nums.length];
        sort(nums, 0, nums.length-1);
        return nums;
    }

    public void sort(int[] nums, int low, int high){
        if(low >= high){
            return;
        }
        int mid = low + (high-low)/2;
        sort(nums, low, mid);
        sort(nums, mid+1, high);
        merge(nums, low, mid, high);

    }

    public void merge(int[] nums, int low, int mid, int high){
        for(int i = low; i <= high ;i++){
            temp[i] = nums[i];
        }

        int i = low, j = mid+1;
        for(int k = low;k <= high;k++){
            if(i == mid + 1){
                nums[k] = temp[j++];
            }else if(j == high+1){
                nums[k] = temp[i++];
            }else if(temp[i] > temp[j]){
                nums[k] = temp[j++];
            }else {
                nums[k] = temp[i++];
            }
        }
    }
}

单例模式

代码实现

懒汉式:
双重校验,线程安全且在多线程情况下能保持高性能。

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
	    if (singleton == null) {  
	        synchronized (Singleton.class) {  
	            if (singleton == null) {  
	                singleton = new Singleton();  
	            }  
	        }  
	    }  
	    return singleton;  
    }  
}

饿汉式:
线程安全,在程序启动时直接运行加载,但是可能造成资源浪费。

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
   		return instance;  
    }  
}

LRU Cache

代码实现

public class LRUCache {
   class LinkedNode {
     int key;
     int value;
     LinkedNode prev;
     LinkedNode next;
   }
 
  private void addNode(LinkedNode node) {
    node.prev = head;
    node.next = head.next;
    head.next.prev = node;
    head.next = node;
  }

  private void removeNode(LinkedNode node){
    LinkedNode prev = node.prev;
    LinkedNode next = node.next;
    prev.next = next;
    next.prev = prev;
  }

  private void moveToHead(LinkedNode node){
    removeNode(node);
    addNode(node);
  }

  private LinkedNode popTail() {
    LinkedNode res = tail.prev;
    removeNode(res);
    return res;
  }

  private Hashtable<Integer, LinkedNode> cache = new Hashtable<Integer,LinkedNode>();
  private int size;
  private int capacity;
  private LinkedNode head, tail;

  public LRUCache(int capacity) {
    this.size = 0;
    this.capacity = capacity;
    head = new LinkedNode();
    tail = new LinkedNode();
    head.next = tail;
    tail.prev = head;
  }

  public int get(int key) {
    LinkedNode node = cache.get(key);
    if (node == null) return -1;
    moveToHead(node);
    return node.value;
  }

  public void put(int key, int value) {
    LinkedNode node = cache.get(key);

    if(node == null) {
      LinkedNode newNode = new LinkedNode();
      newNode.key = key;
      newNode.value = value;
      cache.put(key, newNode);
      addNode(newNode);
      ++size;
      if(size > capacity) {
        LinkedNode tail = popTail();
        cache.remove(tail.key);
        --size;
      }
    } else {
      node.value = value;
      moveToHead(node);
    }
  }
}

LFU Cache

代码实现

class LFUCache {
    private static class Node {
        int key, value, freq = 1; // 新书只读了一次
        Node prev, next;

        Node(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }

    private final int capacity;
    private final Map<Integer, Node> keyToNode = new HashMap<>();
    private final Map<Integer, Node> freqToDummy = new HashMap<>();
    private int minFreq;

    public LFUCache(int capacity) {
        this.capacity = capacity;
    }

    public int get(int key) {
        Node node = getNode(key);
        return node != null ? node.value : -1;
    }

    public void put(int key, int value) {
        Node node = getNode(key);
        if (node != null) { // 有这本书
            node.value = value; // 更新 value
            return;
        }
        if (keyToNode.size() == capacity) { // 书太多了
            Node dummy = freqToDummy.get(minFreq);
            Node backNode = dummy.prev; // 最左边那摞书的最下面的书
            keyToNode.remove(backNode.key);
            remove(backNode); // 移除
            if (dummy.prev == dummy) { // 这摞书是空的
                freqToDummy.remove(minFreq); // 移除空链表
            }
        }
        node = new Node(key, value); // 新书
        keyToNode.put(key, node);
        pushFront(1, node); // 放在「看过 1 次」的最上面
        minFreq = 1;
    }

    private Node getNode(int key) {
        if (!keyToNode.containsKey(key)) { // 没有这本书
            return null;
        }
        Node node = keyToNode.get(key); // 有这本书
        remove(node); // 把这本书抽出来
        Node dummy = freqToDummy.get(node.freq);
        if (dummy.prev == dummy) { // 抽出来后,这摞书是空的
            freqToDummy.remove(node.freq); // 移除空链表
            if (minFreq == node.freq) { // 这摞书是最左边的
                minFreq++;
            }
        }
        pushFront(++node.freq, node); // 放在右边这摞书的最上面
        return node;
    }

    // 创建一个新的双向链表
    private Node newList() {
        Node dummy = new Node(0, 0); // 哨兵节点
        dummy.prev = dummy;
        dummy.next = dummy;
        return dummy;
    }

    // 在链表头添加一个节点(把一本书放在最上面)
    private void pushFront(int freq, Node x) {
        Node dummy = freqToDummy.computeIfAbsent(freq, k -> newList());
        x.prev = dummy;
        x.next = dummy.next;
        x.prev.next = x;
        x.next.prev = x;
    }

    // 删除一个节点(抽出一本书)
    private void remove(Node x) {
        x.prev.next = x.next;
        x.next.prev = x.prev;
    }
}

实现HashMap

有时候题目会要求不能使用任何 List、Set数据结构,纯Node型数组实现

代码实现

class MyHashMap {
    private class Pair {
        private int key;
        private int value;

        public Pair(int key, int value) {
            this.key = key;
            this.value = value;
        }

        public int getKey() {
            return key;
        }

        public int getValue() {
            return value;
        }

        public void setValue(int value) {
            this.value = value;
        }
    }

    private static final int BASE = 769;
    private LinkedList[] data;

    /** Initialize your data structure here. */
    public MyHashMap() {
        data = new LinkedList[BASE];
        for (int i = 0; i < BASE; ++i) {
            data[i] = new LinkedList<Pair>();
        }
    }
    
    /** value will always be non-negative. */
    public void put(int key, int value) {
        int h = hash(key);
        Iterator<Pair> iterator = data[h].iterator();
        while (iterator.hasNext()) {
            Pair pair = iterator.next();
            if (pair.getKey() == key) {
                pair.setValue(value);
                return;
            }
        }
        data[h].offerLast(new Pair(key, value));
    }
    
    /** Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key */
    public int get(int key) {
        int h = hash(key);
        Iterator<Pair> iterator = data[h].iterator();
        while (iterator.hasNext()) {
            Pair pair = iterator.next();
            if (pair.getKey() == key) {
                return pair.value;
            }
        }
        return -1;
    }
    
    /** Removes the mapping of the specified value key if this map contains a mapping for the key */
    public void remove(int key) {
        int h = hash(key);
        Iterator<Pair> iterator = data[h].iterator();
        while (iterator.hasNext()) {
            Pair pair = iterator.next();
            if (pair.key == key) {
                data[h].remove(pair);
                return;
            }
        }
    }

    private static int hash(int key) {
        return key % BASE;
    }
}

在这里插入图片描述

手写LinkedList

代码实现

package com.test.collection;

/**
 * 自定义实现LinkList
 * 
 * 1.双向链表
 * 实现原理:底层封装Node节点对象(每个节点存放有3部分内容:1.上个节点的位置,2.当前节点内容,3.下一个节点的位置)
 * 
 * 2.查询
 * LinkList 相较 ArrayList 查询效率低:
 * 由于LinkList底层存放元素的不是数组,不能直接通过索引进行获取,需要从头或者从尾逐一遍历索引节点对象。
 * ArrayList直接通过索引获取即可。
 * 
 * 3.删除、插入
 * linkList 相较ArrayList 插入、删除的效率高 
 * LinkList 直接打断前后的链接,链接到新对象即可;
 * 而ArrayList插入之后需要对后面的元素 进行整体移位
 * @author chenx
 *
 */
public class MyLinkList {
    private Node first;
    private Node last;
    public int size;
    
    public void add(Object obj){
        Node node=new Node();
        if(first == null){
            node.prev=null;
            node.element=obj;
            node.next=null;
            first=node;
            last=node;
        }else{
            //默认直接追加到最后
            node.prev=last;
            node.element=obj;
            node.next=null;
            last.next =node;
            last =node;
        }
        size ++;
    }
    
    /**
     * 由于不是数组,不能直接通过索引进行获取,需要从头或者从尾逐一遍历索引节点对象
     * 因此,相较ArrayList查询要慢
     * @param index
     * @return
     */
    public Object get(int index){
        rangeCheck(index);//下标越界检查
        Node temp=node(index);//获取当前节点
        return temp.element;
    }
    
    /**
     * 链表移除,直接打断前后的链接,链接到新对象即可;
     * 而ArrayList删除之后需要对后面的元素 进行整体移位,
     * 因此:linkList 相较ArrayList 删除的速度快
     * @param index
     * @param obj
     */
    public void remove(int index){
        rangeCheck(index);//下标越界检查
        Node temp=node(index);//获取当前节点
        Node up=temp.prev;
        Node down=temp.next;
        
        if(up==null){
            first = down;
        }else{
            up.next=down;
        }
        
        if(down==null){
            last = up;
        }else{
            down.prev=up;
        }
        
        size--;
    }
    //获取节点
    Node node(int index){//通过节点遍历实现类似索引的效果
        Node temp=first;
        if(first !=null){
            if(index <(size >>1)){
                temp=first;
                for(int i=0;i<index;i++){
                    temp = temp.next;
                }
            }else{
                temp=last;
                for(int i=size;i>index;i--){
                    temp = temp.prev;
                }
            }
        }
        return temp;
    }
    /**
     * 链表插入,直接打断前后的链接,链接到新对象即可;
     * 而ArrayList插入之后需要对后面的元素 进行整体移位,
     * 因此:linkList 相较ArrayList 插入的速度快
     * @param index
     * @param obj
     */
    public void add(int index,Object obj){
        Node temp=node(index);//获取当前节点
        Node newNode=new Node();
        newNode.element=obj;
        if(temp!=null){
            Node up=temp.prev;
            up.next=newNode;
            newNode.prev=up;
            newNode.next=temp;
            temp.prev=newNode;
            size++;
        }
    }
    
    public int size(){
        return size;
    }
    
    //下标越界检查
    private void rangeCheck(int index){
        if(index<0 || index>size){
            try {
                throw new Exception();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

生产者消费者模式

代码实现

class ProducerConsumer {
 
   private int maxSize;
   private LinkedList<Object> storage;
 
   public ProducerConsumer(int size) {
       this.maxSize = size;
       storage = new LinkedList<>();
   }
 
   public synchronized void put() throws InterruptedException {
       while (storage.size() == maxSize) {
           storage.wait();
       }
       storage.add(new Object());
       storage.notifyAll();
   }
 
   public synchronized void take() throws InterruptedException {
       while (storage.size() == 0) {
           storage.wait();
       }
       System.out.println(storage.remove());
       storage.notifyAll();
   }
}


阻塞队列

代码实现

public class BlockingQueue<E> {
    /**
     * 阻塞队列最大容量
     */
    private int size;

    /**
     * 队列底层实现
     */
    LinkedList<E> list = new LinkedList<>();

    ReentrantLock lock = new ReentrantLock();

    /**
     * 队列满的等待条件
     */
    Condition full = lock.newCondition();

    /**
     * 队列空的等待条件
     */
    Condition empty = lock.newCondition();

    public BlockingQueue(int size) {
        this.size = size;
    }


    public void enqueue(E e) throws InterruptedException {
        lock.lock();
        try {
            // 队列满了,就在full条件上进行等待
            while (list.size() == size){
                full.await();
            }

            list.add(e);
            System.out.println("入队:"+e);
            // 入队之后,就通知在empty条件下等待的线程
            empty.signal();
        } finally {
            lock.unlock();
        }
    }

    public E dequeue() throws InterruptedException {
        E e;
        lock.lock();
        try {
            // 队列为空,就在空条件上等待
            while (list.size() == 0){
                empty.await();
            }
            e = list.removeFirst();
            System.out.println("出队:"+e);
            // 出队之后,就通知在full条件下等待的线程
            full.signal();
            return e;
        } finally {
            lock.unlock();
        }
    }
}

多线程按序打印

三个不同的线程 A、B、C 将会共用一个 Foo 实例。

线程 A 将会调用 first() 方法
线程 B 将会调用 second() 方法
线程 C 将会调用 third() 方法

代码实现

class Foo {
    private int i = 1;
    private int n = 3;


    public Foo() {
        
    }

    public void first(Runnable printFirst) throws InterruptedException {
        while(i <= n){
            synchronized(this){
                if(i <= n && i % 3 == 1){
                    printFirst.run();
                    i++;
                }
            }
        }
        
    }

    public void second(Runnable printSecond) throws InterruptedException {
        while(i <= n){
            synchronized(this){
                if(i <= n && i % 3 == 2){
                    printSecond.run();
                    i++;
                }
            }
        }
    }

    public void third(Runnable printThird) throws InterruptedException {
        while(i <= n){
            synchronized(this){
                if(i <= n && i % 3 == 0){
                    printThird.run();
                    i++;
                }
            }
        }
    }
}

class Foo {
    private int i = 1;
    private int n = 3;

    private Lock lock = new ReentrantLock();

    public Foo() {
        
    }

    public void first(Runnable printFirst) throws InterruptedException {
        while(i <= n){
            lock.lock();
            try{
                if(i <= n && i % 3 == 1){
                    printFirst.run();
                    i++;
                }
            }finally{
                lock.unlock();
            }
        }
        
    }

    public void second(Runnable printSecond) throws InterruptedException {
        while(i <= n){
            lock.lock();
            try{
                if(i <= n && i % 3 == 2){
                    printSecond.run();
                    i++;
                }
            }finally{
                lock.unlock();
            }
        }
    }

    public void third(Runnable printThird) throws InterruptedException {
        while(i <= n){
            lock.lock();
            try{
                if(i <= n && i % 3 == 0){
                    printThird.run();
                    i++;
                }
            }finally{
                lock.unlock();
            }
        }
    }
}

class FooBar {
    private int n;
    private volatile int i = 1;
    private ReentrantLock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public FooBar(int n) {
        this.n = n;
    }

    public void foo(Runnable printFoo) throws InterruptedException {
        while(i <= 2*n){
            lock.lock();
            try{
                if(i <= 2*n && i % 2 == 1){
                    printFoo.run();
                    condition.signalAll();
                    i++;
                }else{
                    condition.await();
                }
            }finally{
                lock.unlock();
            }
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {
        
        while(i <= 2*n){
            lock.lock();
            try{
                if(i <= 2*n && i % 2 == 0){
                    printBar.run();
                    condition.signalAll();
                    i++;
                }else{
                    condition.await();
                }
            }finally{
                lock.unlock();
            }
        }
    }
}

class FooBar {
    private int n;
    private Semaphore s1 = new Semaphore(1);
    private Semaphore s2 = new Semaphore(0);

    public FooBar(int n) {
        this.n = n;
    }

    public void foo(Runnable printFoo) throws InterruptedException {
        
        for (int i = 0; i < n; i++) {
            s1.acquire();
        	printFoo.run();
            s2.release();
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {
        
        for (int i = 0; i < n; i++) {
            s2.acquire();
        	printBar.run();
            s1.release();
        }
    }
}

多线程交替打印字符串

编写一个可以从 1 到 n 输出代表这个数字的字符串的程序,但是:

如果这个数字可以被 3 整除,输出 “fizz”。
如果这个数字可以被 5 整除,输出 “buzz”。
如果这个数字可以同时被 3 和 5 整除,输出 “fizzbuzz”。

代码实现

class FizzBuzz {
    private int n;
    private int i = 1;
    private Lock lock = new ReentrantLock();


    public FizzBuzz(int n) {
        this.n = n;
    }

    // printFizz.run() outputs "fizz".
    public void fizz(Runnable printFizz) throws InterruptedException {        
        while(i <= n){
            lock.lock();
            try{
                if(i <= n && i % 3 == 0 && i % 5 != 0){                    
                    printFizz.run();
                    i++;
                }                
            }finally{
                lock.unlock();
            }
        }
    }

    // printBuzz.run() outputs "buzz".
    public void buzz(Runnable printBuzz) throws InterruptedException {
        while(i <= n){
            lock.lock();
            try{
                if(i <= n && i % 3 != 0 && i % 5 == 0){                    
                    printBuzz.run();
                    i++;
                }                
            }finally{
                lock.unlock();
            }
        }
        
    }

    // printFizzBuzz.run() outputs "fizzbuzz".
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
        while(i <= n){
            lock.lock();
            try{
                if(i <= n && i % 3 == 0 && i % 5 == 0){                    
                    printFizzBuzz.run();
                    i++;
                }                
            }finally{
                lock.unlock();
            }
        }
        
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void number(IntConsumer printNumber) throws InterruptedException {
        while(i <= n){
            lock.lock();
            try{
                if(i <= n && i % 3 != 0 && i % 5 != 0){                    
                    printNumber.accept(i);
                    i++;
                }                
            }finally{
                lock.unlock();
            }
        }
        
    }
}

class FizzBuzz {
    private int n;
    private int i = 1;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();


    public FizzBuzz(int n) {
        this.n = n;
    }

    // printFizz.run() outputs "fizz".
    public void fizz(Runnable printFizz) throws InterruptedException {
        while(i <= n){
            lock.lock();
            try{
                if(i % 3 == 0 && i % 5 != 0){                    
                    printFizz.run();
                    i++;
                    condition.signalAll();
                }else{
                    condition.await();
                }
            }finally{
               lock.unlock();
            }
        }
    }

    // printBuzz.run() outputs "buzz".
    public void buzz(Runnable printBuzz) throws InterruptedException {
        while(i <= n){
            lock.lock();
            try{
                if(i % 3 != 0 && i % 5 == 0){                    
                    printBuzz.run();
                    i++;
                    condition.signalAll();
                }else{
                    condition.await();
                }
            }finally{
               lock.unlock();
            }
        }
    }

    // printFizzBuzz.run() outputs "fizzbuzz".
    public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException {
        while(i <= n){
            lock.lock();
            try{
                if(i % 3 == 0 && i % 5 == 0){                    
                    printFizzBuzz.run();
                    i++;
                    condition.signalAll();
                }else{
                    condition.await();
                }
            }finally{
               lock.unlock();
            }
        }
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void number(IntConsumer printNumber) throws InterruptedException {
        while(i <= n){
            lock.lock();
            try{
                if(i % 3 != 0 && i % 5 != 0){                    
                    printNumber.accept(i);
                    i++;
                    condition.signalAll();
                }else{
                    condition.await();
                }
            }finally{
               lock.unlock();
            }
        }
        
    }
}

总结

觉得本博客有用的客官,可以给个点赞+收藏哦! 嘿嘿

喜欢本系列博客的可以关注下,以后除了会继续更新面试手撕代码文章外,还会出其他系列的文章!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值