算法学习记录(三十四)

152 阅读1分钟

问:

  1. 旋转矩阵
  2. 以zigzag方式打印矩阵
  3. 假设s和m初始化,s='a';m=s;定义两种操作,第一种操作:m = s;s = s + s;第二种操作:s=s+m。求对小操作步骤数,可以将s拼接到长度等于n
  4. 给定一个字符串类型数组arr,求其中出现次数最多的前K个

解:

function rotate(arr) {
    // 确定两个顶点
    let a = 0
    let b = 0
    let x = arr.length - 1
    let y = arr[0].length - 1
    while (a < x && b < y) {
        for (let i = 0; i < y - b; i++) {
            const temp = arr[a][b+i]
            arr[a][b+i] = arr[x-i][b]
            arr[x-i][b] = arr[x][y-i]
            arr[x][y-i] = arr[a+i][y]
            arr[a+i][y] = temp
        }
        a++
        b++
        x--
        y--
    }
    return arr
}
function zigzagPrint(arr) {
    const res = []
    // 确定两个顶点
    let a = 0
    let b = 0
    let x = 0
    let y = 0
    let flag = true
    while (a < arr.length && b < arr[0].length && x < arr.length && y < arr[0].length) {
        printNode(a,b,x,y,flag)
        flag = !flag
        // 两个顶点移动轨迹
        if (a < arr.length - 1) {
            a++
        } else if (b < arr[0].length - 1) {
            b++
        }
        if (y < arr[0].length - 1) {
            y++
        } else if (x < arr.length) {
            x++
        }
    }
    return res
    // 打印两点间的值
    function printNode(a,b,x,y,flag) {
        if (flag) {
            while (a >= x) {
                res.push(arr[a--][b++])
            }
        } else {
            while (x <= a) {
                res.push(arr[x++][y--])
            }
        }
    }
}
function getMinTimes(N) {
    // 假如N是一个质数
    // 如果 m 变成2个a以上,即m = k 个 a。那么 s 最后一定会是 s = x * k * a 个数。这不符合N是质数的前提。
    // 所以得出结论,当N是质数时,调用N-1次操作二是最优解
    // 若N不是质数。把它分解为多个质数因子相乘的形式 N = x * y * z * o * p。
    // 当操作到p时,p是一个质数,把(x * y * z * o)看作一个整体,那么最优解就是调用p-1次操作二。
    // 那么由p推及到x。可以得出结论 res = x - 1 + y - 1 + z - 1 + o - 1 + p - 1。即 res = N的质数因子和 - N的质数因子个数
    const { sum, num } = getPrimeFactor(N)
    return sum - num
    function getPrimeFactor(N) {
        let sum = 0
        let num = 0
        for (let i = 2; i <= N;i++) {
            while (N % i===0) {
                sum += i
                num++
                N = N / i
            }
        }
        return {
            sum,
            num
        }
    }
}
  1. 统计数组中字符串的词频。遍历词频表,把每条数据当成一个节点放入一个数组。实际上就是给这个数组按照词频做堆排序。取前K个最大的数。
function findKthLargest(nums, k) {
    // 词频统计
    const hashMap = new Map()
    const help = []
    for (let i of nums) {
        hashMap.has(i) ? hashMap.set(i, hashMap.get(i) + 1) : hashMap.set(i, 1)
    }
    for (let i of hashMap.entries()) {
        help.push({
            key: i[0],
            value: i[1]
        })
    }
    nums = help
    return heapSort(nums)
    function heapSort(nums) {
        let heapSize = 0
        for (let i = 0; i<nums.length;i++) {
            heapInsert(i)
            heapSize += 1
        }
        while (k) {
            [nums[0], nums[heapSize - 1]] = [nums[heapSize - 1], nums[0]]
            heapSize -= 1
            k -= 1
            heapFy(0, heapSize)
        }
        function heapFy(i, heapSize) {
            const leftIdx = 2 * i + 1
            const rightIdx = leftIdx + 1
            let target = i
            if (leftIdx < heapSize && nums[leftIdx].value > nums[target].value) target = leftIdx
            if (rightIdx < heapSize && nums[rightIdx].value > nums[target].value) target = rightIdx
            if (target !== i) {
                [nums[i], nums[target]] = [nums[target], nums[i]]
                heapFy(target, heapSize)
            }
        }
        function heapInsert(i) {
            const father = Math.floor((i - 1) / 2)
            if (nums[father]?.value < nums[i]?.value) {
                [nums[father], nums[i]] = [nums[i], nums[father]];
                i = father
                heapInsert(i)
            }
        }
        return nums.slice(heapSize)
    }
};

// 复习时发现上述思路有误,更优解应该是创建一个小根堆。遍历数组生成词频表,当词频加一时,若小根堆的大小
//还没到k就直接加入这个字符信息,若小根堆已经到k个大小时,就跟小根堆堆顶元素比较,也就是说小根堆的堆顶就
//是一个瓶颈。超过这个瓶颈就是前K个最多的元素。