版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mike_learns_to_rock/article/details/89181010
Algorithm
https://leetcode.com/problems/jump-game/
jump game:判断是否可以跳跃到最后
- 解法1: DFS,会超时;用贪心法加快收敛速度
- 解法2: BFS,也需要贪心加快收敛
- 解法3: 动态规划,Bottom-up
class Solution {
public boolean canJump(int[] nums) {
boolean[] top = new boolean[nums.length];
int last = nums.length - 1;
for (int i = nums.length - 1; i >= 0; i--) {
if (nums[i] >= last - i) {
top[i] = true;
last = i;
}
}
return top[0];
}
}
- 解法4:动态规划,Top-down,就是把dfs的中间状态存储下来
enum Index {
GOOD, BAD, UNKNOWN
}
class Solution {
Index[] memo;
private boolean dfs(int p, int[] nums) {
if (memo[p] != Index.UNKNOWN) {
return memo[p] == Index.GOOD ? true : false;
}
for (int i = p + 1; i <= p + nums[p]; i++) {
if (dfs(i, nums)) {
memo[i] = Index.GOOD;
return true;
}
}
memo[p] = Index.BAD;
return false;
}
public boolean canJump(int[] nums) {
memo = new Index[nums.length];
for (int i = 0; i < memo.length; i++) {
memo[i] = Index.UNKNOWN;
}
memo[memo.length - 1] = Index.GOOD;
return dfs(0, nums);
}
}
https://leetcode.com/problems/jump-game-ii/
jump game 2 :找到最小的跳跃步数
- 解法是BFS,用贪心算法来加快收敛速度
class Solution {
public int jump(int[] nums) {
if (nums.length == 1) {
return 0;
}
Queue<Integer> queue = new LinkedList<>();
boolean[] visit = new boolean[nums.length];
int step = 1;
queue.add(0);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
int cur = ((LinkedList<Integer>) queue).pop();
if (cur + nums[cur] >= nums.length - 1) {
return step;
}
int maxJ = 0;
int maxDistance = 0;
for (int j = 1; j <= nums[cur]; j++) {
int distance = nums[cur + j] + cur + j;
if (distance > maxDistance) {
maxDistance = distance;
maxJ = j;
}
}
if (!visit[cur + maxJ]) {
visit[cur + maxJ] = true;
queue.add(cur + maxJ);
}
}
step++;
}
return -1;
}
}
Review
Design a key-value cache to save the results of the most recent web server queries
- 明确用户场景和约束
场景
- 用户发送一条search请求,缓存hit
- 用户发送一条search请求,缓存miss
- 缓存服务高可用
约束
- 流量不均匀,热点请求需要缓存,
- 缓存空间有限,how/when 更新缓存
- 低时延
- 1000万用户,100亿请求/月
存储评估
- 一条key + value = ?(270B)
- 一个月数据量最多2.7TB(100亿不同的请求),缓存肯定存储不下,需要淘汰
- 服务qps 4000
- 粗设计
- 客户端 - 服务端(反向代理)- 查询api - <倒排索引服务,文档服务> - 内存缓存
- 设计核心组件
缓存
- [HOW] LRU淘汰策略,那么参照https://leetcode.com/problems/lru-cache/ 双端链表 + 哈希表
- [WHEN] 何时更新:页内容变更/页删除以及新页添加/页排名变化
- 扩展系统
Tips
- 需求背景是一个任务下包含上万个子任务,子任务都是网络IO耗时较长的任务,客户端需要等待较长时间;java使用CloseableHttpAsyncClient时,因为任务数量远大于任务处理能力,导致很多request队列时间过长,造成header中的token过期;
- 暂时使用同步client解决的,真正消费的时候才去计算token;后面需要研究下CloseableHttpAsyncClient的玩法儿。感觉应该有解法;
- 或者把任务数量分摊到多个节点上,后面需要重新优化下架构了。
share
java虚拟机内存分配与回收策略
- 对象优先在Eden分配,Eden空间不足时,发起minor GC
- 大对象直接进入老年代,防止在 Eden 和 Survivor 之间的大量内存复制,-XX:PretenureSizeThreshold
- 长期存活的对象进入老年代,经过多次minor GC依然存活的对象,会进入老年代,-XX:MaxTenuringThreshold
- 动态对象年龄判定,虚拟机不会傻傻得以MaxTenuringThreshold为标准处理昌吉存活对象,会根据Survivor中的情况,重新定义年龄段
- 空间分配担保,就是为了确保minor GC是安全的,就是老年代担保自己可以装下新生代GC的对象;如果多维度考察,仍然失败,则full gc
fullGC的条件
-
老年代空间不足,大对象进入老年代
- 为了避免以上原因引起的 Full GC,应当尽量不要创建过大的对象以及数组。
- -Xmn 虚拟机参数调大新生代的大小,让对象尽量在新生代被回收掉,不进入老年代
- -XX:MaxTenuringThreshold 调大对象进入老年代的年龄,让对象在新生代多存活一段时间
-
空间分配担保失败
-
JDK 1.7 及以前的永久代空间不足