算法学习记录(四十六)

179 阅读2分钟

问:

  1. 给定一个无序正数数组arr。再给定一个正数target。求arr的子数组中数组累加和小于等于target且最长的子数组长度。例如:arr=[1,2,1,1,1],target = 3。累加和小于等于3的最长子数组为[1,1,1]。
  2. 给定一无序数组arr。在给定一个整数target。求arr的子数组中数组累加和小于等于target且最长的子数组长度。例如:arr=[3,-2,-4,0,6],k=-2。累加和小于等于-2的最长子数组为[3,-2,-4,0]
  3. 一个 char 类型的数组 chs,其中所有的字符都不同。 例如,chs=['A', 'B', 'C', ... 'Z'],则字符串与整数的对应关系如下: A, B... Z, AA,AB...AZ,BA,BB...ZZ,AAA... ZZZ, AAAA... 1, 2...26,27, 28... 52,53,54...702,703...18278, 18279... 给定一个数组 chs,实现根据对应关系输入编号返回对应字符串。K伪进制问题。

解:

  1. 滑动窗口
function getMaxLength(arr, target) {
    let left = 0
    let right = 0
    let max = 0
    let curSum = arr[0]
    while (right < arr.length) {
        // 重置窗口
        if (right < left) right = left
        if (curSum <= target) {
            max = Math.max(max, right - left + 1)
            right++
            curSum += arr[right]
        }
        if (curSum > target) {
            curSum -= arr[left]
            left++
        }
    }
    return max
}
  1. 生成两个辅助数组。第一个数组存储的信息从当前位置开始,能达到的最小累加和为多少。第二个数组存储的信息是,达到最小累加和时的右边界。还是利用滑动窗口解。只不过不是一个个滑动,而是直接滑动到某个最小累加和的右边界。
function getMaxLength(arr, target) {
    // 生成以当前位置开始,能达到的最小值为多少
    const curSumMin = []
    // 记录当前位置能达到的最小值的区域坐标
    const sumMinIdx = []
    for (let i = arr.length - 1; i >= 0; i--) {
        if (i === arr.length - 1) {
            curSumMin[i] = arr[i]
            sumMinIdx[i] = i
            continue
        }
        // 如果当前位的下一个位置最小累加和大于0,那就不要
        if (curSumMin[i + 1] > 0) {
            curSumMin[i] = arr[i]
            sumMinIdx[i] = i
        } else {
            curSumMin[i] = arr[i] + curSumMin[i + 1]
            sumMinIdx[i] = sumMinIdx[i + 1]
        }
    }
    let left = 0
    // 从0开始能达到的最小值,以及那个最小值对应的坐标
    let right = sumMinIdx[0]
    let curSum = curSumMin[0]
    let max = 0
    while (right < arr.length) {
        if (left > right) right = left
        if (curSum <= target) {
            max = Math.max(max, right - left + 1)
            right = sumMinIdx[right + 1]
            curSum += curSumMin[right]
        }
        if (curSum > target) {
            curSum -= curSumMin[left]
            left = sumMinIdx[left] + 1
        }
    }
    return max
}
  1. 先确定有多少个伪k进制位,每一位上放一个1。然后剩余的数,从高位到低位遍历判断每一位能放几个数。
function numToStr(arr, num) {
    const k = arr.length
    let dig = 0
    let tempSum = 0
    let res = []
    while (tempSum + k ** dig <= num) {
        tempSum += k ** dig
        dig++
        res.push(1)
    }
    let need = num - tempSum
    for (let i = 0; i < res.length; i++) {
        const curPos = Math.floor(need / k ** (dig - i - 1))
        need = need - curPos * k ** (dig - i - 1)
        res[i] = res[i] + curPos
    }
    res = res.map(item => arr[item - 1])
    return res
}