算法学习记录(四十八)

118 阅读1分钟

问:

  1. 给定两个字符串str1和str2,求两个字符串的最长公共子串
  2. 给定两个字符串str1和str2,求两个字符串的最长公共子序列
  3. 给定一个长度为N的正数数组。代表N个人的体重。再给定一个正数limit,代表一艘船的载重。假设每艘船最多坐两个人。乘客体重和不能超过limit。请问让这N个人过河最少需要几条船

解: 1.

// 暴力递归
function getMaxLength(str1, str2) {
    let max = -Infinity
    for (let i = 0; i < str1.length; i++) {
        for (let j = 0; j < str2.length; j++) {
            max = Math.max(max, getRes(i, j))
        }
    }
    function getRes(curI, curJ) {
        if (curI === 0 || curJ === 0) {
            return str1[curI] === str2[curJ] ? 1 : 0
        }
        if (str1[curI] === str2[curJ]) {
            return getRes(curI - 1, curJ - 1) + 1
        } else {
            return 0
        }
    }
    return max
}

// dp
function getMaxLength(str1, str2) {
    const dp = []
    let max = -Infinity
    for (let i = 0; i < str1.length; i++) {
        dp[i] = []
        for (let j = 0; j < str2.length; j++) {
            if (i === 0 || j === 0) {
                dp[i][j] = str1[i] === str2[j] ? 1 : 0
                max = Math.max(dp[i][j], max)
                continue
            }
            if (str1[i] !== str2[j]) {
                dp[i][j] = 0
            } else {
                dp[i][j] = dp[i - 1][j - 1] + 1
            }
            max = Math.max(dp[i][j], max)
        }
    }
    return max
}
// dp
function getMaxLength(str1, str2) {
    const dp = []
    for (let i = 0; i < str1.length; i++) {
        dp[i] = []
        for (let j = 0; j < str2.length; j++) {
            if (i === 0) {
                dp[i][j] = str1[i] === str2[j] ? 1 : dp[i][j - 1] ?? 0
                continue
            }
            if (j === 0) {
                dp[i][j] = str1[i] === str2[j] ? 1 : dp[i - 1][j] ?? 0
                continue
            }
            let p1 = 0
            let p2 = 0
            if (str1[i] === str2[j]) {
                p1 = dp[i - 1][j - 1] + 1
            }
            p2 = dp[i - 1][j - 1]
            const p3 = dp[i - 1][j]
            const p4 = dp[i][j - 1]
            if (i === 1 && j === 0) {
                console.log(p3, p4);
            }
            dp[i][j] = Math.max(p1, p2, p3, p4)
        }
    }
    return dp[str1.length - 1][str2.length - 1]
}
function getMinShip(arr, limit) {
    arr.sort((a, b) => a - b)
    if (arr[arr.length - 1] > limit) return -1
    const idx = getIdxOfItem(arr, limit / 2)
    // 全是小于等于limit / 2的数
    if (idx === arr.length - 1) {
        return Math.ceil(arr.length / 2)
    }
    // 全是大于limit / 2的数
    if (idx === -1) {
        return arr.length
    }
    let left = idx
    let right = idx + 1
    // type代表的值是 type1: 一个大于limit/2的人和一个小于limit/2的人组成一条船。  
    // type2: 两个小于limit/2的人组成一条船   type3:大于limit/2的人单独一条船
    let type1 = 0
    let type2 = 0
    // 从小于等于limit/2的位置开始双指针判断。能组成一条船就双指针移动。否则左指针去找体重更轻的人。
    // 当遍历结束。如果右指针没遍历完,那么右指针没遍历到的就是没匹配到体重轻的剩下来的单独一条船的人。
    while (left >= 0 && right < arr.length) {
        if (arr[left] + arr[right] <= limit) {
            left--
            right++
            type1++
        } else {
            left--
            type2++
        }
    }
    const type3 = arr.length - right
    return type1 + Math.ceil(type2 / 2) + type3
    function getIdxOfItem(arr, item) {
        let left = 0
        let right = arr.length - 1
        let mostRight = -1
        while (left <= right) {
            const midIdx = Math.floor((right + left) / 2)
            if (arr[midIdx] <= item) {
                left = midIdx + 1
                mostRight = Math.max(midIdx, mostRight)
            }
            if (arr[midIdx] > item) {
                right = midIdx - 1
            }
        }
        return mostRight
    }
}