前语
本文是一次学习分享,主要是我从一个面试题引发的考虑,然后结合实际事务处理问题的案例。从这篇文章中,大家能够考虑怎么样才能够触类旁通,怎么样结合自己的实际情况去打破技能瓶颈,?
由于公司扩展了新的事务,咱们有了一个运营活动需求一起运行在多个App的需求,但是,比方某个活动前端只开发一次,但是需求布置在两个域名下(有一些法务上的约束),关于运营来说,假如每个活动都要让他们装备两次的话,无疑是增加了他们的工作担负,并且还可能呈现错配的问题。因此,就引入了一个短链的需求(实际上便是用一个地址依据App的UserAgent
来做分发,但是为了照顾到别的事务线的运营,咱们就直接把它当做一个短链需求来完成),咱们直接把跳转的内容相关到某个短链上,直接把短链给运营进行投放。
面试题之数字转Excel单元格序号
这道面试题,我相信很多同学都做过,比方下面这个图: 横轴上面的序号是由A-Z,第27列便是AA,其实就适当所以26进制,A代表1,27便是26*10^1+26*10^0得来的。
现在,请编写一个算法,给你一个合法的整数得到转化成Excel横轴上面的字母标识法(即26进制)的内容。
这个题的处理方法,在初等数学就现已讲过叫除K取余法
,不过关于很久现已没有再看过数学教材的咱们来说,如同现已忘了这个解法的进程了。咱们就不管用什么方法,反正尽量写出这道题吧。
我的思路是,假定从最左边开端取,有多少个26,假定几百上千个,怎么去确认最高位的数字?那如同就完全没方法做。
那从右边开端算呢?由于咱们总能求得个位上的数的,所以拿这个整数对26取余,这样就得到了个位上的字母了,由于把个位上的字母现已得到了,那么用这个数减去这个个位上的数字之后,剩下的数便是26的整26倍了。
假如咱们现在把这个剩下是整26倍的数除以26,本来的从右边数的第二位不就变成了第一位了吗?如同现已把刚才的那个数字的规划减小了,并且又回到了重复的问题,就这样一向往从右往左递推,那这样就能把问题处理了。
function transform(num) {
let result = '';
const charMap = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z'
];
while (num >= 26) {
const digit = (num - 1) % 26;
const alphabet = charMap[digit];
result = alphabet + result;
num = Math.floor((num - 1) / 26);
}
// 处理最终一位数
result = charMap[num - 1] + result;
return result;
}
短链雪花算法
什么是短链?
短链,一般便是一个很简洁的域名,然后后面跟上一个有含义的参数(比方,v.dy.cn/w1Uirh2,我随意写的,不必定打的开哦),但是咱们作为用户不知道它的含义,这个短链服务一般会作为公司的全栈架构进口,一般能够作为BFF中的一个功能,也能够单独开发布置。服务端能够依据用户的UserAgent
的不同,把用户的恳求导向到对应的事务服务。
关于用户来说,短链比较好回忆,他实际上只是只需求记住短链码即可;关于开发者来说,短链服务是一个很好的导流进口,由于开发者能够很简略的拿到用户的UserAgent,就能够依据用户的信息吞吐用户当时设备感兴趣的内容。
比方,在我从前上任过的一家公司,关于运营来说,有一个叫做超级二维码的功能。这个二维码假如用App扫开,打开的是一个内嵌H5页面;假如是用小程序扫,能够直接打开公司的小程序,这个地址便是依据小程序的标识,返回了一个对应的scheme;而内嵌H5直接以302方法的重定向到了一个网页,其它运用类型以此类推。
生成短链码
短链服务的呼应有必要要快,在理解了短链服务的含义之后,对咱们的雪花算法功率就有必定的要求,所以问题的要害便是在于怎么生成短链码,怎么快速的解析短链码。
咱们需求用一张表来存这些短链的跳转内容,整数作为主键和UUID作为主键都有各自的优势和考虑要素,以下是运用整数主键相比运用UUID主键的一些优势:
-
功率和功能:整数主键一般比UUID主键更高效,由于它们在存储和比较时占用更少的空间。这能够减小磁盘和内存耗费,进步查询功能,特别是在大型数据集上;整数主键一般更简略进行索引,因此查询操作一般更快速。
-
数据库巨细:整数主键一般需求更少的存储空间,这在大型数据库中能够节约很多的磁盘空间。
-
衔接操作:在衔接不同表时,运用整数主键一般更高效,由于比较整数比较UUID更快。
-
数据共同性:整数主键一般更简略确保数据的共同性,由于它们不简略遭到UUID生成算法的影响。
然而,运用UUID作为主键也有其优势,特别是在分布式系统和分布式数据库中:
-
大局仅有性:UUID确保了全球范围内的仅有性,即便在分布式环境中也能够安全运用。这关于分布式系统和多个数据库实例之间的数据同步十分有用。
-
安全性:UUID不简略被猜想或计算出来,因此能够进步数据的安全性。
-
独立性:UUID主键不依赖于特定数据库或生成次序,因此更简略在不同数据库之间迁移和仿制数据。
-
随机性:UUID主键具有随机性,这能够协助减轻锁定和热点问题,特别是在高并发环境下。
比较简略想到的便是,用UUID生成一个指定长度的内容,然后取指定的长度。既然是短链,要方便用户回忆,那肯定不可能太长,假如UUID的长度取的太短,咱们不禁心里面会有个问号,真的不会呈现重复吗?
假定咱们在数据库中用自增ID,然后采用哈希算法,然后再取多少位,依然跟前面的算法存在相同的问题。
所以,在这个时分,我就想到了我在上节说到的面试题。我以26个大写字母+26个小写字母+10个数字对数据库的自增ID做进制转化,那么短链肯定是不会太长了,并且两个ID生成出来的内容必定是不会重复的。
此刻,我又进一步考虑了一个问题,假如我的短链服务就这样被他人发现了规则,那岂不是我的一切内容都能够被他人爬取完了吗?哈哈哈,,能够玩儿一个阴招,我干嘛那么厚道啊,谁告诉你0就真的是代表0啊,哈哈哈。
所以我将这62个字符乱序,得到一个排列,然后将这个序列保存下来,这个便是今后短链的秘钥,加密解密都能够用它来做。
好了,这样就能确保短链码跟数据库表记载有仅有的相关,并且短链码能够转出数据记载的ID,数据记载的ID也能转出短链码。
这个代码简略的令人发指,哈哈哈:
function getShortLinkCode(num) {
let result = '';
// 我的字符映射码没有乱序,实际项目中必定要乱序,并且必定要存下来
const charMap = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
];
// 只是只需求将本来的26进制转化为62进制即可
while (num >= 62) {
const digit = (num - 1) % 62;
const alphabet = charMap[digit];
result = alphabet + result;
num = Math.floor((num - 1) / 62);
}
// 处理最终一位数
result = charMap[num - 1] + result;
return result;
}
另外,还需求一个依据短链码求解表记载ID的函数,这个函数相对来说要简略一些,但是必定要跟生成短链进程中所用到字符次序是共同的:
function parsePkFromShortLinkCode(code) {
// 我的字符映射码没有乱序,实际项目中必定要乱序,并且必定要存下来
const charMap = {
'A': 1,
'B': 2,
'C': 3,
'D': 4,
'E': 5,
'F': 6,
'G': 7,
'H': 8,
'I': 9,
'J': 10,
'K': 11,
'L': 12,
'M': 13,
'N': 14,
'O': 15,
'P': 16,
'Q': 17,
'R': 18,
'S': 19,
'T': 20,
'U': 21,
'V': 22,
'W': 23,
'X': 24,
'Y': 25,
'Z': 26,
'a': 27,
'b': 28,
'c': 29,
'd': 30,
'e': 31,
'f': 32,
'g': 33,
'h': 34,
'i': 35,
'j': 36,
'k': 37,
'l': 38,
'm': 39,
'n': 40,
'o': 41,
'p': 42,
'q': 43,
'r': 44,
's': 45,
't': 46,
'u': 47,
'v': 48,
'w': 49,
'x': 50,
'y': 51,
'z': 52,
'0': 53,
'1': 54,
'2': 55,
'3': 56,
'4': 57,
'5': 58,
'6': 59,
'7': 60,
'8': 61,
'9': 62
};
// 从个位一向求和到最高位,所以需求reverse一下
return code.split('').reverse().reduce((total, char, idx) => {
return (total += charMap[char] * 62 ** idx)
}, 0)
}
试一下,看看转化是否正确:
为了让短链不至于太短,咱们能够初试数据库的自增ID从1E开端。
这个雪花算法能够在确保功能的前提下,内容不至于被爬虫爬取。
结语
尽管很多同学比较反感刷题,不过从我的经历来说的话,刷题是成为高手的一个必经之路,是打破自己技能瓶颈至关重要的一个阶段。在刷题的进程中,往往咱们能够才智到很多不常见的编程手法,俗话说好记忆不如烂笔头,自己亲自写一遍,知识就简略转化成咱们自己的,形成永久回忆。
在我的这个场景中,也是经过刷题积累到的,然后在适宜的时机用对了适宜的东西就能迅速的处理问题。关于刷题也没必要怼着一类题型不停的刷刷刷,假如当你现已完全把握到了一类问题的处理方案之后,就能够跳过了,假如过一段时间你觉得可能忘了,然后再回过头来尝试做几道这个类型的题加深回忆,多重复几次,就形成了永久回忆(至少我是这样的,遇到问题的时分,脑子里下意识的反响便是,这个问题我从前处理过,哈哈哈)
关于本文论述的内容有任何疑问的同学能够在评论区留言或私信我。
假如大家喜欢我的文章,能够多多点赞收藏加重视,你们的认但是我最好的更新动力,。