算法 - 圖

  • 圖是網(wǎng)絡(luò)結(jié)構(gòu)的抽象模型馅扣,是一組由邊連接的節(jié)點
  • 圖可以表示任何二元關(guān)系斟赚,比如道路、航班
  • JS中沒有圖差油,但是可以用Object和Array構(gòu)建圖
  • 圖的表示法:鄰接矩陣拗军、鄰接表、關(guān)聯(lián)矩陣…
鄰接矩陣
鄰接表

圖的深度/廣度優(yōu)先遍歷

  • 深度優(yōu)先遍歷:盡可能深的搜索圖的分支
  • 廣度優(yōu)先遍歷:先訪問離根節(jié)點最近的節(jié)點

深度優(yōu)先遍歷算法口訣

  • 訪問根節(jié)點
  • 對根節(jié)點的沒訪問過的相鄰節(jié)點挨個進行深度優(yōu)先遍歷
深度優(yōu)先遍歷
// 圖蓄喇,后面不會重復寫
const graph = {
    0: [1, 2],
    1: [2],
    2: [0, 3],
    3: [3]
}
const visited = new Set()

const dfs = n => {
    console.log(n)
    visited.add(n)
    graph[n].forEach(c => {
        if (!visited.has(c)) {
            dfs(c)
        }
    })
}

dfs(2) // 2 0 1 3

廣度優(yōu)先遍歷算法口訣

  • 新建一個隊列发侵,把根節(jié)點入隊
  • 把隊頭出隊并訪問
  • 把隊頭的沒訪問過的相鄰節(jié)點入隊
  • 重復第二、三步妆偏,直到隊列為空
廣度優(yōu)先遍歷
const visited = new Set()
visited.add(2)
const q = [2]

while (q.length) {
    const n = q.shift()
    console.log(n) // 2 0 3 1
    graph[n].forEach(c => {
        if (!visited.has(c)) {
            q.push(c)
            visited.add(c)
        }
    })
}

有效數(shù)字

leeCode第65題

  • 構(gòu)建一個表示狀態(tài)的圖
  • 遍歷字符串刃鳄,并沿著圖走,如果到了某個節(jié)點無路可走就返回false
  • 遍歷結(jié)束钱骂,如走到3/5/6叔锐,就返回true挪鹏,否則返回false
有效數(shù)字鄰接表圖
/**
 * @param {string} s
 * @return {boolean}
 * @description 難點在于畫出鄰接表圖,循環(huán)遍歷輸入愉烙,將每一個字符轉(zhuǎn)化為對應(yīng)屬性讨盒,用于獲取當前狀態(tài)
 */
 const isNumber = function(s) {
    const graph = {
        0: { blank: 0, sign: 1, dot: 2, digit: 6 },
        1: { digit: 6, dot: 2 },
        2: { digit: 3 },
        3: { digit: 3, e: 4 },
        4: { digit: 5, sign: 7 },
        5: { digit: 5 },
        6: { digit: 6, dot: 3, e: 4 },
        7: { digit: 5 },
    }

    let state = 0 // 初始狀態(tài)都是0
    for (c of s.trim()) { // 題目中前后括號不影響判斷,所以先去除前后空格
        if (c === ' ') {
            c = 'blank'
        } else if (c === '+' || c === '-') {
            c = 'sign'
        } else if (c === '.') {
            c = 'dot'
        } else if (c.toLowerCase() === 'e') {
            c = 'e'
        } else if (!isNaN(c)) {
            c = 'digit'
        }
        
        state = graph[state][c]
        if (state === undefined) return false
    }

    // 合法的三個狀態(tài)
    const validState = [3, 5, 6]
    return validState.includes(state)
}

// "abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"
const testArr = ["2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"]

testArr.forEach(item => {
    console.log(isNumber(item))
})

太平洋大西洋水流問題

leeCode第417題

  • 把矩陣想象成圖
  • 從海岸線逆流而上遍歷圖步责,所到之處就是可以流到某個大洋的坐標
  • 新建兩個矩陣返顺,分別記錄能流到兩個大洋的坐標
  • 從海岸線,多管齊下蔓肯,同事深度優(yōu)先遍歷圖遂鹊,過程中填充上述矩陣
  • 遍歷兩個矩陣,找出能流到兩個大洋的坐標
/**
 * @param {number[][]} matrix
 * @return {number[][]}
 */
const pacificAtlantic = function(matrix) {
    if (!matrix || !matrix[0]) return []

    // 生成兩個空白矩陣
    const m = matrix.length
    const n = matrix[0].length
    const flow1 = Array.from({length: m}, () => new Array(n).fill(false))
    const flow2 = Array.from({length: m}, () => new Array(n).fill(false))

    const dfs = (r, c, flow) => {
        flow[r][c] = true
        const location = [[r - 1, c], [r + 1, c], [r, c -1], [r, c + 1]]
        location.forEach(([nr, nc]) => {
            if (
                // 保證在矩陣中
                nr >= 0 && nr < m && 
                nc >= 0 && nc < n &&
                // 防止死循環(huán)
                !flow[nr][nc] &&
                //保證逆流而上
                matrix[nr][nc] >= matrix[r][c]
            ) {
                dfs(nr, nc, flow)
            }
        })
    }

    // 沿著海岸線逆流而上
    for (let r = 0; r < m; r++) {
        dfs(r, 0, flow1)
        dfs(r, n - 1, flow2)
    }

    for (let c = 0; c < n; c++) {
        dfs(0, c, flow1)
        dfs(m - 1, c, flow2)
    }

    // 收集能流到兩個大洋里的坐標
    let res = []
    for (let r = 0; r < m; r += 1) {
        for (let c = 0; c < n; c += 1) {
            if (flow1[r][c] && flow2[r][c]) {
                res.push([r, c])
            }
        }
    }

    return res
}

const matrix = [
    [1, 2, 2, 3, 5],
    [3, 2, 3, 4, 4],
    [2, 4, 5, 3, 1],
    [6, 7, 1, 4, 5],
    [5, 1, 1, 2, 4]
]

console.log(pacificAtlantic(matrix))

克隆圖

leeCode第133題

  • 拷貝所有節(jié)點
  • 拷貝所有的邊
  • 將拷貝的節(jié)點蔗包,按照原圖的連接方法進行連接

這道題沒法模擬秉扑,dfs中會丟失原索引值,導致填充都為0气忠,但如果將索引一起放進去leeCode又跑不過,只能去leeCode上測試

深度優(yōu)先解法:

const cloneGraph = function(node) {
    if (!node) return

    const visited = new Map()
    const dfs = n => {
        const nCopy = new Node(n.val)
        visited.set(n, nCopy)
        const neighbors = n.neighbors || []
        neighbors.forEach(ne => {
            if (!visited.has(ne)) { // 已被記錄的鄰接邊不再記錄
                dfs(ne)
            }
            nCopy.neighbors.push(visited.get(ne))
        })
    }
    dfs(node)
    return visited.get(node)
}

廣度優(yōu)先解法:

const cloneGraph = function(node) {
    if (!node) return

    const visited = new Map()
    visited.set(node, new Node(node.val))
    const q = [node]
    while (q.length) {
        const n = q.shift()
        const neighbors = n.neighbors || []
        neighbors.forEach(ne => {
            if (!visited.has(ne)) {
                q.push(ne)
                visited.set(ne, new Node(ne.val))
            }
            visited.get(n).neighbors.push(visited.get(ne))
        })
    }
    return visited.get(node)
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末赋咽,一起剝皮案震驚了整個濱河市旧噪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌脓匿,老刑警劉巖淘钟,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異陪毡,居然都是意外死亡米母,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門毡琉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來铁瞒,“玉大人,你說我怎么就攤上這事桅滋』鬯#” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵丐谋,是天一觀的道長芍碧。 經(jīng)常有香客問我,道長号俐,這世上最難降的妖魔是什么泌豆? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮吏饿,結(jié)果婚禮上踪危,老公的妹妹穿的比我還像新娘蔬浙。我一直安慰自己,他們只是感情好陨倡,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布敛滋。 她就那樣靜靜地躺著,像睡著了一般兴革。 火紅的嫁衣襯著肌膚如雪绎晃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天杂曲,我揣著相機與錄音庶艾,去河邊找鬼。 笑死擎勘,一個胖子當著我的面吹牛咱揍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播棚饵,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼煤裙,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了噪漾?” 一聲冷哼從身側(cè)響起硼砰,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎欣硼,沒想到半個月后题翰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡诈胜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年豹障,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片焦匈。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡血公,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缓熟,到底是詐尸還是另有隱情坞笙,我是刑警寧澤,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布荚虚,位于F島的核電站薛夜,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏版述。R本人自食惡果不足惜梯澜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望晚伙。 院中可真熱鬧吮龄,春花似錦咆疗、人聲如沸漓帚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至迅皇,卻和暖如春昧辽,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背登颓。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工搅荞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人框咙。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像喇嘱,于是被迫代替她去往敵國和親茉贡。 傳聞我的和親對象是個殘疾皇子婉称,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容