大厂代码面手撕基础题
不要纠结,干就完事了,熟练度很重要!!!多练习,多总结!!!
快速排序
代码实现
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();
}
}
}
}
总结
觉得本博客有用的客官,可以给个点赞+收藏哦! 嘿嘿
喜欢本系列博客的可以关注下,以后除了会继续更新面试手撕代码文章外,还会出其他系列的文章!