常见算法

2017年05月01日

使用 位运算 实现 加减乘除

加法

a+b变为 a异或b(a^b)再加上 a与b(a&b)的结果右移一位,这样递归直到 b 为0,即为a+b的最后结果。例如 2+3 -> 10+11(二进制) -> 01(10 ^ 11)+ 100(2 & 3 « 1)-> 101 (01 ^ 100) + 0 (01 & 100 « 1) -> 最后结果为 101 (即10进制的5)。

其实这里的 a^b 其实等于 a+b 不考虑进位的结果,而 a&b«1 就相当于需要进位的数值,递归如此进行位运算,直到需进位为0时,就为最终相加的结果。

减法

a-b 可转化为 a+(-b) 而 -b 可用 b 补码(取反+1, ~b+1,这里可使用上面的加法来做)来进行处理。

乘法

a*b 可转为 b个a进行相加的操作,来算出结果

除法

a/b 可转化为 a可以减多少个b才能 小于 0, 来算出结果。

快速找出 一个连续数字的数组中缺失的数

例如: [0,1,3] 缺失 2

解答:由于 a^a (一个数字异或自身结果为0),所以可将其两两消掉,

  for (int i = 0; i < nums.length; i++) {  
          xor ^= i;  
          xor ^= nums[i];  
      }
      xor ^= nums.length;
      // 最终 xor 即为缺失的数。

求给定一个字符串的最长回文子串

  • 方案一:将字符串倒序,和原字符串求最长公共子序列(且这个子序列必须满足是个回文,即逆序字符串中的公共子序列末尾 在原串中的位置 与 原串公共子序列末尾的位置之差,为公共子序列的长度)

  • 方案二:动态规划,第i到第j个所组成的子串是否为回文串,如果i和j的字符相等,则他是否为回文串取决于第i+1到第j-1所组成的子串是否为回文串(即:dp[i][j] = s[i] == s[j] && dp[i+1][j-1])

查找单链表中的倒数第k个结点

从链表头开始遍历到第k个节点的时候,将 结果值记为表头,然后继续向后遍历,结果值也向后顺延。

求链表中中间节点

设置两个点,first和second,同时向链表末端移动,first每次移动一步,second每次移动两步,最后first就是中间节点。

从尾到头打印单链表

dfs 或者 使用栈

判断链表是否有环

快慢指针:first指针每次移动一步,second支持每次移动两步,如果两个指针相遇,则有环

求链表环的长度

也是使用快慢指针:两个指针相遇的点,再让它继续往前走,再次回到原点时指针移动的距离就是环的长度

求链表环的起点

通过上面获取到环长度length后,second指针先走 length 步,然后first和second同时移动,每次一步,当两个指针相遇时,即为环的起点。(可以这样理解:假设second指针为起点,则它走length正好走了一圈,回到起点,如果不在环上,则它到起点的距离必然和头指针到起点的距离一样)

求两个链表的交点

两个链表分别执行一遍,求出链表长度为m和n,然后让较长的链表执行先移动(m-n)的距离,然后两个指针同时移动,两个指针相遇时即为交点。

给出一单链表头指针head和一节点指针 toBeDeleted,O(1)时间复杂度删除节点 toBeDeleted

将 toBeDeleted 节点的下一个节点的数据复制到当前节点,然后删除下一个节点即可(注意:如果待删除节点为最后一个节点时,需要使用常规方法先找出前一个节点,再删除 toBeDeleted 节点)

求二叉树中节点的最大距离 即二叉树中相距最远的两个节点之间的距离

最大深度为以某一个节点为根节点的左子树的最大深度+右子树的最大深度

simhash 相似度计算 算法

http://www.lanceyan.com/tech/arch/simhash_hamming_distance_similarity.html

C++中文实现:https://github.com/yanyiwu/simhash

Java中文实现:https://github.com/yangydeng/SimhashForChinese

限流算法

https://www.jianshu.com/p/d9504fc0af4d

  • 计数器
  • 滑动窗口
  • 桶漏算法
  • 令牌算法

分布式ID生成

https://tech.meituan.com/2019/03/07/open-source-project-leaf.html

Java动态追踪技术

Java动态追踪技术探究