首页 > 其他分享 >Thinking--快速找出故障机器(异或)

Thinking--快速找出故障机器(异或)

时间:2023-03-08 19:32:47浏览次数:31  
标签:currentValue accumulator Thinking list -- 异或 let xorResult id


Thinking系列,旨在利用10分钟的时间传达一种可落地的编程思想。

假设一个机器仅存储一个标号为ID(数值)的记录,且该数据会保存备份(即,两个机器存储了同样的数据;类似于双节点部署)。

  1. 在某个时间,如果得到一个数据文件ID的列表,是否能够快速找出这个列表中仅出现一次的ID?
  2. 如果已知道有一台机器死机呢?如果两台呢?
const originList = [123, 456, 789, 134, 123, 456, 789, 134]
const list = [123, 456, 789, 134, 123, 456, 789] // 缺少一个
const list1 = [123, 456, 789, 123, 456, 789] // 缺少两个,同一ID
const list2 = [123, 456, 789, 134, 123, 456] // 缺少两个,不同ID

解法一:利用哈希表记下每个ID出现的次数

function getSingleNumber (list) {
let countMap = new Map()
for (let id of list) {
let count = countMap.get(id)
if (count) {
countMap.set(id, count + 1)
} else {
countMap.set(id, 1)
}
}
for (let [id, count] of countMap.entries()) {
if (count === 1) {
return id
}
}
}

该解法的时间复杂度为O(N),空间复杂度也为O(N)。

解法二:利用哈希表记下每个ID出现的次数(出现两次的删除)

ID为2的肯定不是故障机,可以不予考虑,即清除空间。

function getSingleNumber (list) {
let countMap = new Map()
for (let id of list) {
let count = countMap.get(id)
if (count) {
countMap.delete(id)
} else {
countMap.set(id, 1)
}
}
for (let [id, count] of countMap.entries()) {
if (count === 1) {
return id
}
}
}

该解法的时间复杂度为O(N),空间复杂度最好的情况下可以达到O(1),最坏情况下仍然是O(N)。

解法三:“不变量”

originSum = originList.reduce((accumulator, currentValue) => accumulator + currentValue) 
listSum = list.reduce((accumulator, currentValue) => accumulator + currentValue) = list.reduce((accumulator, currentValue) => accumulator + currentValue)
id = originSum - listSum // 134

延伸:如果两台死机,这里需要分两种情况:第一种,两台是同一id;第二种,两台是不同的id。

originMult = originList.reduce((accumulator, currentValue) => accumulator * currentValue)
list2Sum = list2.reduce((accumulator, currentValue) => accumulator + currentValue)
list2Mult = list2.reduce((accumulator, currentValue) => accumulator * currentValue)
a + b = originSum - list2Sum // 923
a * b = originMult/list2Mult // 105726

Thinking--快速找出故障机器(异或)_前端异或

function getSingleNumber (originList) {
let a, b
for (let i = 0; i < originList.length; i++ ) {
a = originList[i]
for (let j = i + 1; j < originList.length; j++ ) {
b = originList[j]
if (a + b === originSum - list2Sum && a * b === originMult/list2Mult) {
return [a, b]
}
}
}
}

该解法的时间复杂度为O(N),空间复杂度为O(1)

解法四:异或

Thinking--快速找出故障机器(异或)_thinking_02

function getSingleNumber (list) {
let xorResult = list[0]
for (let i = 1; i < list.length; i++) {
xorResult = xorResult ^ list[i]
}
return xorResult
}

异或,$ a⊕b = (¬a ∧ b) ∨ (a ∧¬b) $ 如果a、b两个值不相同,则异或结果为1;如果a、b两个值相同,异或结果为0。异或满足交换律、结合律和自反性。

交换律:a ^ b = b ^ a
结合律:a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c,即d = a ^ b ^ c 可以推出 a = d ^ b ^ c
自反性:a ^ b ^ a = b

延伸:如果两台死机,这里需要分两种情况:第一种,两台是同一id;第二种,两台是不同的id。

getSingleNumber(list1)  // 0,说明是两个相同ID
getSingleNumber(list2) // 915,说明是两个不同ID

相同ID,(原集合的和 - 现集合的和) / 2

originSum = originList.reduce((accumulator, currentValue) => accumulator + currentValue) 
list1Sum = list1.reduce((accumulator, currentValue) => accumulator + currentValue)
id = (originSum - list1Sum) / 2 // 134

不相同ID

如果Thinking--快速找出故障机器(异或)_thinking_03

originSum = originList.reduce((accumulator, currentValue) => accumulator + currentValue) 
list2Sum = list2.reduce((accumulator, currentValue) => accumulator + currentValue)
diffNum = (originSum - list2Sum) // 923
function getSingleNumber (list) {
let firstOneIndex = getFirstOneIndex(diffNum)
let xorResult = [-1, -1]
for (let i = 0; i < list.length; i++) {
let binaryNum = list[i].toString(2)
if (binaryNum[binaryNum.length + firstOneIndex] === '0') {
xorResult[0] = xorResult[0] === -1 ? list[i] : xorResult[0] ^ list[i]
} else {
xorResult[1] = xorResult[1] === -1 ? list[i] : xorResult[1] ^ list[i]
}
}
return xorResult
}
// "1110011011" 从右到左,获取第一个1,用负数表示(下标从1开始)
function getFirstOneIndex (num) {
let binaryNum = num.toString(2)
return -(binaryNum.length - num.toString(2).lastIndexOf('1'))
}
getSingleNumber(list2) // [134, 789]

该解法的时间复杂度为O(N),空间复杂度为O(1)


标签:currentValue,accumulator,Thinking,list,--,异或,let,xorResult,id
From: https://blog.51cto.com/u_15998238/6108715

相关文章

  • Thinking--AOP思想在前端中的应用
    Thinking系列,旨在利用10分钟的时间传达一种可落地的编程思想。AOPAOP(AspectOrientedProgramming),面向切面编程。其从主关注点中分离出横切关注点是面向侧面的程序设计的核......
  • vuex-router-sync 源码解析
    vuex-router-sync:路由状态管理,保持vue-router和vuex存储同步。import{sync}from'vuex-router-sync'importrouterfrom'@/router'importstorefrom'@/store'syn......
  • vue computed正确使用方式
    最近面试中,遇到一个小伙子,谈到了vue中的​​computed​​​和​​watch​​区别,最后得到了一个让我瞠目结舌的答案,只用​​watch​​,从不用​​computed​​模板内的......
  • 信道安全
    题目描述Alpha机构有自己的一套网络系统进行信息传送。情报员A位于节点1,他准备将一份情报发送给位于节点n的情报部门。可是由于最近国际纷争,战事不断,很多信道都有可能......
  • 搜索与图论3.2
    一、简述本节主要介绍一下有关最小生成树的两个算法,即\(Prim\)算法和\(Kruskal\)算法,适用于无向图。二、Prim算法基本思想\(Prim\)算法有一个适用于稠密图的朴素......
  • 内网穿透的高性能的反向代理应用FRP-自定义404错误页【实践可行版】
    frp简介frp是一个专注于内网穿透的高性能的反向代理应用,支持TCP、UDP、HTTP、HTTPS等多种协议。可以将内网服务以安全、便捷的方式通过具有公网IP节点的中转暴露到公......
  • 【MySQL】排序和分页
    排序ORDERBY多列;#强调格式:WHERE需要声明在FROM后,ORDERBY之前。先排序Country 再排序CustomerName,默认是按ASC排序的。SELECT*FROMCustomersORDERBYCountr......
  • python 提取列表元素打印不带中括号
    目录python提取列表元素打印不带中括号python提取列表元素打印不带中括号有个需求,需要对python3的列表切片,获取得到用户名后和手动输入的用户名比对,如果一致就打印true......
  • 寒假集训——基础数论6 线性代数
    矩阵定义简单来说矩阵就是一个\(n\)行\(r\)列的阵,实在不行可以理解成一个二维数组\[%开始数学环境\left[%左括号\begin{array}{ccc}......
  • vim: error while loading shared libraries: /lib64/libgpm.so.2: file too short
    在使用vim的时候出现了报错:[root@localhost~]#vimvim:errorwhileloadingsharedlibraries:/lib64/libgpm.so.2:filetooshort解决过程如下:yumreinstall-y......