LeetCode刷题 - 高级算法扩展小结

一.位运算

一般基础的状态压缩就是将一行的状态压成一个数,这个数的二进制形式反映了这一行的情况。由于使用二进制来保存被压缩的状态,所以要用到神奇的二进制位运算操作,将一个十进制数转成二进制进行位运算操作再转回十进制数

总结

1.计算机有一套机制用二进制表示(正/负)整数/小数

2.平时我们写代码不用刻意写 ‘<<’ 或者 ‘>>’ 等移位运算符,因为编译器会自动做优化

如果要写,建议加括号

3.熟记真值表

4.XOR有很多性质,最重要的是:定义本身和交换律,结合律

其他性质可从定义和交换律,结合律推导出来

5.XOR的性质产生了很多等式,这些等式有时候可以写成状态转移方差,可以把原问题转换成dp问题

6.bit部分考的很少很少,甚至低于dp的范畴,主要用于状态压缩或者暴力解的时候方便穷尽所有的case,在contest里面常见

二.Reservoir Sampling / Rejection Sampling

水库抽样

public int getRandom() {
  int res = -1, count = 1;
  for (ListNode cur = head; cur != null; cur = cur.next)
    if (found_a_valid_case)
      if (random.nextInt(count++) == 0) res = cur.val;
  return res;
}

三.离线算法

什么叫在线算法?就是依次处理每一个query,对每一个query的计算,和之后的query无关,也不会用到之后的query信息(但可能也可以使用之前的query信息)

所以,在线算法,可以用来处理数据流。算法不需要一次性把所有的query都收集到再处理。大家也可以想象成:把这个算法直接部署到线上,尽管在线上可能又产生了很多新的query,也不影响,算法照常运行

离线算法则不同。离线算法需要把所有的信息都收集到,才能运行。处理当前query的计算过程,可能需要使用之后query的信息

总结

1.离线算法可以优化时间,缺点是需要知道所有的data,不能及时给每一个query答案,需要后台bash处理

2.这样做的核心在于,我们一边处理query,一边处理边,不是一次性的把所有的边都考虑进来,而是根据query的limit从小到大的限制,从小到大依次考虑边。注意,这个思路需要我们首先对整个query数组排序,之后再处理,所以需要收集到所有query信息以后再执行,它是一个离线算法

3.在线算法也可以实现类似的时间复杂度但是需要一些特殊算法,如树上倍增 + LCA

for (int i = 0, j = 0; i < N; i++) {
  int[] query = queries[i];
  while (j < M && edgeList[j][2] < queries[i][2]) //如果构造edge小于limit就创建
    dsu.union(edgeList[j][0],edgeList[j++][1]);
  res[queries[i][3]] = dsu.find(queries[i][0]) == dsu.find(queries[i][1]);
}

四.滚动哈希

考的不多,多为Hard题

public int search(String S, int L, int[] nums) {      //sliding window size = L
  long h = 0, aL = 1;
  for (int i = 0; i  seen = new HashSet(List.of(h));
  for (int start = 1; start < n - L + 1; start++) {
    h = h * a;                                        //move window
    h = (h - nums[start - 1] * aL % MOD + MOD) % MOD; //remove last digit
    h = (h + nums[start + L - 1]) % MOD;              //input new digit
    if (!seen.add(h)) return start;
  }
  return -1;
}

你可能感兴趣的:(数据结构与算法,leetcode,算法,职场和发展)