手撕代码总结(纯Java版)------常见算法

KMP算法

public static int kmpSearch(String s, String p) {
   int sLen = s.length();
   int pLen = p.length();
   if (sLen < pLen) {
       return -1;
   }

   int[] next = getNext(p);
   // matching: O(n)
   int i = 0, j = 0;
   while (i < sLen && j < pLen) {
       //①如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++
       if (j == -1 || s.charAt(i) == p.charAt(j)) {
           i++;
           j++;
       } else {
           //②如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]
           //next[j]即为j所对应的next值
           j = next[j];
       }
   }
   if (j == pLen) {
       return i - j;
   } else {
       return -1;
   }
}

public static int[] getNext(String p) {
   int len = p.length();
   int[] next = new int[len];
   next[0] = -1;
   int i = 0, k = -1;
   while (i < len - 1) {
       // p[k]表示前缀,p[i]表示后缀
       if (k == -1 || p.charAt(i) == p.charAt(k)) {
           ++k;
           ++i;
           if (p.charAt(i) != p.charAt(k)) {
               next[i] = k;
           } else {
               // 因为不能出现p[i] = p[next[i]],所以当出现时需要继续递归,k = next[k] = next[next[k]]
               next[i] = next[k];
           }
       } else {
           k = next[k];
       }
   }
   return next;
}

LRU

import java.util.HashMap;
class Node{
    public Node(String key,String value){
        this.key = key;
        this.value = value;
    }
    public Node pre;
    public Node next;
    public String key;
    public String value;
}
public class LRUCache {
    private Node head;
    private Node end;
    //缓存上限
    private int limit;
    private HashMap map;
    public LRUCache(int limit) {
        this.limit = limit;
        map = new HashMap();
    }
    public String get(String key) {
        Node node = map.get(key);
        if(node == null) {
            return null;
        }
        //调整node到尾部
        refreshNode(node);
        return node.value;
    }
    public void put(String key, String value) {
        Node node = map.get(key);
        if(node == null) {
            //key不存在直接插入
            while(map.size() >= limit) {
                //去除链表内的节点
                String oldKey = removeNode(head);
                //去除map中的缓存
                map.remove(oldKey);
            }
            node = new Node(key, value);
            //链表中加入节点
            addNode(node);
            //map中加入节点
            map.put(key, node);
        } else {
            //更新节点并调整到尾部
            node.value = value;
            refreshNode(node);
        }
    }
    private void refreshNode(Node node) {
        //如果访问的是尾节点,无须移动节点
        if(node == end) {
            return; 
        }
        //把节点移动到尾部,相当于做一次删除插入操作
        removeNode(node);
        addNode(node);
    }
    private String removeNode(Node node) {
        //尾节点
        if(node == end) {
            end = end.pre;
        } else if(node == head) {
        //头结点
            head = head.next;
        } else {
            //中间节点
            node.pre.next = node.next;
            node.next.pre = node.pre;
        }
        return node.key;
    }
    private void addNode(Node node) {
        if(end != null) {
            end.next = node;
            node.pre = end;
            node.next = null;
        }
        end = node;
        if(head == null) {
            head = node;
        }
    }
}

手动实现一个锁

class Share {
    int i;
    Lock lock = new ReentrantLock();
    public void incr() {
        lock.lock();
        try { // 当发生异常时, 能够释放锁, 否则会导致死锁.
            i++;
        }
        finally {
            lock.unlock();
        }
    }
}

public class MyLock implements Lock {
    AtomicReference<Thread> owner = new AtomicReference<>(); // 线程拥有者
    // 等待锁的线程队列 选择blockingQueue是因为其是线程安全 
    // 选择linked是因为没有随机访问但是有频繁的增删
    BlockingQueue<Thread> waiter = new LinkedBlockingDeque<>(); // 阻塞线程
    @Override
    public void lock() {
        while (!owner.compareAndSet(null, Thread.currentThread())) { 
            // 抢不到锁的情况 -- 放入等待列表 -- 阻塞
            waiter.add(Thread.currentThread()); // 放入等待列表
            LockSupport.park(); // 静态方法 让当前线程自己阻塞自己
            waiter.remove(Thread.currentThread()); // 不会让队列不断增加, 造成内存泄露
            // 为什么remove是写在这里? 很有意思, 当线程被唤醒时, 是从这一行开始执行的, 所以它退出了阻塞队列, 这是并发编程中比较难理解的逻辑
        }
    }

    @Override
    public void unlock() {
        // 持有锁的线程能够成功
        if (owner.compareAndSet(Thread.currentThread(), null)) { // 为什么是if 因为不存在竞争
            // 唤醒其他等待线程
            for (Object object : waiter) {
                Thread next = (Thread) object;
                LockSupport.unpark(next);
            }
        }
        /*
        还有其他需要实现的方法都可以不用实现 用默认值, 暂时用不到
        */
    }

链表判环

public class Linked {
 
	// Node静态类
	private static class Node {
		private Integer data;
		private Node next;
		
		Node(){}
		Node(Integer data){
			this(data, null);
		}
		Node(Integer data, Node next){
			this.data = data;
			this.next = next;
		}
	}
	
	/**
	 * 判断单链表是否有环。
	 * @param head 头指针
	 * @return 有环返回true,否则返回false
	 */
	public static boolean isLoop(Node head) {
		// 指针,头指针的下一个为单步,下一个的下一个是双步
		Node singleStep = head.next;
		Node doubleStep = head.next.next;
 
		// 存在2个以上的结点时
		while(doubleStep != null) {
			Integer num1 = singleStep.data;
			Integer num2 = doubleStep.data;
			// 当值相同时,说明是存在环了
			if(num1 == num2) return true;
			
			// 更新2个节点
			singleStep = singleStep.next;
			doubleStep = doubleStep.next.next;
			// 双步的结点先更新到链表尾部,说明不存在环
			if(doubleStep == null) return false;
		}
		
		// 只存在一个节点,必然是环 
		return true;
	}
	
	public static void main(String[] args) {
		Node head = new Node();// 头为null
		// 6个节点
		Node node1 = new Node(1);
		Node node2 = new Node(2);
		Node node3 = new Node(3);
		Node node4 = new Node(4);
		Node node5 = new Node(5);
		Node node6 = new Node(6);
		
		// 创建有环链表
		// null->node1->node2->node3->node4->node5->node6->node3
		head.next = node1;
		node1.next = node2;
		node2.next = node3;
		node3.next = node4;
		node4.next = node5;
		node5.next = node6;
		node6.next = node1;
		
		boolean loop = isLoop(head);
		System.out.println(loop);
 
	}
}

力扣 子集

package test;
 
import java.util.ArrayList;
import java.util.List;
 //枚举:逐个枚举,空集的幂集只有空集,每增加一个元素,让之前幂集中的每个集合,追加这个元素,就是新增的子集。
class Solution {
    public static List<List<Integer>> enumerate(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        res.add(new ArrayList<>());// 空 []
        for (int i = 0; i < nums.length; i++) {
            int size = res.size();
            for (int j = 0; j < size; j++) {
                List<Integer> list = new ArrayList<>(res.get(j));
                list.add(nums[i]);
                res.add(list);
            }
        }
        return res;
    }
}
 
public class Main{
    public static void main (String []args){
        int[] a = {1,2,3};
        List<List<Integer>> p = Solution.enumerate(a);
        System.out.print(" " + p);
    }
}
 

SQL 取班级前三名成绩

select * from tb_student s
where(
	exists(
		select count(*) from tb_student st
		where st.score > s.score
		and st.class = s.class
		group by st.class
		having count(*) <= 3
		)
)
order by
class,score DESC
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值