LeetCode剑指offer记录

Posted tulandbla

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode剑指offer记录相关的知识,希望对你有一定的参考价值。

LeetCode剑指offer记录(2)


第三天

01.13

地上有一个m行n列的方格,从坐标 [0,0] 到坐标 [m-1,n-1] 。一个机器人从坐标 [0, 0] 的格子开始移动,它每次可以向左、右、上、下移动一格(不能移动到方格外),也不能进入行坐标和列坐标的数位之和大于k的格子。例如,当k为18时,机器人能够进入方格 [35, 37] ,因为3+5+3+7=18。但它不能进入方格 [35, 38],因为3+5+3+8=19。请问该机器人能够到达多少个格子?

示例 1:
输入:m = 2, n = 3, k = 1
输出:3
示例 2:
输入:m = 3, n = 1, k = 0
输出:1

思路:BFS广度优先搜索。
利用方向数组简易化访问操作。
判断这个点能不能遍历的条件一定要齐全,比如该点坐标[i,j],i<0||j<0||i>m-1||j>n-1||visted[‘i,j‘]||fun1(i)+fun1(j)>k,这些条件的出现都不能让该点被遍历。

//fun1返回数位和
var fun1 = function(num) {
	var res = 0
	while (num) {
		var a = num % 10
		res += a
		num = Math.floor(num / 10)
	}
	return res
}

var movingCount = function(m, n, k) {
	//方向数组
	var dedicationArray = [
		[-1, 0], //向上
		[0, 1], //向右
		[1, 0], //向下
		[0, -1] //向左
	]

	//已经访问过的坐标集
	var visited = {}
	visited[‘0,0‘] = true

	//目前位置坐标集
	var queue = [[0, 0]]

	while (queue.length) {
		let [x, y] = queue.shift() //在此回溯

		//访问过程,随便访问。无所谓顺序
		for (var i = 0; i < 4; i++) {
			var offSetX = x + dedicationArray[i][0] //将要访问的x坐标
			var offSetY = y + dedicationArray[i][1] //将要访问的y坐标

			if (
				offSetX < 0 ||
				offSetX >= m ||
				offSetY < 0 ||
				offSetY >= n ||
				fun1(offSetX) + fun1(offSetY) > k ||
				visited[`${offSetX},${offSetY}`]
			) {
				continue //跳过该次循环
			}
			//访问成功
			visited[`${offSetX},${offSetY}`] = true
			queue.push([offSetX, offSetY])
		}
	}
	return Object.keys(visited).length
}

01.14

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m] 。请问 k[0]k[1]...*k[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1

示例?2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 ×?3 ×?4 = 36

提示:
2 <= n <= 58
/**
 * @param {number} n
 * @return {number}
 */
var cuttingRope = function(n) {
	//动态规划
	//可以看成底数就是dp[1],dp[2],dp[3],所有大于3的整数都可以由他们三个组合而成

	//dp[n]代表传入长度为n时,剪绳子后,最大乘积的那个数
	var dp = new Array(n + 1)
	dp.fill(1)
	//易得 dp[1]=1,dp[2]=1,i从3开始算
	for (var i = 3; i <= n; i++) {
		for (var j = 1; j < i; j++) {
			var res = Math.max(j * (i - j), j * dp[i - j])
			dp[i] = Math.max(dp[i], res)
		}
	}
	return dp[n]
}

01.15

请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9?表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

示例 1:
输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011?中,共有三位为 ‘1‘。

示例 2:
输入:00000000000000000000000010000000
输出:1
解释:输入的二进制串 00000000000000000000000010000000?中,共有一位为 ‘1‘。

示例 3:
输入:11111111111111111111111111111101
输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 ‘1‘。

思路:n & (n - 1) 会把该整数最右边的1变成0,依次循环,直到整数中所有的1变成0循环结束。
则循环执行的次数就是该整数的二进制数中包含的1的个数。

/**
 * @param {number} n - a positive integer
 * @return {number}
 */
var hammingWeight = function(n) {
	var res = 0

	while (n !== 0) {
		n = n & (n - 1)
		res++
		console.log(n)
	}
	return res
}

01.16

实现函数double Power(double base, int exponent),求base的exponent次方。不得使用库函数,同时不需要考虑大数问题。

示例 1:
输入: 2.00000, 10
输出: 1024.00000

示例?2:
输入: 2.10000, 3
输出: 9.26100

示例?3:
输入: 2.00000, -2
输出: 0.25000

解释: 2^-2 = 1/2^2 = 1/4 = 0.25

分治法。
一个整数base的n次方:
①如果n是偶数,则可分为base^1/2 * base^1/2
②如果n是奇数,则可分为base^1/2 * base^1/2 * base
③n为负数,则先用他的绝对值计算最后返回的时候取倒数即可。

/**
 * @param {number} x
 * @param {number} n
 * @return {number}
 */
var myPow = function(x, n) {
	var isNagative = n < 0
	var result = fun1(x, n)
	return isNagative ? 1 / result : result
}

var fun1 = function(base, exponent) {
	if (exponent < 0) {
		exponent = -exponent
	}
	if (exponent === 0) {
		return 1
	}
	if (exponent === 1) {
		return base
	}
	var subExponent = Math.floor(exponent / 2)
	var subResult = fun1(base, subExponent)

	return exponent % 2 == 1
		? base * subResult * subResult
		: subResult * subResult
}

01.17

输入数字 n,按顺序打印出从 1 到最大的 n 位十进制数。比如输入 3,则打印出 1、2、3 一直到最大的 3 位数 999。

示例 1:
输入: n = 1
输出: [1,2,3,4,5,6,7,8,9]
/**
 * @param {number} n
 * @return {number[]}
 */
var printNumbers = function(n) {
	var counter = Math.pow(10, n) - 1
	var k = []
	for (var i = 1; i <= counter; i++) {
		k.push(i)
	}
	return k
}

01.18

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

返回删除后的链表的头节点。

注意:此题对比原题有改动

示例 1:
输入: head = [4,5,1,9], val = 5
输出: [4,1,9]
解释: 给定你链表中值为?5?的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.

示例 2:
输入: head = [4,5,1,9], val = 1
输出: [4,5,9]
解释: 给定你链表中值为?1?的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
?

说明:
题目保证链表中节点的值互不相同
若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点

思路:利用哨兵节点。哨兵节点是一个附加的链表节点,该节点作为第一个节点,它的值域中并不存储任何东西,只是为了操作的方便而引入的。如果一个链表有哨兵节点的话,那么线性表的第一个元素应该是链表的第二个节点。 它的加入使得链表操作更灵活。

/**

  • 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) {
    //哨兵节点:
    var preNode = new ListNode()
    preNode.next = head

    var currNode = preNode

    while (currNode.next != null) {
    if (currNode.next.val == val) {
    currNode.next = currNode.next.next
    break
    }
    currNode = currNode.next
    }
    return preNode.next
    }


以上是关于LeetCode剑指offer记录的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode剑指offer记录

LeetCode810. 黑板异或游戏/455. 分发饼干/剑指Offer 53 - I. 在排序数组中查找数字 I/53 - II. 0~n-1中缺失的数字/54. 二叉搜索树的第k大节点(代码片段

剑指 Offer(第 2 版)完整题解笔记 & C++代码实现(LeetCode版)

剑指 Offer(第 2 版)完整题解笔记 & C++代码实现(LeetCode版)

LeetCode(剑指 Offer)- 14- I. 剪绳子

LeetCode(剑指 Offer)- 14- I. 剪绳子