剑指offer13-21(10道题)

本文仅供自己复习用

1、剑指 Offer 13. 机器人的运动范围
在这里插入图片描述
a、BFS
如图红色表示入队列顺序,可以看出其实每一步只是往右走和往下走,而且会有重复
在这里插入图片描述

	/**
	 * @param {number} m
	 * @param {number} n
	 * @param {number} k
	 * @return {number}
	 */
	var movingCount = function(m, n, k) {
	    let queue = ['0,0']
	    let res = 0
	    let getSum = function(num) {
	        let sum = 0
	        while(num !== 0) {
	            sum += num % 10
	            num = Math.floor(num / 10)
	        }
	        return sum
	    }
	    let map = new Map()
	    while(queue.length !== 0) {
	        let [row, col] = queue.shift().split(',')
	        row = parseInt(row)
	        col = parseInt(col)
	        if(getSum(row) + getSum(col) <= k && row < m && col < n) {
	            // 如果有重复的就别加进去
	            if(queue.indexOf(row + ',' + (col + 1)) === -1) {
	                queue.push(row + ',' + (col + 1))
	            }
	
	            if(queue.indexOf((row + 1) + ',' + col) === -1) {
	                queue.push((row + 1) + ',' + col)
	            }
	            res++
	        }
	    }
	    return res
	};

b、DFS
感觉和BFS差别不大

	/**
	 * @param {number} m
	 * @param {number} n
	 * @param {number} k
	 * @return {number}
	 */
	var movingCount = function(m, n, k) {
	    let queue = ['0,0']
        let visited = [...queue]
	    let res = 0
	    let getSum = function(num) {
	        let sum = 0
	        while(num !== 0) {
	            sum += num % 10
	            num = Math.floor(num / 10)
	        }
	        return sum
	    }
	    let map = new Map()
	    while(queue.length !== 0) {
	        let [row, col] = queue.pop().split(',')
	        row = parseInt(row)
	        col = parseInt(col)
	        if(getSum(row) + getSum(col) <= k && row < m && col < n) {
	            // 如果有重复的就别加进去
	            if(visited.indexOf(row + ',' + (col + 1)) === -1) {
	                queue.push(row + ',' + (col + 1))
	            }
	
	            if(visited.indexOf((row + 1) + ',' + col) === -1) {
	                queue.push((row + 1) + ',' + col)
	            }
                res++
                visited.push(row + ',' + col)
	        }
	    }
	    return res
	};

2、剑指 Offer 14- I. 剪绳子
在这里插入图片描述
关键词,最大,而且我们把某一段切开后,还可以把这一段继续切,相当于数据是可以记忆化的,所以我们自然而然地想到动态规划

	/**
	 * @param {number} n
	 * @return {number}
	 */
	var cuttingRope = function(n) {
	    let dp = new Array(n + 1).fill(0)
	    dp[1] = 1
	    dp[2] = 1
	    for(let i = 3; i < n + 1; i++) {
	        for(let j = 1; j < i; j++) {
	            // 分别为dp,当切了一刀后就直接乘上,或者当切了一刀后找切了那一刀的最大乘积再乘上
	            dp[i] = Math.max(dp[i], (i - j) * j, dp[i - j] * j)
	        }
	    }
	    return dp[n]
	};

3、剑指 Offer 14- II. 剪绳子 II
在这里插入图片描述
这道题和13(上一道题)的区别其实只是数更大了,而因为在他会超过Math.MAX_VALUE,所以这里就需要另外找方法进行计算(毕竟大整数乘法有问题嘛)
这里采用贪心算法,因为当绳子0m长,那肯定结果是0,绳子为1m那结果也是0,绳子为2m结果是1,绳子为3m结果是2,绳子为4m结果是4,绳子为5m结果是6
首先我们要了解的是因为绳子可以不断向下分,所以我们要知道什么时候该收手,也就是不往下分了,可以看出当绳子小于等于4m时往下分会很亏,而我们可以知道因为5=2+3,6=3+3,7=2+2+3这可以让我们看出其实每个数都可以分成若干个2和若干个3,而在这里面肯定是3多一点乘积会大一点,如8=2+2+2+2和8=3+3+2这里面3多一点的乘积会大一点,所以我们可以开始写代码(只要小于等于4就不分,大于4的就每次分一个3,直到小于等于4)

	/**
	 * @param {number} n
	 * @return {number}
	 */
	var cuttingRope = function(n) {
	    if(n <= 3) {
	        return n - 1
	    }
	    let res = 1
	    while(n > 4) {
	        res *= 3
	        res %= (1e9 + 7)
	        n -= 3
	    }
	    return res * n % (1e9 + 7)
	};

4、剑指 Offer 15. 二进制中1的个数
在这里插入图片描述
a、正则
这道题除了直接循环,就是正则最容易想出来了,循环就不多说了,正则写一下

	/**
	 * @param {number} n - a positive integer
	 * @return {number}
	 */
	var hammingWeight = function(n) {
	    let arr = n.toString(2).match(/1/g)
	    return arr === null ? 0 : arr.length
	};

b、与和右移的位运算
这里有个重点就是要用无符号右移,因为无符号右移是高位全部补0,而有符号右移的正数是高位补0,负数高位补1

	/**
	 * @param {number} n - a positive integer
	 * @return {number}
	 */
	var hammingWeight = function(n) {
	    let res = 0
	    while(n !== 0) {
	        res += n & 1
	        // 这里的重点在于要用无符号右移,而非有符号右移
	        n = n >>> 1
	    }
	    return res
	};

c、n&n-1
n&n-1可以把最后一个1消掉,然后返回消掉后的值

	/**
	 * @param {number} n - a positive integer
	 * @return {number}
	 */
	var hammingWeight = function(n) {
	    let res = 0
	    while(n !== 0) {
	        // 只要进得来也就是说只要值不是0,必定有一个1
	        res++
	        // n & (n - 1)相当于把最后一个1消除
	        n &= n - 1
	    }
	    return res
	};

拓展:
2的幂

	/**
	 * @param {number} n
	 * @return {boolean}
	 */
	var isPowerOfTwo = function(n) {
	    // 这里必须给(n - 1) & n加个括号,否则会被认为是(n - 1) & (n === 0)
	    return n > 0 && (((n - 1) & n) === 0)
	};

5、剑指 Offer 16. 数值的整数次方
在这里插入图片描述
这道题需要用到一些技巧,主要就是快速幂
a、二分
首先,我们如果暴力地循环肯定超时,所以如果我们要求4的8次方,可以通过先算到4的2次方,然后再平方得到4的4次方,再平方得到4的8次方
这其实就是二分的思想

	/**
	 * @param {number} x
	 * @param {number} n
	 * @return {number}
	 */
	var myPow = function(x, n) {
	    if(x === 1 || n === 0) {
	        return 1
	    }
	    if(n < 0) {
	        n = Math.abs(n)
	        x = 1 / x
	    }
	    let multi = function(num) {
	        if(num === 0) {
	            return 1
	        }
	
	        if(num % 2 === 0) {
	            return multi(num / 2) ** 2
	        } else {
	            return multi(Math.floor(num / 2)) ** 2 * x
	        }
	    }
	    return multi(n)
	};

b、位运算
如图,可以将指数从10进制转为2进制
在这里插入图片描述

	/**
	 * @param {number} x
	 * @param {number} n
	 * @return {number}
	 */
	var myPow = function(x, n) {
	    if(x === 1 || n === 0) {
	        return 1
	    }
	    let res = 1
	    if(n < 0) {
	        n = Math.abs(n)
	        x = 1 / x
	    }
	    let index = 1
	    while(n > 0) {       
	        if(n & 1) {
	            res *= x ** index
	        }
	        index *= 2
	        n = n >>> 1
	    }
	    return res
	};

6、剑指 Offer 17. 打印从1到最大的n位数
在这里插入图片描述
a、暴力循环

	/**
	 * @param {number} n
	 * @return {number[]}
	 */
	var printNumbers = function(n) {
	    n = 10 ** n
	    let res = []
	    for(let i = 1; i < n; i++) {
	        res.push(i)
	    }
	    return res
	};

7、剑指 Offer 18. 删除链表的节点
在这里插入图片描述
a、快慢指针

	/**
	 * Definition for singly-linked list.
	 * function ListNode(val) {
	 *     this.val = val;
	 *     this.next = null;
	 * }
	 */
	/**
	 * @param {ListNode} head
	 * @param {number} val
	 * @return {ListNode}
	 */
	var deleteNode = function(head, val) {
	    let node = head
	    let pre = null
	    while(node !== null) {
	        if(node.val === val) {
	            if(pre === null) {
	                return head.next
	            }
	            pre.next = node.next
	            return head
	        }
	        pre = node
	        node = node.next
	    }
	    return head
	};

8、剑指 Offer 19. 正则表达式匹配
在这里插入图片描述


9、剑指 Offer 20. 表示数值的字符串
在这里插入图片描述


10、剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
在这里插入图片描述
a、两个数组存储,暴力循环

	/**
	 * @param {number[]} nums
	 * @return {number[]}
	 */
	var exchange = function(nums) {
	    let res1 = []
	    let res2 = []
	    for(let i = 0; i < nums.length; i++) {
	        if(nums[i] % 2 === 0) {
	            res2.push(nums[i])
	        } else {
	            res1.push(nums[i])
	        }
	    }
	    return [...res1, ...res2]
	};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值