📌标题
09 贪心算法
BM95 分糖果问题
要求: 时间复杂度为 O(n),空间复杂度为 O(n)
思想:
从左向右遍历,如果a[i+1]>a[i],那么left[i+1]=left[i]+1;
从右向左遍历,如果a[i]>a[i+1],那么right[i]=right[i+1]+1;
之后取max(left[i],right[i])即可。
import java.util.*;
public class Solution {
public int candy (int[] arr) {
int n = arr.length;
int res = 0;
int[] left = new int[n];
int[] right = new int[n];
Arrays.fill(left, 1);
Arrays.fill(right, 1);
//从小到大
for (int i = 0; i < n - 1; i++) {
if (arr[i + 1] > arr[i])
left[i + 1] = left[i] + 1;
}
res =left[n-1];
//从大到小
for (int j = n - 2; j >= 0; j--) {
if (arr[j] > arr[j + 1])
right[j] = right[j + 1] + 1;
res += Math.max(left[j], right[j]);
}
return res;
}
}
BM96 主持人调度(二) 【× 难!!!】
复杂度要求:时间复杂度O(nlogn) ,空间复杂度 O(n)
方法:排序+贪心
思想:
- 首先建立两个数组分别存储开始时间(记为start)和结束时间(记为end)。
- 然后分别对start和end数组进行排序。
- 接着遍历start数组,判断当前开始时间是否大于等于最小的结束时间,
- 如果是,则说明当前主持人就可以搞定;
- 如果否,则需要新增一个主持人,并将end数组下标后移
import java.util.*;
// 这道题没懂??
public class Solution {
public int minmumNumberOfHost (int n, int[][] startEnd) {
int[] start = new int[n];
int[] end = new int[n];
for (int i = 0; i < n; i++) {
start[i] = startEnd[i][0];
end[i] = startEnd[i][1];
}
Arrays.sort(start);
Arrays.sort(end);
int inx = 0, res = 0;
for (int i = 0; i < n; i++) {
// 这里如何比较的??
if (start[i] >= end[inx])
inx++;
else
res++;
}
return res;
}
}
10 模拟
BM97 旋转数组
进阶:空间复杂度 O(1),时间复杂度 O(n)
import java.util.*;
public class Solution {
public int[] solve (int n, int m, int[] a) {
if(n<m)
m%=n;
reverse(a,0,n-1);
reverse(a,0,m-1);
reverse(a,m,n-1);
return a;
}
public void reverse(int[] a,int start,int end){
while(start<end){
int tmp=a[start];
a[start]=a[end];
a[end]=tmp;
start++;
end--;
}
}
}
BM98 螺旋矩阵
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> spiralOrder(int[][] matrix) {
ArrayList<Integer> res = new ArrayList<>();
if (matrix.length == 0) return res;
int rows = matrix.length;
int cols = matrix[0].length;
int left = 0, right = cols - 1, top = 0, bottom = rows - 1;
int numEle = matrix.length * matrix[0].length;
while (numEle >= 1) {
//向右
for (int i = left; i <= right && numEle >= 1; i++) {
res.add(matrix[top][i]);
numEle--;
}
top++;
//向下
for (int i = top; i <= bottom && numEle >= 1; i++) {
res.add(matrix[i][right]);
numEle--;
}
right--;
//向左
for (int i = right; i >= left && numEle >= 1; i--) {
res.add(matrix[bottom][i]);
numEle--;
}
bottom--;
//向上
for (int i = bottom; i >= top && numEle >= 1; i--) {
res.add(matrix[i][left]);
numEle--;
}
left++;
}
return res;
}
}
BM99 顺时针旋转矩阵
类似矩阵的转置
要求:空间复杂度 O(n^2),时间复杂度 O(n^2)
进阶:空间复杂度 O(1),时间复杂度 O(n^2)
方法一:使用辅助数组
方法二:用翻转代替旋转
上下翻转,然后沿着主对角线翻转,得到结果
import java.util.*;
public class Solution {
public int[][] rotateMatrix(int[][] mat, int n) {
for (int col = 0; col < n; col++) {
for (int row = 0; row < n / 2; row++) {
int tmp = mat[row][col];
mat[row][col] = mat[n - 1 - row][col];
mat[n - 1 - row][col] = tmp;
}
}
for (int row = 0; row < n; row++) {
for (int col = 0; col < row; col++) {
int tmp = mat[row][col];
mat[row][col] = mat[col][row];
mat[col][row] = tmp;
}
}
return mat;
}
}
BM100 设计LRU缓存结构
【这是非常经典的算法题!! 必须会!!】
方式一:哈希表+双向链表(推荐使用) 【后端面试必须掌握这个】
方式二:LinkedHashMap 【前端面试偷懒写法!!】
import java.util.*;
public class Solution {
int capacity;
DLinkedNode head, tail;
HashMap<Integer, DLinkedNode> map = new HashMap<>();
//初始化参数
public Solution(int capacity) {
this.capacity = capacity;
//虚head和虚tail
head = new DLinkedNode();
tail = new DLinkedNode();
head.next = tail;
tail.pre = head;
}
public int get(int key) {
if (!map.containsKey(key)) {
return -1;
}
DLinkedNode node = map.get(key);
removeNode(node);
addToHead(node);
return node.val;
}
public void set(int key, int value) {
if (!map.containsKey(key)) {
if(map.size()>=capacity){
DLinkedNode tail = removeTail();
map.remove(tail.key);
}
DLinkedNode newNode = new DLinkedNode(key, value);
addToHead(newNode);
map.put(key, newNode);
} else {
DLinkedNode node = map.get(key);
node.val=value;
removeNode(node);
addToHead(node);
map.put(key,node);
}
}
void removeNode(DLinkedNode node) {
node.pre.next = node.next;
node.next.pre = node.pre;
}
DLinkedNode removeTail(){
//注意写法!!
DLinkedNode deadNode = tail.pre;
removeNode(deadNode);
return deadNode;
}
void addToHead(DLinkedNode node) {
//注意四个指针的顺序,先右后左,先pre,再next!!!
node.next = head.next;
head.next.pre = node;
head.next = node;
node.pre = head;
}
//定义链表节点
class DLinkedNode {
int key;
int val;
DLinkedNode next;
DLinkedNode pre;
DLinkedNode() {
}
DLinkedNode(int key, int value) {
this.key = key;
this.val = value;
}
}
}
//方式二
import java.util.*;
public class Solution {
LinkedHashMap<Integer, Integer> map = new LinkedHashMap<>();
int capacity;
public Solution(int capacity) {
this.capacity = capacity;
}
public int get(int key) {
if(!map.containsKey(key)) {
return -1;
}
int val = map.get(key);
map.remove(key);
map.put(key, val);
return val;
}
public void set(int key, int value) {
if (!map.containsKey(key)) {
if (map.size() >= capacity) {
map.remove(map.keySet().iterator().next());
}
map.put(key, value);
} else {
map.remove(key);
map.put(key, value);
}
}
}
BM101 设计LFU缓存结构
函数 get
和 put
必须以 O(1)
的平均时间复杂度运行。
要求:get和set的时间复杂度都是 O(logn),空间复杂度是 O(n)
方法一:哈希表 + 平衡二叉树
import java.util.*;
class Solution {
int time;
int capacity;
//map只是存储数据
Map<Integer, Node> map = new HashMap<>();
//TreeSet存储失效信息,包括当前时间cnt,
TreeSet<Node> set = new TreeSet<>();
public int get(int key) {
if (!map.containsKey(key)) return -1;
Node cache = map.get(key);
//更新set,并且更新map中key对应的value
set.remove(cache);
cache.freq += 1;
cache.time = ++time;
set.add(cache);
map.put(key, cache);
return cache.value;
}
public void put(int key, int value, int k) {
if (!map.containsKey(key)) {
if (map.size() == k) {
//如果map已经满了,那么删除tree中最近最少使用的缓存
map.remove(set.first().key);
set.remove(set.first());
}
Node cache = new Node(1, ++time, key, value);
map.put(key, cache);
set.add(cache);
} else {
Node cache = map.get(key);
set.remove(cache);
cache.freq += 1;
cache.time = ++time;
cache.value = value;
set.add(cache);
map.put(key, cache);
}
}
class Node implements Comparable<Node> {
//freq 表示缓存使用的频率,time 表示缓存的使用时间
int freq, time, key, value;
Node(int freq, int time, int key, int value) {
this.freq = freq;
this.time = time;
this.key = key;
this.value = value;
}
@Override
public boolean equals(Object o) {
Node node = (Node) o;
return freq == node.freq && time == node.time;
}
@Override
public int hashCode() {
return freq * 1000000007 + time;
}
@Override
public int compareTo(Node node) {
return freq == node.freq ? time - node.time : freq - node.freq;
}
}
public int[] LFU(int[][] operators, int k) {
capacity = k;
ArrayList<Integer> res = new ArrayList<>();
for (int i = 0; i < operators.length; i++) {
if (operators[i][0] == 1) {
put(operators[i][1], operators[i][2], k);
} else {
res.add(get(operators[i][1]));
}
}
int[] ans = new int[res.size()];
for (int i = 0; i < res.size(); i++) {
ans[i] = res.get(i);
}
return ans;
}
}
方法二:双哈希表
O(1) 解法
import java.util.*;
public class Solution {
int min; // 存储当前最小频次
// 存储缓存的内容
HashMap<Integer, Node> map = new HashMap<>();
// 存储每个频次对应的双向链表
HashMap<Integer, LinkedHashSet<Node>> freqMap = new HashMap<>();
public int get(int key) {
if (!map.containsKey(key))
return -1;
Node node = map.get(key);
//更新set
freqInc(node);
return node.value;
}
public void set(int key, int value, int k) {
if (!map.containsKey(key)) {
if (map.size() >= k) {
Node deadNode = removeNode();
map.remove(deadNode.key);
}
Node newNode = new Node(key, value);
map.put(key, newNode);
addNode(newNode);
} else {
Node node = map.get(key);
node.value = value;
freqInc(node);
}
}
public void addNode(Node newNode) {
LinkedHashSet<Node> set = freqMap.get(1);
if (set == null) {
set = new LinkedHashSet<>();
freqMap.put(1, set);
}
set.add(newNode);
min = 1;
}
//删除freqMap的LinkedHashSet对应的freq最小的节点
Node removeNode() {
LinkedHashSet<Node> set = freqMap.get(min);
Node deadNode = set.iterator().next();
set.remove(deadNode);
return deadNode;
}
public void freqInc(Node node) {
//从原set中删除节点,更新freq,加入新的set中
int freq = node.freq;
LinkedHashSet<Node> set = freqMap.get(freq);
set.remove(node);
//???
if (freq == min && set.size() == 0) {
min = freq + 1;
}
node.freq++;
LinkedHashSet<Node> newSet = freqMap.get(freq + 1);
if (newSet == null) {
newSet = new LinkedHashSet<>();
freqMap.put(freq + 1, newSet);
}
newSet.add(node);
}
class Node {
int key;
int value;
int freq = 1;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
public int[] LFU(int[][] operators, int k) {
ArrayList<Integer> res = new ArrayList<>();
for (int i = 0; i < operators.length; i++) {
if (operators[i][0] == 1) {
set(operators[i][1], operators[i][2], k);
} else {
res.add(get(operators[i][1]));
}
}
int[] ans = new int[res.size()];
for (int i = 0; i < res.size(); i++) {
ans[i] = res.get(i);
}
System.out.println(Arrays.toString(ans));
return ans;
}
}
力扣
class LFUCache {
//存储全部的数据
HashMap<Integer, Node> map;
//将数据根据频率来分类存储
HashMap<Integer, LinkedHashSet<Node>> freqMap;
int min;
int size;
int capacity;
public LFUCache(int capacity) {
map = new HashMap<>();
freqMap = new HashMap<>();
this.capacity=capacity;
}
public int get(int key) {
if (!map.containsKey(key)) {
return -1;
}
Node node = map.get(key);
freqInc(node);
return node.value;
}
public void put(int key, int value) {
if(capacity==0) return;
if (!map.containsKey(key)) {
if (map.size() >= capacity) {
Node deadNode = removeNode();
map.remove(deadNode.key);
}
Node newNode = new Node(key, value);
map.put(key, newNode);
addNode(newNode);
} else {
Node node = map.get(key);
node.value = value;
freqInc(node);
}
}
public void addNode(Node newNode) {
LinkedHashSet<Node> set = freqMap.get(1);
if (set == null) {
set = new LinkedHashSet<>();
freqMap.put(1, set);
}
set.add(newNode);
min=1;
}
//删除freqmap最小频率对应的节点
public Node removeNode() {
LinkedHashSet<Node> set = freqMap.get(min);
Node deadnNode = set.iterator().next();
set.remove(deadnNode);
return deadnNode;
}
public void freqInc(Node node) {
int freq = node.freq;
//从原set中删除对应节点
LinkedHashSet<Node> set = freqMap.get(freq);
set.remove(node);
if (freq == min && set.isEmpty()) {
min = freq + 1;
}
//获取频次+1对应的set,将节点加入
node.freq++;
LinkedHashSet<Node> newSet = freqMap.get(freq + 1);
if (newSet == null) {
newSet = new LinkedHashSet<>();
freqMap.put(freq + 1, newSet);
}
newSet.add(node);
}
class Node {
int key;
int value;
int freq = 1;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
}
整理不易🚀🚀,关注和收藏后拿走📌📌欢迎留言🧐👋📣
欢迎专注我的公众号AdaCoding 和 Github:AdaCoding123