1、二分查找
右侧边界为length-1;
while left <= right 跳出条件为区间中没有数据了。
right = mid - 1;
寻找左侧边界,需要检查left大于length,left是否不等于target。
寻找右侧边界,需要检查right小于0,right是否不等于target。
2、快速排序
从数组中取第一个数作为pivot,大于该数的划分到右边,小于的划分到左边。双指针,while循环left < right。
while(left < right && nums [left] <= pivot)
找到左边大于pivot和右边小于pivot的数之后交换
//快速排序
public int[] quickSort(int[] nums, int k) {
quickSelect(nums, 0, nums.length - 1);
return nums;
}
//左右两边递归执行
public void quickSelect(int[] a, int l, int r) {
if (l < r) {
int pos = randomPartition(a, l, r);
quickSelect(a, l, pos - 1);
quickSelect(a, pos + 1, r);
}
}
//随机在范围内选一个元素,交换到最右
public int randomPartition(int[] a, int l, int r) {
Random random = new Random();
int i = random.nextInt(r - l + 1) + l;
swap(a, i, r);
return partition(a, l, r);
}
//取最右元素作为基准,遍历nums数组,小于最右元素的值交换位置,最后将最右元素交换到应该的位置
public int partition(int[] nums, int left, int right) {
int value = nums[right];
int i = left - 1;
for (int j = left; j < right; j++) {
if (nums[j] <= value) {
i++;
swap(nums, i, j);
}
}
swap(nums, i + 1, right);
return i + 1;
}
public void swap(int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
3、寻找第K大的数
最大堆实现
PriorityQueue
代码是求最小K个数。
public static int[] smallestK(int[] arr, int k) {
int[] vec = new int[k];
if (k == 0) { // 排除 0 的情况
return vec;
}
PriorityQueue<Integer> queue = new PriorityQueue<Integer>(new Comparator<Integer>() {
public int compare(Integer num1, Integer num2) {
return num2 - num1;
}
});
for (int i = 0; i < k; ++i) {
queue.offer(arr[i]);
}
for (int i = k; i < arr.length; ++i) {
if (queue.peek() > arr[i]) {
queue.poll();
queue.offer(arr[i]);
}
}
for (int i = 0; i < k; ++i) {
vec[i] = queue.poll();
}
return vec;
}
4、前序、中序、后序、层序遍历二叉树
前序
public List<Integer> orderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null) return list;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()) {
TreeNode cur = stack.pop();
if(cur.right != null) stack.push(cur.right);
if(cur.left != null) stack.push(cur.left);
list.add(cur.val);
}
return list;
}
中序
public List<Integer> inorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
List<Integer> list = new ArrayList<>();
if(root == null) return list;
TreeNode cur = root;
while(!stack.isEmpty() || cur != null) {
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
list.add(cur.val);
cur = cur.right;
}
return list;
}
后序
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
//后序遍历:左 右 根 --> 根 右 左
List<Integer> res = new ArrayList<>();
if(root == null) return res;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
res.add(node.val);
if(node.left != null) stack.push(node.left);
if(node.right != null) stack.push(node.right);
}
Collections.reverse(res);
return res;
}
}
5、反转链表
迭代法:
pre = null;
while中存一下下个节点next.
递归法:
public ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newHead = reverseList(head.next);
head.next.next = head;
head.next = null;
return newHead;
}
6、判断链表是否有环
快慢指针,判断是否相遇。
寻找链表形成环的位置
同时从头出发,快慢指针相遇时,快指针从头继续出发,相遇位置即为形成环的位置,数学推导。
7、LRU实现
HashMap + 双向链表
Node
DoubleList: getSize\addLast\remove\removeFirst
LRUCathe: makeRecentLy\addRecentLy\deleteKey\removeLeastRecentLy
class Node {
private int key, val;
private Node pre, next;
public Node(int key, int val) {
this.key = key;
this.val = val;
}
}
class DoubleList {
Node head, tail;
private int size;
public DoubleList() {
head = new Node(0, 0);
tail = new Node(0, 0);
head.next = tail;
tail.pre = head;
size = 0;
}
public int getSize() {
return size;
}
public void addLast(Node node) {
node.pre = tail.pre;
node.next = tail;
tail.pre.next = node;
tail.pre = node;
size++;
}
public void remove(Node node) {
node.pre.next = node.next;
node.next.pre = node.pre;
size--;
}
public Node removeFirst() {
if (head.next == tail) {
return null;
}
Node first = head.next;
remove(first);
return first;
}
}
class LRUCache {
private DoubleList cache;
private HashMap<Integer, Node> map;
private int cap;
public LRUCache(int cap) {
this.cap = cap;
map = new HashMap<>();
cache = new DoubleList();
}
public int get(int key) {
if (!map.containsKey(key)) {
return -1;
}
// 将该数据提升为最近使用的
makeRecently(key);
return map.get(key).val;
}
public void put(int key, int val) {
if (map.containsKey(key)) {
// 删除旧的数据
deleteKey(key);
// 新插入的数据为最近使用的数据
addRecently(key, val);
return;
}
if (cap == cache.getSize()) {
// 删除最久未使用的元素
removeLeastRecently();
}
// 添加为最近使用的元素
addRecently(key, val);
}
/* 将某个 key 提升为最近使用的 */
private void makeRecently(int key) {
Node x = map.get(key);
// 先从链表中删除这个节点
cache.remove(x);
// 重新插到队尾
cache.addLast(x);
}
/* 添加最近使用的元素 */
private void addRecently(int key, int val) {
Node x = new Node(key, val);
// 链表尾部就是最近使用的元素
cache.addLast(x);
// 别忘了在 map 中添加 key 的映射
map.put(key, x);
}
/* 删除某一个 key */
private void deleteKey(int key) {
Node x = map.get(key);
// 从链表中删除
cache.remove(x);
// 从 map 中删除
map.remove(key);
}
/* 删除最久未使用的元素 */
private void removeLeastRecently() {
// 链表头部的第一个元素就是最久未使用的
Node deletedNode = cache.removeFirst();
// 同时别忘了从 map 中删除它的 key
int deletedKey = deletedNode.key;
map.remove(deletedKey);
}
LinkedHashMap
public class LRUCathe {
int capacity;
LinkedHashMap<Integer, Integer> cathe = new LinkedHashMap<>();
public LRUCathe(int capticy) {
this.capacity = capticy;
}
public int get(int key) {
if (!cathe.containsKey(key)) {
return -1;
}
makeItRecently(key);
return cathe.get(key);
}
public void put(int key, int val) {
if (cathe.containsKey(key)) {
cathe.put(key, val);
makeItRecently(key);
}
if (cathe.size() >= capacity) {
int oldestKey = cathe.keySet().iterator().next();
cathe.remove(oldestKey);
}
cathe.put(key, val);
}
private void makeItRecently(int key) {
int val = cathe.get(key);
cathe.remove(key);
cathe.put(key, val);
}
}
8、两个栈实现队列
一个inStack
一个outStack
push进inStack
peek就判断outStack是否空,为空就转移inStack,不为空直接返回peek
pop先执行peek操作,然后pop outStack
9、队列实现栈
10、背包问题
11、买卖股票
12、打家劫舍